trpc.group/trpc-go/trpc-go@v1.0.3/http/value_detached_ctx.go (about) 1 // 2 // 3 // Tencent is pleased to support the open source community by making tRPC available. 4 // 5 // Copyright (C) 2023 THL A29 Limited, a Tencent company. 6 // All rights reserved. 7 // 8 // If you have downloaded a copy of the tRPC source code from Tencent, 9 // please note that tRPC source code is licensed under the Apache 2.0 License, 10 // A copy of the Apache 2.0 License is included in this file. 11 // 12 // 13 14 package http 15 16 import ( 17 "context" 18 "sync" 19 "time" 20 ) 21 22 // valueDetachedCtx removes all values associated with ctx while 23 // ensuring the transitivity of ctx timeout/cancel. 24 // After the original ctx timeout/cancel, valueDetachedCtx must release 25 // the original ctx to ensure that the resources associated with 26 // original ctx can be GC normally. 27 type valueDetachedCtx struct { 28 mu sync.Mutex 29 ctx context.Context 30 } 31 32 // detachCtxValue creates a new valueDetachedCtx from ctx. 33 func detachCtxValue(ctx context.Context) context.Context { 34 if ctx.Done() == nil { 35 return context.Background() 36 } 37 c := valueDetachedCtx{ctx: ctx} 38 go func() { 39 <-ctx.Done() 40 deadline, ok := ctx.Deadline() 41 c.mu.Lock() 42 c.ctx = &ctxRemnant{ 43 deadline: deadline, 44 hasDeadline: ok, 45 err: ctx.Err(), 46 done: ctx.Done(), 47 } 48 c.mu.Unlock() 49 }() 50 return &c 51 } 52 53 // Deadline implements the Deadline method of Context. 54 func (c *valueDetachedCtx) Deadline() (time.Time, bool) { 55 c.mu.Lock() 56 defer c.mu.Unlock() 57 return c.ctx.Deadline() 58 } 59 60 // Done implements Done method of Context. 61 func (c *valueDetachedCtx) Done() <-chan struct{} { 62 c.mu.Lock() 63 defer c.mu.Unlock() 64 return c.ctx.Done() 65 } 66 67 // Err implements Err method of Context. 68 func (c *valueDetachedCtx) Err() error { 69 c.mu.Lock() 70 defer c.mu.Unlock() 71 return c.ctx.Err() 72 } 73 74 // Value always returns nil. 75 func (c *valueDetachedCtx) Value(_ interface{}) interface{} { 76 return nil 77 } 78 79 // ctxRemnant is the remnant of valueDetachedCtx after timeout/cancel, 80 // retains some information of the original ctx, ensure that the original ctx 81 // can be GC normally. 82 type ctxRemnant struct { 83 deadline time.Time 84 hasDeadline bool 85 err error 86 done <-chan struct{} 87 } 88 89 // Deadline returns the saved readline information. 90 func (c *ctxRemnant) Deadline() (time.Time, bool) { 91 return c.deadline, c.hasDeadline 92 } 93 94 // Done returns saved Done channel. 95 func (c *ctxRemnant) Done() <-chan struct{} { 96 return c.done 97 } 98 99 // Err returns saved error. 100 func (c *ctxRemnant) Err() error { 101 return c.err 102 } 103 104 // Value always returns nil. 105 func (c *ctxRemnant) Value(_ interface{}) interface{} { 106 return nil 107 }