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  }