github.com/ydb-platform/ydb-go-sdk/v3@v3.57.0/internal/xcontext/context_with_cancel.go (about) 1 package xcontext 2 3 import ( 4 "context" 5 "sync" 6 "time" 7 ) 8 9 func WithCancel(ctx context.Context) (context.Context, context.CancelFunc) { 10 childCtx := &cancelCtx{ 11 parentCtx: ctx, 12 } 13 childCtx.ctx, childCtx.ctxCancel = context.WithCancel(ctx) 14 15 return childCtx, childCtx.cancel 16 } 17 18 type cancelCtx struct { 19 parentCtx context.Context 20 ctx context.Context 21 ctxCancel context.CancelFunc 22 23 m sync.Mutex 24 err error 25 } 26 27 func (ctx *cancelCtx) Deadline() (deadline time.Time, ok bool) { 28 return ctx.ctx.Deadline() 29 } 30 31 func (ctx *cancelCtx) Done() <-chan struct{} { 32 return ctx.ctx.Done() 33 } 34 35 func (ctx *cancelCtx) Err() error { 36 ctx.m.Lock() 37 defer ctx.m.Unlock() 38 39 if ctx.err != nil { 40 return ctx.err 41 } 42 43 ctx.err = ctx.ctx.Err() 44 45 return ctx.err 46 } 47 48 func (ctx *cancelCtx) Value(key interface{}) interface{} { 49 return ctx.ctx.Value(key) 50 } 51 52 func (ctx *cancelCtx) cancel() { 53 ctx.m.Lock() 54 defer ctx.m.Unlock() 55 56 ctx.ctxCancel() 57 58 if ctx.err != nil { 59 return 60 } 61 62 if err := ctx.parentCtx.Err(); err != nil { 63 ctx.err = err 64 65 return 66 } 67 ctx.err = errAt(context.Canceled, 1) 68 }