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