Source file src/context/context.go
1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package context defines the Context type, which carries deadlines, 6 // cancellation signals, and other request-scoped values across API boundaries 7 // and between processes. 8 // 9 // Incoming requests to a server should create a [Context], and outgoing 10 // calls to servers should accept a Context. The chain of function 11 // calls between them must propagate the Context, optionally replacing 12 // it with a derived Context created using [WithCancel], [WithDeadline], 13 // [WithTimeout], or [WithValue]. When a Context is canceled, all 14 // Contexts derived from it are also canceled. 15 // 16 // The [WithCancel], [WithDeadline], and [WithTimeout] functions take a 17 // Context (the parent) and return a derived Context (the child) and a 18 // [CancelFunc]. Calling the CancelFunc cancels the child and its 19 // children, removes the parent's reference to the child, and stops 20 // any associated timers. Failing to call the CancelFunc leaks the 21 // child and its children until the parent is canceled or the timer 22 // fires. The go vet tool checks that CancelFuncs are used on all 23 // control-flow paths. 24 // 25 // The [WithCancelCause] function returns a [CancelCauseFunc], which 26 // takes an error and records it as the cancellation cause. Calling 27 // [Cause] on the canceled context or any of its children retrieves 28 // the cause. If no cause is specified, Cause(ctx) returns the same 29 // value as ctx.Err(). 30 // 31 // Programs that use Contexts should follow these rules to keep interfaces 32 // consistent across packages and enable static analysis tools to check context 33 // propagation: 34 // 35 // Do not store Contexts inside a struct type; instead, pass a Context 36 // explicitly to each function that needs it. This is discussed further in 37 // https://go.dev/blog/context-and-structs. The Context should be the first 38 // parameter, typically named ctx: 39 // 40 // func DoSomething(ctx context.Context, arg Arg) error { 41 // // ... use ctx ... 42 // } 43 // 44 // Do not pass a nil [Context], even if a function permits it. Pass [context.TODO] 45 // if you are unsure about which Context to use. 46 // 47 // Use context Values only for request-scoped data that transits processes and 48 // APIs, not for passing optional parameters to functions. 49 // 50 // The same Context may be passed to functions running in different goroutines; 51 // Contexts are safe for simultaneous use by multiple goroutines. 52 // 53 // See https://go.dev/blog/context for example code for a server that uses 54 // Contexts. 55 package context 56 57 import ( 58 "errors" 59 "internal/reflectlite" 60 "sync" 61 "sync/atomic" 62 "time" 63 ) 64 65 // A Context carries a deadline, a cancellation signal, and other values across 66 // API boundaries. 67 // 68 // Context's methods may be called by multiple goroutines simultaneously. 69 type Context interface { 70 // Deadline returns the time when work done on behalf of this context 71 // should be canceled. Deadline returns ok==false when no deadline is 72 // set. Successive calls to Deadline return the same results. 73 Deadline() (deadline time.Time, ok bool) 74 75 // Done returns a channel that's closed when work done on behalf of this 76 // context should be canceled. Done may return nil if this context can 77 // never be canceled. Successive calls to Done return the same value. 78 // The close of the Done channel may happen asynchronously, 79 // after the cancel function returns. 80 // 81 // WithCancel arranges for Done to be closed when cancel is called; 82 // WithDeadline arranges for Done to be closed when the deadline 83 // expires; WithTimeout arranges for Done to be closed when the timeout 84 // elapses. 85 // 86 // Done is provided for use in select statements: 87 // 88 // // Stream generates values with DoSomething and sends them to out 89 // // until DoSomething returns an error or ctx.Done is closed. 90 // func Stream(ctx context.Context, out chan<- Value) error { 91 // for { 92 // v, err := DoSomething(ctx) 93 // if err != nil { 94 // return err 95 // } 96 // select { 97 // case <-ctx.Done(): 98 // return ctx.Err() 99 // case out <- v: 100 // } 101 // } 102 // } 103 // 104 // See https://blog.golang.org/pipelines for more examples of how to use 105 // a Done channel for cancellation. 106 Done() <-chan struct{} 107 108 // If Done is not yet closed, Err returns nil. 109 // If Done is closed, Err returns a non-nil error explaining why: 110 // Canceled if the context was canceled 111 // or DeadlineExceeded if the context's deadline passed. 112 // After Err returns a non-nil error, successive calls to Err return the same error. 113 Err() error 114 115 // Value returns the value associated with this context for key, or nil 116 // if no value is associated with key. Successive calls to Value with 117 // the same key returns the same result. 118 // 119 // Use context values only for request-scoped data that transits 120 // processes and API boundaries, not for passing optional parameters to 121 // functions. 122 // 123 // A key identifies a specific value in a Context. Functions that wish 124 // to store values in Context typically allocate a key in a global 125 // variable then use that key as the argument to context.WithValue and 126 // Context.Value. A key can be any type that supports equality; 127 // packages should define keys as an unexported type to avoid 128 // collisions. 129 // 130 // Packages that define a Context key should provide type-safe accessors 131 // for the values stored using that key: 132 // 133 // // Package user defines a User type that's stored in Contexts. 134 // package user 135 // 136 // import "context" 137 // 138 // // User is the type of value stored in the Contexts. 139 // type User struct {...} 140 // 141 // // key is an unexported type for keys defined in this package. 142 // // This prevents collisions with keys defined in other packages. 143 // type key int 144 // 145 // // userKey is the key for user.User values in Contexts. It is 146 // // unexported; clients use user.NewContext and user.FromContext 147 // // instead of using this key directly. 148 // var userKey key 149 // 150 // // NewContext returns a new Context that carries value u. 151 // func NewContext(ctx context.Context, u *User) context.Context { 152 // return context.WithValue(ctx, userKey, u) 153 // } 154 // 155 // // FromContext returns the User value stored in ctx, if any. 156 // func FromContext(ctx context.Context) (*User, bool) { 157 // u, ok := ctx.Value(userKey).(*User) 158 // return u, ok 159 // } 160 Value(key any) any 161 } 162 163 // Canceled is the error returned by [Context.Err] when the context is canceled. 164 var Canceled = errors.New("context canceled") 165 166 // DeadlineExceeded is the error returned by [Context.Err] when the context's 167 // deadline passes. 168 var DeadlineExceeded error = deadlineExceededError{} 169 170 type deadlineExceededError struct{} 171 172 func (deadlineExceededError) Error() string { return "context deadline exceeded" } 173 func (deadlineExceededError) Timeout() bool { return true } 174 func (deadlineExceededError) Temporary() bool { return true } 175 176 // An emptyCtx is never canceled, has no values, and has no deadline. 177 // It is the common base of backgroundCtx and todoCtx. 178 type emptyCtx struct{} 179 180 func (emptyCtx) Deadline() (deadline time.Time, ok bool) { 181 return 182 } 183 184 func (emptyCtx) Done() <-chan struct{} { 185 return nil 186 } 187 188 func (emptyCtx) Err() error { 189 return nil 190 } 191 192 func (emptyCtx) Value(key any) any { 193 return nil 194 } 195 196 type backgroundCtx struct{ emptyCtx } 197 198 func (backgroundCtx) String() string { 199 return "context.Background" 200 } 201 202 type todoCtx struct{ emptyCtx } 203 204 func (todoCtx) String() string { 205 return "context.TODO" 206 } 207 208 // Background returns a non-nil, empty [Context]. It is never canceled, has no 209 // values, and has no deadline. It is typically used by the main function, 210 // initialization, and tests, and as the top-level Context for incoming 211 // requests. 212 func Background() Context { 213 return backgroundCtx{} 214 } 215 216 // TODO returns a non-nil, empty [Context]. Code should use context.TODO when 217 // it's unclear which Context to use or it is not yet available (because the 218 // surrounding function has not yet been extended to accept a Context 219 // parameter). 220 func TODO() Context { 221 return todoCtx{} 222 } 223 224 // A CancelFunc tells an operation to abandon its work. 225 // A CancelFunc does not wait for the work to stop. 226 // A CancelFunc may be called by multiple goroutines simultaneously. 227 // After the first call, subsequent calls to a CancelFunc do nothing. 228 type CancelFunc func() 229 230 // WithCancel returns a derived context that points to the parent context 231 // but has a new Done channel. The returned context's Done channel is closed 232 // when the returned cancel function is called or when the parent context's 233 // Done channel is closed, whichever happens first. 234 // 235 // Canceling this context releases resources associated with it, so code should 236 // call cancel as soon as the operations running in this [Context] complete. 237 func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 238 c := withCancel(parent) 239 return c, func() { c.cancel(true, Canceled, nil) } 240 } 241 242 // A CancelCauseFunc behaves like a [CancelFunc] but additionally sets the cancellation cause. 243 // This cause can be retrieved by calling [Cause] on the canceled Context or on 244 // any of its derived Contexts. 245 // 246 // If the context has already been canceled, CancelCauseFunc does not set the cause. 247 // For example, if childContext is derived from parentContext: 248 // - if parentContext is canceled with cause1 before childContext is canceled with cause2, 249 // then Cause(parentContext) == Cause(childContext) == cause1 250 // - if childContext is canceled with cause2 before parentContext is canceled with cause1, 251 // then Cause(parentContext) == cause1 and Cause(childContext) == cause2 252 type CancelCauseFunc func(cause error) 253 254 // WithCancelCause behaves like [WithCancel] but returns a [CancelCauseFunc] instead of a [CancelFunc]. 255 // Calling cancel with a non-nil error (the "cause") records that error in ctx; 256 // it can then be retrieved using Cause(ctx). 257 // Calling cancel with nil sets the cause to Canceled. 258 // 259 // Example use: 260 // 261 // ctx, cancel := context.WithCancelCause(parent) 262 // cancel(myError) 263 // ctx.Err() // returns context.Canceled 264 // context.Cause(ctx) // returns myError 265 func WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc) { 266 c := withCancel(parent) 267 return c, func(cause error) { c.cancel(true, Canceled, cause) } 268 } 269 270 func withCancel(parent Context) *cancelCtx { 271 if parent == nil { 272 panic("cannot create context from nil parent") 273 } 274 c := &cancelCtx{} 275 c.propagateCancel(parent, c) 276 return c 277 } 278 279 // Cause returns a non-nil error explaining why c was canceled. 280 // The first cancellation of c or one of its parents sets the cause. 281 // If that cancellation happened via a call to CancelCauseFunc(err), 282 // then [Cause] returns err. 283 // Otherwise Cause(c) returns the same value as c.Err(). 284 // Cause returns nil if c has not been canceled yet. 285 func Cause(c Context) error { 286 if cc, ok := c.Value(&cancelCtxKey).(*cancelCtx); ok { 287 cc.mu.Lock() 288 defer cc.mu.Unlock() 289 return cc.cause 290 } 291 // There is no cancelCtxKey value, so we know that c is 292 // not a descendant of some Context created by WithCancelCause. 293 // Therefore, there is no specific cause to return. 294 // If this is not one of the standard Context types, 295 // it might still have an error even though it won't have a cause. 296 return c.Err() 297 } 298 299 // AfterFunc arranges to call f in its own goroutine after ctx is done 300 // (canceled or timed out). 301 // If ctx is already done, AfterFunc calls f immediately in its own goroutine. 302 // 303 // Multiple calls to AfterFunc on a context operate independently; 304 // one does not replace another. 305 // 306 // Calling the returned stop function stops the association of ctx with f. 307 // It returns true if the call stopped f from being run. 308 // If stop returns false, 309 // either the context is done and f has been started in its own goroutine; 310 // or f was already stopped. 311 // The stop function does not wait for f to complete before returning. 312 // If the caller needs to know whether f is completed, 313 // it must coordinate with f explicitly. 314 // 315 // If ctx has a "AfterFunc(func()) func() bool" method, 316 // AfterFunc will use it to schedule the call. 317 func AfterFunc(ctx Context, f func()) (stop func() bool) { 318 a := &afterFuncCtx{ 319 f: f, 320 } 321 a.cancelCtx.propagateCancel(ctx, a) 322 return func() bool { 323 stopped := false 324 a.once.Do(func() { 325 stopped = true 326 }) 327 if stopped { 328 a.cancel(true, Canceled, nil) 329 } 330 return stopped 331 } 332 } 333 334 type afterFuncer interface { 335 AfterFunc(func()) func() bool 336 } 337 338 type afterFuncCtx struct { 339 cancelCtx 340 once sync.Once // either starts running f or stops f from running 341 f func() 342 } 343 344 func (a *afterFuncCtx) cancel(removeFromParent bool, err, cause error) { 345 a.cancelCtx.cancel(false, err, cause) 346 if removeFromParent { 347 removeChild(a.Context, a) 348 } 349 a.once.Do(func() { 350 go a.f() 351 }) 352 } 353 354 // A stopCtx is used as the parent context of a cancelCtx when 355 // an AfterFunc has been registered with the parent. 356 // It holds the stop function used to unregister the AfterFunc. 357 type stopCtx struct { 358 Context 359 stop func() bool 360 } 361 362 // goroutines counts the number of goroutines ever created; for testing. 363 var goroutines atomic.Int32 364 365 // &cancelCtxKey is the key that a cancelCtx returns itself for. 366 var cancelCtxKey int 367 368 // parentCancelCtx returns the underlying *cancelCtx for parent. 369 // It does this by looking up parent.Value(&cancelCtxKey) to find 370 // the innermost enclosing *cancelCtx and then checking whether 371 // parent.Done() matches that *cancelCtx. (If not, the *cancelCtx 372 // has been wrapped in a custom implementation providing a 373 // different done channel, in which case we should not bypass it.) 374 func parentCancelCtx(parent Context) (*cancelCtx, bool) { 375 done := parent.Done() 376 if done == closedchan || done == nil { 377 return nil, false 378 } 379 p, ok := parent.Value(&cancelCtxKey).(*cancelCtx) 380 if !ok { 381 return nil, false 382 } 383 pdone, _ := p.done.Load().(chan struct{}) 384 if pdone != done { 385 return nil, false 386 } 387 return p, true 388 } 389 390 // removeChild removes a context from its parent. 391 func removeChild(parent Context, child canceler) { 392 if s, ok := parent.(stopCtx); ok { 393 s.stop() 394 return 395 } 396 p, ok := parentCancelCtx(parent) 397 if !ok { 398 return 399 } 400 p.mu.Lock() 401 if p.children != nil { 402 delete(p.children, child) 403 } 404 p.mu.Unlock() 405 } 406 407 // A canceler is a context type that can be canceled directly. The 408 // implementations are *cancelCtx and *timerCtx. 409 type canceler interface { 410 cancel(removeFromParent bool, err, cause error) 411 Done() <-chan struct{} 412 } 413 414 // closedchan is a reusable closed channel. 415 var closedchan = make(chan struct{}) 416 417 func init() { 418 close(closedchan) 419 } 420 421 // A cancelCtx can be canceled. When canceled, it also cancels any children 422 // that implement canceler. 423 type cancelCtx struct { 424 Context 425 426 mu sync.Mutex // protects following fields 427 done atomic.Value // of chan struct{}, created lazily, closed by first cancel call 428 children map[canceler]struct{} // set to nil by the first cancel call 429 err error // set to non-nil by the first cancel call 430 cause error // set to non-nil by the first cancel call 431 } 432 433 func (c *cancelCtx) Value(key any) any { 434 if key == &cancelCtxKey { 435 return c 436 } 437 return value(c.Context, key) 438 } 439 440 func (c *cancelCtx) Done() <-chan struct{} { 441 d := c.done.Load() 442 if d != nil { 443 return d.(chan struct{}) 444 } 445 c.mu.Lock() 446 defer c.mu.Unlock() 447 d = c.done.Load() 448 if d == nil { 449 d = make(chan struct{}) 450 c.done.Store(d) 451 } 452 return d.(chan struct{}) 453 } 454 455 func (c *cancelCtx) Err() error { 456 c.mu.Lock() 457 err := c.err 458 c.mu.Unlock() 459 return err 460 } 461 462 // propagateCancel arranges for child to be canceled when parent is. 463 // It sets the parent context of cancelCtx. 464 func (c *cancelCtx) propagateCancel(parent Context, child canceler) { 465 c.Context = parent 466 467 done := parent.Done() 468 if done == nil { 469 return // parent is never canceled 470 } 471 472 select { 473 case <-done: 474 // parent is already canceled 475 child.cancel(false, parent.Err(), Cause(parent)) 476 return 477 default: 478 } 479 480 if p, ok := parentCancelCtx(parent); ok { 481 // parent is a *cancelCtx, or derives from one. 482 p.mu.Lock() 483 if p.err != nil { 484 // parent has already been canceled 485 child.cancel(false, p.err, p.cause) 486 } else { 487 if p.children == nil { 488 p.children = make(map[canceler]struct{}) 489 } 490 p.children[child] = struct{}{} 491 } 492 p.mu.Unlock() 493 return 494 } 495 496 if a, ok := parent.(afterFuncer); ok { 497 // parent implements an AfterFunc method. 498 c.mu.Lock() 499 stop := a.AfterFunc(func() { 500 child.cancel(false, parent.Err(), Cause(parent)) 501 }) 502 c.Context = stopCtx{ 503 Context: parent, 504 stop: stop, 505 } 506 c.mu.Unlock() 507 return 508 } 509 510 goroutines.Add(1) 511 go func() { 512 select { 513 case <-parent.Done(): 514 child.cancel(false, parent.Err(), Cause(parent)) 515 case <-child.Done(): 516 } 517 }() 518 } 519 520 type stringer interface { 521 String() string 522 } 523 524 func contextName(c Context) string { 525 if s, ok := c.(stringer); ok { 526 return s.String() 527 } 528 return reflectlite.TypeOf(c).String() 529 } 530 531 func (c *cancelCtx) String() string { 532 return contextName(c.Context) + ".WithCancel" 533 } 534 535 // cancel closes c.done, cancels each of c's children, and, if 536 // removeFromParent is true, removes c from its parent's children. 537 // cancel sets c.cause to cause if this is the first time c is canceled. 538 func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) { 539 if err == nil { 540 panic("context: internal error: missing cancel error") 541 } 542 if cause == nil { 543 cause = err 544 } 545 c.mu.Lock() 546 if c.err != nil { 547 c.mu.Unlock() 548 return // already canceled 549 } 550 c.err = err 551 c.cause = cause 552 d, _ := c.done.Load().(chan struct{}) 553 if d == nil { 554 c.done.Store(closedchan) 555 } else { 556 close(d) 557 } 558 for child := range c.children { 559 // NOTE: acquiring the child's lock while holding parent's lock. 560 child.cancel(false, err, cause) 561 } 562 c.children = nil 563 c.mu.Unlock() 564 565 if removeFromParent { 566 removeChild(c.Context, c) 567 } 568 } 569 570 // WithoutCancel returns a derived context that points to the parent context 571 // and is not canceled when parent is canceled. 572 // The returned context returns no Deadline or Err, and its Done channel is nil. 573 // Calling [Cause] on the returned context returns nil. 574 func WithoutCancel(parent Context) Context { 575 if parent == nil { 576 panic("cannot create context from nil parent") 577 } 578 return withoutCancelCtx{parent} 579 } 580 581 type withoutCancelCtx struct { 582 c Context 583 } 584 585 func (withoutCancelCtx) Deadline() (deadline time.Time, ok bool) { 586 return 587 } 588 589 func (withoutCancelCtx) Done() <-chan struct{} { 590 return nil 591 } 592 593 func (withoutCancelCtx) Err() error { 594 return nil 595 } 596 597 func (c withoutCancelCtx) Value(key any) any { 598 return value(c, key) 599 } 600 601 func (c withoutCancelCtx) String() string { 602 return contextName(c.c) + ".WithoutCancel" 603 } 604 605 // WithDeadline returns a derived context that points to the parent context 606 // but has the deadline adjusted to be no later than d. If the parent's 607 // deadline is already earlier than d, WithDeadline(parent, d) is semantically 608 // equivalent to parent. The returned [Context.Done] channel is closed when 609 // the deadline expires, when the returned cancel function is called, 610 // or when the parent context's Done channel is closed, whichever happens first. 611 // 612 // Canceling this context releases resources associated with it, so code should 613 // call cancel as soon as the operations running in this [Context] complete. 614 func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { 615 return WithDeadlineCause(parent, d, nil) 616 } 617 618 // WithDeadlineCause behaves like [WithDeadline] but also sets the cause of the 619 // returned Context when the deadline is exceeded. The returned [CancelFunc] does 620 // not set the cause. 621 func WithDeadlineCause(parent Context, d time.Time, cause error) (Context, CancelFunc) { 622 if parent == nil { 623 panic("cannot create context from nil parent") 624 } 625 if cur, ok := parent.Deadline(); ok && cur.Before(d) { 626 // The current deadline is already sooner than the new one. 627 return WithCancel(parent) 628 } 629 c := &timerCtx{ 630 deadline: d, 631 } 632 c.cancelCtx.propagateCancel(parent, c) 633 dur := time.Until(d) 634 if dur <= 0 { 635 c.cancel(true, DeadlineExceeded, cause) // deadline has already passed 636 return c, func() { c.cancel(false, Canceled, nil) } 637 } 638 c.mu.Lock() 639 defer c.mu.Unlock() 640 if c.err == nil { 641 c.timer = time.AfterFunc(dur, func() { 642 c.cancel(true, DeadlineExceeded, cause) 643 }) 644 } 645 return c, func() { c.cancel(true, Canceled, nil) } 646 } 647 648 // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to 649 // implement Done and Err. It implements cancel by stopping its timer then 650 // delegating to cancelCtx.cancel. 651 type timerCtx struct { 652 cancelCtx 653 timer *time.Timer // Under cancelCtx.mu. 654 655 deadline time.Time 656 } 657 658 func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 659 return c.deadline, true 660 } 661 662 func (c *timerCtx) String() string { 663 return contextName(c.cancelCtx.Context) + ".WithDeadline(" + 664 c.deadline.String() + " [" + 665 time.Until(c.deadline).String() + "])" 666 } 667 668 func (c *timerCtx) cancel(removeFromParent bool, err, cause error) { 669 c.cancelCtx.cancel(false, err, cause) 670 if removeFromParent { 671 // Remove this timerCtx from its parent cancelCtx's children. 672 removeChild(c.cancelCtx.Context, c) 673 } 674 c.mu.Lock() 675 if c.timer != nil { 676 c.timer.Stop() 677 c.timer = nil 678 } 679 c.mu.Unlock() 680 } 681 682 // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 683 // 684 // Canceling this context releases resources associated with it, so code should 685 // call cancel as soon as the operations running in this [Context] complete: 686 // 687 // func slowOperationWithTimeout(ctx context.Context) (Result, error) { 688 // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 689 // defer cancel() // releases resources if slowOperation completes before timeout elapses 690 // return slowOperation(ctx) 691 // } 692 func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 693 return WithDeadline(parent, time.Now().Add(timeout)) 694 } 695 696 // WithTimeoutCause behaves like [WithTimeout] but also sets the cause of the 697 // returned Context when the timeout expires. The returned [CancelFunc] does 698 // not set the cause. 699 func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc) { 700 return WithDeadlineCause(parent, time.Now().Add(timeout), cause) 701 } 702 703 // WithValue returns a derived context that points to the parent Context. 704 // In the derived context, the value associated with key is val. 705 // 706 // Use context Values only for request-scoped data that transits processes and 707 // APIs, not for passing optional parameters to functions. 708 // 709 // The provided key must be comparable and should not be of type 710 // string or any other built-in type to avoid collisions between 711 // packages using context. Users of WithValue should define their own 712 // types for keys. To avoid allocating when assigning to an 713 // interface{}, context keys often have concrete type 714 // struct{}. Alternatively, exported context key variables' static 715 // type should be a pointer or interface. 716 func WithValue(parent Context, key, val any) Context { 717 if parent == nil { 718 panic("cannot create context from nil parent") 719 } 720 if key == nil { 721 panic("nil key") 722 } 723 if !reflectlite.TypeOf(key).Comparable() { 724 panic("key is not comparable") 725 } 726 return &valueCtx{parent, key, val} 727 } 728 729 // A valueCtx carries a key-value pair. It implements Value for that key and 730 // delegates all other calls to the embedded Context. 731 type valueCtx struct { 732 Context 733 key, val any 734 } 735 736 // stringify tries a bit to stringify v, without using fmt, since we don't 737 // want context depending on the unicode tables. This is only used by 738 // *valueCtx.String(). 739 func stringify(v any) string { 740 switch s := v.(type) { 741 case stringer: 742 return s.String() 743 case string: 744 return s 745 case nil: 746 return "<nil>" 747 } 748 return reflectlite.TypeOf(v).String() 749 } 750 751 func (c *valueCtx) String() string { 752 return contextName(c.Context) + ".WithValue(" + 753 stringify(c.key) + ", " + 754 stringify(c.val) + ")" 755 } 756 757 func (c *valueCtx) Value(key any) any { 758 if c.key == key { 759 return c.val 760 } 761 return value(c.Context, key) 762 } 763 764 func value(c Context, key any) any { 765 for { 766 switch ctx := c.(type) { 767 case *valueCtx: 768 if key == ctx.key { 769 return ctx.val 770 } 771 c = ctx.Context 772 case *cancelCtx: 773 if key == &cancelCtxKey { 774 return c 775 } 776 c = ctx.Context 777 case withoutCancelCtx: 778 if key == &cancelCtxKey { 779 // This implements Cause(ctx) == nil 780 // when ctx is created using WithoutCancel. 781 return nil 782 } 783 c = ctx.c 784 case *timerCtx: 785 if key == &cancelCtxKey { 786 return &ctx.cancelCtx 787 } 788 c = ctx.Context 789 case backgroundCtx, todoCtx: 790 return nil 791 default: 792 return c.Value(key) 793 } 794 } 795 } 796