// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package context defines the Context type, which carries deadlines, cancellation // signals, and other request-scoped values across API boundaries and between // processes. // // Incoming requests to a server establish a Context, and outgoing calls to servers // should accept a Context. The chain of function calls between must propagate the // Context, optionally replacing it with a modified copy created using // WithDeadline, WithTimeout, WithCancel, or WithValue. // // Programs that use Contexts should follow these rules to keep interfaces // consistent across packages and enable static analysis tools to check context // propagation: // // Do not store Contexts inside a struct type; instead, pass a Context // explicitly to each function that needs it. The Context should be the first // parameter, typically named ctx: // // func DoSomething(ctx context.Context, arg Arg) error { // // ... use ctx ... // } // // Do not pass a nil Context, even if a function permits it. Pass context.TODO // if you are unsure about which Context to use. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. // // The same Context may be passed to functions running in different goroutines; // Contexts are safe for simultaneous use by multiple goroutines. package context import ( "errors" "sync" "time" ) // A Context carries deadlines, and cancellation signals, and other values // across API boundaries. // // Context's methods may be called by multiple goroutines simultaneously. type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never become done. Successive calls to Done return the same value. // // WithCancel arranges for Done to be closed when cancel is called; // WithDeadline arranges for Done to be closed when the deadline // expires; WithTimeout arranges for Done to be closed when the timeout // elapses. // // Done is provided for use in select statements: // // // DoSomething calls DoSomethingSlow and returns as soon as // // it returns or ctx.Done is closed. // func DoSomething(ctx context.Context) (Result, error) { // c := make(chan Result, 1) // go func() { c <- DoSomethingSlow(ctx) }() // select { // case res := <-c: // return res, nil // case <-ctx.Done(): // return nil, ctx.Err() // } // } Done() <-chan struct{} // Err returns a non-nil error value after Done is closed. Err returns // Canceled if the context was canceled; Err returns DeadlineExceeded if // the context's deadline passed. No other values for Err are defined. // After Done is closed, successive calls to Err return the same value. Err() error // Value returns the value associated with this context for key, or nil // if no value is associated with key. Successive calls to Value with // the same key returns the same result. // // Use context values only for request-scoped data that transits // processes and APIs, not for passing optional parameters to functions. // // A key identifies a specific value in a Context. Functions that wish // to store values in Context typically allocate a key in a global // variable then use that key as the argument to context.WithValue and // Context.Value. A key can be any type that supports equality; // packages should define keys as an unexported type to avoid // collisions. // // Packages that define a Context key should provide type-safe accessors // for the values stores using that key: // // // Package user defines a User type that's stored in Contexts. // package user // // import "code.google.com/p/go.net/context" // // // User is the type of value stored in the Contexts. // type User struct {...} // // // key is an unexported type for keys defined in this package. // // This prevents collisions with keys defined in other packages. // type key int // // // userKey is the key for user.User values in Contexts. It is // // unexported; clients use user.NewContext and user.FromContext // // instead of using this key directly. // var userKey key = 0 // // // NewContext returns a new Context that carries value u. // func NewContext(ctx context.Context, u *User) context.Context { // return context.WithValue(userKey, u) // } // // // FromContext returns the User value stored in ctx, if any. // func FromContext(ctx context.Context) (*User, bool) { // u, ok := ctx.Value(userKey).(*User) // return u, ok // } Value(key interface{}) interface{} } // Canceled is the error returned by Context.Err when the context is canceled. var Canceled = errors.New("context canceled") // DeadlineExceeded is the error returned by Context.Err when the context's // deadline passes. var DeadlineExceeded = errors.New("context deadline exceeded") // A ctx is a Context that automatically propagates cancellation signals to // other ctxs (those created using this ctx as their parent). A ctx also // manages its own deadline timer. // // TODO(sameer): split this into separate concrete types for WithValue, // WithCancel, and WithTimeout/Deadline. This reduces the size of the structs; // for example, we don't need a timer field when creating a Context using // WithValue. type ctx struct { parent Context // set by newCtx done chan struct{} // closed by the first cancel call. nil if uncancelable. key interface{} // set by WithValue val interface{} // set by WithValue deadline time.Time // set by WithDeadline deadlineSet bool // set by WithDeadline // parent.mu ACQUIRED_BEFORE mu: mu must not be held when acquiring parent.mu. mu sync.RWMutex children map[*ctx]bool // set to nil by the first cancel call err error // set to non-nil by the first cancel call timer *time.Timer // set by WithDeadline, read by cancel } func (c *ctx) Deadline() (deadline time.Time, ok bool) { return c.deadline, c.deadlineSet } func (c *ctx) Done() <-chan struct{} { return c.done // may be nil } func (c *ctx) Err() error { c.mu.RLock() // c.err is under mu defer c.mu.RUnlock() return c.err } func (c *ctx) Value(key interface{}) interface{} { if c.key == key { return c.val } if c.parent != nil { return c.parent.Value(key) } return nil } // The background context for this process. var background = newCtx(nil, neverCanceled) // Background returns a non-nil, empty Context. It is never canceled, has no // values, and has no deadline. It is typically used by the main function, // initialization, and tests, and as the top-level Context for incoming // requests. func Background() Context { return background } // TODO returns a non-nil, empty Context. Code should use context.TODO when // it's unclear which Context to use or it's is not yet available (because the // surrounding function has not yet been extended to accept a Context // parameter). TODO is recognized by static analysis tools that determine // whether Contexts are propagated correctly in a program. func TODO() Context { return Background() } // A CancelFunc tells an operation to abandon its work. // A CancelFunc does not wait for the work to stop. // After the first, subsequent calls to a CancelFunc do nothing. type CancelFunc func() // WithCancel returns a copy of parent with a new Done channel. The returned // context's Done channel is closed when the returned cancel function is called // or when the parent context's Done channel is closed, whichever happens first. func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { return withCancel(parent) } func withCancel(parent Context) (*ctx, CancelFunc) { c := newCtx(parent, maybeCanceled) return c, func() { c.cancel(true, Canceled) } } // WithDeadline returns a copy of the parent context with the deadline adjusted // to be no later than d. If the parent's deadline is already earlier than d, // WithDeadline(parent, d) is semantically equivalent to parent. The returned // context's Done channel is closed when the deadline expires, when the returned // cancel function is called, or when the parent context's Done channel is // closed, whichever happens first. // // Canceling this context releases resources associated with the deadline // timer, so code should call cancel as soon as the operations running in this // Context complete. func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { c, cancel := withCancel(parent) if cur, ok := c.Deadline(); ok && cur.Before(deadline) { // The current deadline is already sooner than the new one. return c, cancel } c.deadline, c.deadlineSet = deadline, true d := deadline.Sub(time.Now()) if d <= 0 { // TODO(sameer): pass removeFromParent=true here? c.cancel(false, DeadlineExceeded) // deadline has already passed return c, cancel } c.mu.Lock() defer c.mu.Unlock() c.timer = time.AfterFunc(d, func() { // TODO(sameer): pass removeFromParent=true here? c.cancel(false, DeadlineExceeded) }) return c, cancel } // WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). // // Canceling this context releases resources associated with the deadline // timer, so code should call cancel as soon as the operations running in this // Context complete: // // func slowOperationWithTimeout(ctx context.Context) (Result, error) { // ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) // defer cancel() // releases resources if slowOperation completes before timeout elapses // return slowOperation(ctx) // } func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { return WithDeadline(parent, time.Now().Add(timeout)) } // WithValue returns a copy of parent in which the value associated with key is // val. // // Use context Values only for request-scoped data that transits processes and // APIs, not for passing optional parameters to functions. func WithValue(parent Context, key interface{}, val interface{}) Context { c := newCtx(parent, neverCanceled) c.key, c.val = key, val return c } const maybeCanceled = true const neverCanceled = false func newCtx(parent Context, childMayCancel bool) *ctx { c := &ctx{parent: parent} parentMayCancel := parent != nil && parent.Done() != nil if childMayCancel || parentMayCancel { c.done = make(chan struct{}) } if parent != nil { c.deadline, c.deadlineSet = parent.Deadline() } if parentMayCancel { if p, ok := parent.(*ctx); ok { // Arrange for the new ctx to be canceled when the parent is. p.mu.Lock() if p.err != nil { // parent has already been canceled c.cancel(false, p.err) } else { if p.children == nil { p.children = make(map[*ctx]bool) } p.children[c] = true } p.mu.Unlock() } else { // Cancel the new ctx when context.Done is closed. go func() { select { case <-parent.Done(): c.cancel(false, parent.Err()) case <-c.done: } }() } } return c } // cancel closes c.done, cancels each of this ctx's children, and, if // removeFromParent is true, removes this ctx from its parent's children. // cancel stops c.timer, if it is running. func (c *ctx) cancel(removeFromParent bool, err error) { if err == nil { panic("context: internal error: missing cancel error") } c.mu.Lock() if c.done == nil { panic("context: internal error: missing done channel") } if c.err != nil { c.mu.Unlock() return // already canceled } if c.timer != nil { c.timer.Stop() c.timer = nil } close(c.done) c.err = err for child := range c.children { // NOTE: acquiring the child's lock while holding parent's lock. child.cancel(false, err) } c.children = nil c.mu.Unlock() if p, ok := c.parent.(*ctx); ok && p != nil && removeFromParent { p.mu.Lock() if p.children != nil { delete(p.children, c) } p.mu.Unlock() } }