Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 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 | // cancelation signals, and other request-scoped values across API boundaries |
| 7 | // and between processes. |
| 8 | // |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 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. |
Sameer Ajmani | c4692da | 2016-06-14 16:48:42 -0400 | [diff] [blame] | 15 | // |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 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. |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 24 | // |
| 25 | // Programs that use Contexts should follow these rules to keep interfaces |
| 26 | // consistent across packages and enable static analysis tools to check context |
| 27 | // propagation: |
| 28 | // |
| 29 | // Do not store Contexts inside a struct type; instead, pass a Context |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 30 | // explicitly to each function that needs it. The Context should be the first |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 31 | // parameter, typically named ctx: |
| 32 | // |
| 33 | // func DoSomething(ctx context.Context, arg Arg) error { |
| 34 | // // ... use ctx ... |
| 35 | // } |
| 36 | // |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 37 | // Do not pass a nil Context, even if a function permits it. Pass context.TODO |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 38 | // if you are unsure about which Context to use. |
| 39 | // |
| 40 | // Use context Values only for request-scoped data that transits processes and |
| 41 | // APIs, not for passing optional parameters to functions. |
| 42 | // |
| 43 | // The same Context may be passed to functions running in different goroutines; |
| 44 | // Contexts are safe for simultaneous use by multiple goroutines. |
| 45 | // |
Shenghou Ma | 0960c7c | 2016-05-05 14:22:34 -0400 | [diff] [blame] | 46 | // See https://blog.golang.org/context for example code for a server that uses |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 47 | // Contexts. |
| 48 | package context |
| 49 | |
| 50 | import ( |
| 51 | "errors" |
| 52 | "fmt" |
Brad Fitzpatrick | bd72497 | 2016-04-10 15:45:34 +0000 | [diff] [blame] | 53 | "reflect" |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 54 | "sync" |
| 55 | "time" |
| 56 | ) |
| 57 | |
| 58 | // A Context carries a deadline, a cancelation signal, and other values across |
| 59 | // API boundaries. |
| 60 | // |
| 61 | // Context's methods may be called by multiple goroutines simultaneously. |
| 62 | type Context interface { |
| 63 | // Deadline returns the time when work done on behalf of this context |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 64 | // should be canceled. Deadline returns ok==false when no deadline is |
| 65 | // set. Successive calls to Deadline return the same results. |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 66 | Deadline() (deadline time.Time, ok bool) |
| 67 | |
| 68 | // Done returns a channel that's closed when work done on behalf of this |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 69 | // context should be canceled. Done may return nil if this context can |
| 70 | // never be canceled. Successive calls to Done return the same value. |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 71 | // |
| 72 | // WithCancel arranges for Done to be closed when cancel is called; |
| 73 | // WithDeadline arranges for Done to be closed when the deadline |
| 74 | // expires; WithTimeout arranges for Done to be closed when the timeout |
| 75 | // elapses. |
| 76 | // |
| 77 | // Done is provided for use in select statements: |
| 78 | // |
| 79 | // // Stream generates values with DoSomething and sends them to out |
| 80 | // // until DoSomething returns an error or ctx.Done is closed. |
Brad Fitzpatrick | 87bca88 | 2016-04-26 18:54:12 -0700 | [diff] [blame] | 81 | // func Stream(ctx context.Context, out chan<- Value) error { |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 82 | // for { |
| 83 | // v, err := DoSomething(ctx) |
| 84 | // if err != nil { |
| 85 | // return err |
| 86 | // } |
| 87 | // select { |
| 88 | // case <-ctx.Done(): |
| 89 | // return ctx.Err() |
| 90 | // case out <- v: |
| 91 | // } |
| 92 | // } |
| 93 | // } |
| 94 | // |
Shenghou Ma | 0960c7c | 2016-05-05 14:22:34 -0400 | [diff] [blame] | 95 | // See https://blog.golang.org/pipelines for more examples of how to use |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 96 | // a Done channel for cancelation. |
| 97 | Done() <-chan struct{} |
| 98 | |
Russ Cox | 6e2c4bc | 2017-04-10 21:09:13 -0400 | [diff] [blame] | 99 | // If Done is not yet closed, Err returns nil. |
| 100 | // If Done is closed, Err returns a non-nil error explaining why: |
| 101 | // Canceled if the context was canceled |
| 102 | // or DeadlineExceeded if the context's deadline passed. |
| 103 | // After Err returns a non-nil error, successive calls to Err return the same error. |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 104 | Err() error |
| 105 | |
| 106 | // Value returns the value associated with this context for key, or nil |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 107 | // if no value is associated with key. Successive calls to Value with |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 108 | // the same key returns the same result. |
| 109 | // |
| 110 | // Use context values only for request-scoped data that transits |
| 111 | // processes and API boundaries, not for passing optional parameters to |
| 112 | // functions. |
| 113 | // |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 114 | // A key identifies a specific value in a Context. Functions that wish |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 115 | // to store values in Context typically allocate a key in a global |
| 116 | // variable then use that key as the argument to context.WithValue and |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 117 | // Context.Value. A key can be any type that supports equality; |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 118 | // packages should define keys as an unexported type to avoid |
| 119 | // collisions. |
| 120 | // |
| 121 | // Packages that define a Context key should provide type-safe accessors |
Kenny Grant | 04acd62 | 2016-05-31 22:30:37 +0100 | [diff] [blame] | 122 | // for the values stored using that key: |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 123 | // |
| 124 | // // Package user defines a User type that's stored in Contexts. |
| 125 | // package user |
| 126 | // |
| 127 | // import "context" |
| 128 | // |
| 129 | // // User is the type of value stored in the Contexts. |
| 130 | // type User struct {...} |
| 131 | // |
| 132 | // // key is an unexported type for keys defined in this package. |
| 133 | // // This prevents collisions with keys defined in other packages. |
| 134 | // type key int |
| 135 | // |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 136 | // // userKey is the key for user.User values in Contexts. It is |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 137 | // // unexported; clients use user.NewContext and user.FromContext |
| 138 | // // instead of using this key directly. |
Michael Stapelberg | 2915e44 | 2017-08-30 07:50:13 -0700 | [diff] [blame] | 139 | // var userKey key |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 140 | // |
| 141 | // // NewContext returns a new Context that carries value u. |
| 142 | // func NewContext(ctx context.Context, u *User) context.Context { |
| 143 | // return context.WithValue(ctx, userKey, u) |
| 144 | // } |
| 145 | // |
| 146 | // // FromContext returns the User value stored in ctx, if any. |
| 147 | // func FromContext(ctx context.Context) (*User, bool) { |
| 148 | // u, ok := ctx.Value(userKey).(*User) |
| 149 | // return u, ok |
| 150 | // } |
| 151 | Value(key interface{}) interface{} |
| 152 | } |
| 153 | |
| 154 | // Canceled is the error returned by Context.Err when the context is canceled. |
| 155 | var Canceled = errors.New("context canceled") |
| 156 | |
| 157 | // DeadlineExceeded is the error returned by Context.Err when the context's |
| 158 | // deadline passes. |
Brad Fitzpatrick | dc4427f | 2016-05-19 18:08:43 +0000 | [diff] [blame] | 159 | var DeadlineExceeded error = deadlineExceededError{} |
| 160 | |
| 161 | type deadlineExceededError struct{} |
| 162 | |
Russ Cox | f69991c | 2016-10-04 23:58:42 -0400 | [diff] [blame] | 163 | func (deadlineExceededError) Error() string { return "context deadline exceeded" } |
| 164 | func (deadlineExceededError) Timeout() bool { return true } |
| 165 | func (deadlineExceededError) Temporary() bool { return true } |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 166 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 167 | // An emptyCtx is never canceled, has no values, and has no deadline. It is not |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 168 | // struct{}, since vars of this type must have distinct addresses. |
| 169 | type emptyCtx int |
| 170 | |
| 171 | func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { |
| 172 | return |
| 173 | } |
| 174 | |
| 175 | func (*emptyCtx) Done() <-chan struct{} { |
| 176 | return nil |
| 177 | } |
| 178 | |
| 179 | func (*emptyCtx) Err() error { |
| 180 | return nil |
| 181 | } |
| 182 | |
| 183 | func (*emptyCtx) Value(key interface{}) interface{} { |
| 184 | return nil |
| 185 | } |
| 186 | |
| 187 | func (e *emptyCtx) String() string { |
| 188 | switch e { |
| 189 | case background: |
| 190 | return "context.Background" |
| 191 | case todo: |
| 192 | return "context.TODO" |
| 193 | } |
| 194 | return "unknown empty Context" |
| 195 | } |
| 196 | |
| 197 | var ( |
| 198 | background = new(emptyCtx) |
| 199 | todo = new(emptyCtx) |
| 200 | ) |
| 201 | |
| 202 | // Background returns a non-nil, empty Context. It is never canceled, has no |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 203 | // values, and has no deadline. It is typically used by the main function, |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 204 | // initialization, and tests, and as the top-level Context for incoming |
| 205 | // requests. |
| 206 | func Background() Context { |
| 207 | return background |
| 208 | } |
| 209 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 210 | // TODO returns a non-nil, empty Context. Code should use context.TODO when |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 211 | // it's unclear which Context to use or it is not yet available (because the |
| 212 | // surrounding function has not yet been extended to accept a Context |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 213 | // parameter). TODO is recognized by static analysis tools that determine |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 214 | // whether Contexts are propagated correctly in a program. |
| 215 | func TODO() Context { |
| 216 | return todo |
| 217 | } |
| 218 | |
| 219 | // A CancelFunc tells an operation to abandon its work. |
| 220 | // A CancelFunc does not wait for the work to stop. |
| 221 | // After the first call, subsequent calls to a CancelFunc do nothing. |
| 222 | type CancelFunc func() |
| 223 | |
| 224 | // WithCancel returns a copy of parent with a new Done channel. The returned |
| 225 | // context's Done channel is closed when the returned cancel function is called |
| 226 | // or when the parent context's Done channel is closed, whichever happens first. |
| 227 | // |
| 228 | // Canceling this context releases resources associated with it, so code should |
| 229 | // call cancel as soon as the operations running in this Context complete. |
| 230 | func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { |
| 231 | c := newCancelCtx(parent) |
| 232 | propagateCancel(parent, &c) |
| 233 | return &c, func() { c.cancel(true, Canceled) } |
| 234 | } |
| 235 | |
| 236 | // newCancelCtx returns an initialized cancelCtx. |
| 237 | func newCancelCtx(parent Context) cancelCtx { |
Josh Bleecher Snyder | 986768d | 2017-01-08 13:22:24 -0800 | [diff] [blame] | 238 | return cancelCtx{Context: parent} |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 239 | } |
| 240 | |
| 241 | // propagateCancel arranges for child to be canceled when parent is. |
| 242 | func propagateCancel(parent Context, child canceler) { |
| 243 | if parent.Done() == nil { |
| 244 | return // parent is never canceled |
| 245 | } |
| 246 | if p, ok := parentCancelCtx(parent); ok { |
| 247 | p.mu.Lock() |
| 248 | if p.err != nil { |
| 249 | // parent has already been canceled |
| 250 | child.cancel(false, p.err) |
| 251 | } else { |
| 252 | if p.children == nil { |
Jack Lindamood | 3938279 | 2016-07-26 14:20:36 -0700 | [diff] [blame] | 253 | p.children = make(map[canceler]struct{}) |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 254 | } |
Jack Lindamood | 3938279 | 2016-07-26 14:20:36 -0700 | [diff] [blame] | 255 | p.children[child] = struct{}{} |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 256 | } |
| 257 | p.mu.Unlock() |
| 258 | } else { |
| 259 | go func() { |
| 260 | select { |
| 261 | case <-parent.Done(): |
| 262 | child.cancel(false, parent.Err()) |
| 263 | case <-child.Done(): |
| 264 | } |
| 265 | }() |
| 266 | } |
| 267 | } |
| 268 | |
| 269 | // parentCancelCtx follows a chain of parent references until it finds a |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 270 | // *cancelCtx. This function understands how each of the concrete types in this |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 271 | // package represents its parent. |
| 272 | func parentCancelCtx(parent Context) (*cancelCtx, bool) { |
| 273 | for { |
| 274 | switch c := parent.(type) { |
| 275 | case *cancelCtx: |
| 276 | return c, true |
| 277 | case *timerCtx: |
| 278 | return &c.cancelCtx, true |
| 279 | case *valueCtx: |
| 280 | parent = c.Context |
| 281 | default: |
| 282 | return nil, false |
| 283 | } |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | // removeChild removes a context from its parent. |
| 288 | func removeChild(parent Context, child canceler) { |
| 289 | p, ok := parentCancelCtx(parent) |
| 290 | if !ok { |
| 291 | return |
| 292 | } |
| 293 | p.mu.Lock() |
| 294 | if p.children != nil { |
| 295 | delete(p.children, child) |
| 296 | } |
| 297 | p.mu.Unlock() |
| 298 | } |
| 299 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 300 | // A canceler is a context type that can be canceled directly. The |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 301 | // implementations are *cancelCtx and *timerCtx. |
| 302 | type canceler interface { |
| 303 | cancel(removeFromParent bool, err error) |
| 304 | Done() <-chan struct{} |
| 305 | } |
| 306 | |
Josh Bleecher Snyder | 986768d | 2017-01-08 13:22:24 -0800 | [diff] [blame] | 307 | // closedchan is a reusable closed channel. |
| 308 | var closedchan = make(chan struct{}) |
| 309 | |
| 310 | func init() { |
| 311 | close(closedchan) |
| 312 | } |
| 313 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 314 | // A cancelCtx can be canceled. When canceled, it also cancels any children |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 315 | // that implement canceler. |
| 316 | type cancelCtx struct { |
| 317 | Context |
| 318 | |
Josh Bleecher Snyder | 986768d | 2017-01-08 13:22:24 -0800 | [diff] [blame] | 319 | mu sync.Mutex // protects following fields |
| 320 | done chan struct{} // created lazily, closed by first cancel call |
Jack Lindamood | 3938279 | 2016-07-26 14:20:36 -0700 | [diff] [blame] | 321 | children map[canceler]struct{} // set to nil by the first cancel call |
| 322 | err error // set to non-nil by the first cancel call |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 323 | } |
| 324 | |
| 325 | func (c *cancelCtx) Done() <-chan struct{} { |
Josh Bleecher Snyder | 986768d | 2017-01-08 13:22:24 -0800 | [diff] [blame] | 326 | c.mu.Lock() |
| 327 | if c.done == nil { |
| 328 | c.done = make(chan struct{}) |
| 329 | } |
| 330 | d := c.done |
| 331 | c.mu.Unlock() |
| 332 | return d |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 333 | } |
| 334 | |
| 335 | func (c *cancelCtx) Err() error { |
| 336 | c.mu.Lock() |
| 337 | defer c.mu.Unlock() |
| 338 | return c.err |
| 339 | } |
| 340 | |
| 341 | func (c *cancelCtx) String() string { |
| 342 | return fmt.Sprintf("%v.WithCancel", c.Context) |
| 343 | } |
| 344 | |
| 345 | // cancel closes c.done, cancels each of c's children, and, if |
| 346 | // removeFromParent is true, removes c from its parent's children. |
| 347 | func (c *cancelCtx) cancel(removeFromParent bool, err error) { |
| 348 | if err == nil { |
| 349 | panic("context: internal error: missing cancel error") |
| 350 | } |
| 351 | c.mu.Lock() |
| 352 | if c.err != nil { |
| 353 | c.mu.Unlock() |
| 354 | return // already canceled |
| 355 | } |
| 356 | c.err = err |
Josh Bleecher Snyder | 986768d | 2017-01-08 13:22:24 -0800 | [diff] [blame] | 357 | if c.done == nil { |
| 358 | c.done = closedchan |
| 359 | } else { |
| 360 | close(c.done) |
| 361 | } |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 362 | for child := range c.children { |
| 363 | // NOTE: acquiring the child's lock while holding parent's lock. |
| 364 | child.cancel(false, err) |
| 365 | } |
| 366 | c.children = nil |
| 367 | c.mu.Unlock() |
| 368 | |
| 369 | if removeFromParent { |
| 370 | removeChild(c.Context, c) |
| 371 | } |
| 372 | } |
| 373 | |
| 374 | // WithDeadline returns a copy of the parent context with the deadline adjusted |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 375 | // to be no later than d. If the parent's deadline is already earlier than d, |
| 376 | // WithDeadline(parent, d) is semantically equivalent to parent. The returned |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 377 | // context's Done channel is closed when the deadline expires, when the returned |
| 378 | // cancel function is called, or when the parent context's Done channel is |
| 379 | // closed, whichever happens first. |
| 380 | // |
| 381 | // Canceling this context releases resources associated with it, so code should |
| 382 | // call cancel as soon as the operations running in this Context complete. |
Michael Darakananda | eca4599 | 2017-09-21 10:25:35 +1000 | [diff] [blame] | 383 | func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { |
| 384 | if cur, ok := parent.Deadline(); ok && cur.Before(d) { |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 385 | // The current deadline is already sooner than the new one. |
| 386 | return WithCancel(parent) |
| 387 | } |
| 388 | c := &timerCtx{ |
| 389 | cancelCtx: newCancelCtx(parent), |
Michael Darakananda | eca4599 | 2017-09-21 10:25:35 +1000 | [diff] [blame] | 390 | deadline: d, |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 391 | } |
| 392 | propagateCancel(parent, c) |
Michael Darakananda | eca4599 | 2017-09-21 10:25:35 +1000 | [diff] [blame] | 393 | dur := time.Until(d) |
| 394 | if dur <= 0 { |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 395 | c.cancel(true, DeadlineExceeded) // deadline has already passed |
| 396 | return c, func() { c.cancel(true, Canceled) } |
| 397 | } |
| 398 | c.mu.Lock() |
| 399 | defer c.mu.Unlock() |
| 400 | if c.err == nil { |
Michael Darakananda | eca4599 | 2017-09-21 10:25:35 +1000 | [diff] [blame] | 401 | c.timer = time.AfterFunc(dur, func() { |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 402 | c.cancel(true, DeadlineExceeded) |
| 403 | }) |
| 404 | } |
| 405 | return c, func() { c.cancel(true, Canceled) } |
| 406 | } |
| 407 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 408 | // A timerCtx carries a timer and a deadline. It embeds a cancelCtx to |
| 409 | // implement Done and Err. It implements cancel by stopping its timer then |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 410 | // delegating to cancelCtx.cancel. |
| 411 | type timerCtx struct { |
| 412 | cancelCtx |
| 413 | timer *time.Timer // Under cancelCtx.mu. |
| 414 | |
| 415 | deadline time.Time |
| 416 | } |
| 417 | |
| 418 | func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { |
| 419 | return c.deadline, true |
| 420 | } |
| 421 | |
| 422 | func (c *timerCtx) String() string { |
Brad Fitzpatrick | 298791a | 2016-08-30 01:05:18 +0000 | [diff] [blame] | 423 | return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, time.Until(c.deadline)) |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 424 | } |
| 425 | |
| 426 | func (c *timerCtx) cancel(removeFromParent bool, err error) { |
| 427 | c.cancelCtx.cancel(false, err) |
| 428 | if removeFromParent { |
| 429 | // Remove this timerCtx from its parent cancelCtx's children. |
| 430 | removeChild(c.cancelCtx.Context, c) |
| 431 | } |
| 432 | c.mu.Lock() |
| 433 | if c.timer != nil { |
| 434 | c.timer.Stop() |
| 435 | c.timer = nil |
| 436 | } |
| 437 | c.mu.Unlock() |
| 438 | } |
| 439 | |
| 440 | // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). |
| 441 | // |
| 442 | // Canceling this context releases resources associated with it, so code should |
| 443 | // call cancel as soon as the operations running in this Context complete: |
| 444 | // |
| 445 | // func slowOperationWithTimeout(ctx context.Context) (Result, error) { |
| 446 | // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) |
| 447 | // defer cancel() // releases resources if slowOperation completes before timeout elapses |
| 448 | // return slowOperation(ctx) |
| 449 | // } |
| 450 | func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { |
| 451 | return WithDeadline(parent, time.Now().Add(timeout)) |
| 452 | } |
| 453 | |
| 454 | // WithValue returns a copy of parent in which the value associated with key is |
| 455 | // val. |
| 456 | // |
| 457 | // Use context Values only for request-scoped data that transits processes and |
| 458 | // APIs, not for passing optional parameters to functions. |
Brad Fitzpatrick | bd72497 | 2016-04-10 15:45:34 +0000 | [diff] [blame] | 459 | // |
Brad Fitzpatrick | c921d8f | 2016-11-11 23:40:25 +0000 | [diff] [blame] | 460 | // The provided key must be comparable and should not be of type |
| 461 | // string or any other built-in type to avoid collisions between |
| 462 | // packages using context. Users of WithValue should define their own |
| 463 | // types for keys. To avoid allocating when assigning to an |
| 464 | // interface{}, context keys often have concrete type |
| 465 | // struct{}. Alternatively, exported context key variables' static |
| 466 | // type should be a pointer or interface. |
Brad Fitzpatrick | bd72497 | 2016-04-10 15:45:34 +0000 | [diff] [blame] | 467 | func WithValue(parent Context, key, val interface{}) Context { |
Brad Fitzpatrick | c884f65 | 2016-04-28 22:04:30 -0500 | [diff] [blame] | 468 | if key == nil { |
| 469 | panic("nil key") |
| 470 | } |
Brad Fitzpatrick | bd72497 | 2016-04-10 15:45:34 +0000 | [diff] [blame] | 471 | if !reflect.TypeOf(key).Comparable() { |
| 472 | panic("key is not comparable") |
| 473 | } |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 474 | return &valueCtx{parent, key, val} |
| 475 | } |
| 476 | |
Sameer Ajmani | e4dc7f1 | 2016-06-24 10:48:06 -0400 | [diff] [blame] | 477 | // A valueCtx carries a key-value pair. It implements Value for that key and |
Brad Fitzpatrick | 9db7ef5 | 2016-03-08 00:07:18 +0000 | [diff] [blame] | 478 | // delegates all other calls to the embedded Context. |
| 479 | type valueCtx struct { |
| 480 | Context |
| 481 | key, val interface{} |
| 482 | } |
| 483 | |
| 484 | func (c *valueCtx) String() string { |
| 485 | return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) |
| 486 | } |
| 487 | |
| 488 | func (c *valueCtx) Value(key interface{}) interface{} { |
| 489 | if c.key == key { |
| 490 | return c.val |
| 491 | } |
| 492 | return c.Context.Value(key) |
| 493 | } |