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