// 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.//// Functions that require a Context should take it as the first parameter, 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.//// Future packages will create Contexts from standard request types like// *http.Request.package context import ( "errors" "fmt" "sync" "time") // An 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.//// Packages that define a Context Key should provide type-safe accessors for the// Values stores using that Key://// // package foo defines a value that's stored in Contexts.// package foo//// import "clive/x/code.google.com/p/go.net/context"//// // Foo is the type of value stored in the Contexts.// type Foo struct {...}//// // contextKey is the Key for foo.Foo values in Contexts. It is// // unexported; foo clients use foo.NewContext and foo.FromContext// // instead of using this Key directly.// var contextKey = context.NewKey("import/path/of/foo.Foo")//// // NewContext returns a new Context that carries value foo.// func NewContext(ctx context.Context, foo *Foo) context.Context {// return context.WithValue(contextKey, foo)// }//// // FromContext returns the Foo value stored in ctx, if any.// func FromContext(ctx context.Context) (*Foo, bool) {// foo, ok := ctx.Value(contextKey).(*Foo)// return foo, ok// }struct Key { name string} var keys = make(map[string]Key) // NewKey allocates a new Key with the provided name. The name must be// non-empty and globally unique: if NewKey is called multiple times with the// same name it panics. NewKey should only be called during initalization.func NewKey(name string) Key { if name == "" { panic("context.NewKey called with an empty name") } if _, ok := keys[name]; ok { panic(fmt.Sprintf("context.NewKey(%q) called multiple times", name)) } k := Key{name} keys[name] = k return k} // String returns the Key's name.func (k Key) String() string { return k.name} // A Context carries deadlines, and cancellation signals, and other values// across API boundaries.//// Context's methods may be called by multiple goroutines simultaneously.interface Context { // 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. 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. Value(key Key) face{}} // 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.struct ctx { parent Context // set by newCtx done chan struct{} // closed by the first cancel call. nil if uncancelable. key Key // set by WithValue val face{} // 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 Key) face{} { 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 an ambient background context, which is never nil. This// context represents the intrinsic state of the application at startup time,// independent of any incoming request state.//// The Background context is typically only used by the main function and tests.func Background() Context { return background} // TODO returns an ambient background context, which is never nil. 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.//// Cancelling 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)).//// Cancelling 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 k is v.//// Use context Values only for request-scoped data that transits processes and// APIs, not for passing optional parameters to functions.func WithValue(parent Context, k Key, v face{}) Context { c := newCtx(parent, neverCanceled) c.key, c.val = k, v return c} const maybeCanceled = trueconst 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() }}
// 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.
//
// Functions that require a Context should take it as the first parameter, 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.
//
// Future packages will create Contexts from standard request types like
// *http.Request.
package context
import (
"errors"
"fmt"
"sync"
"time"
)
// An 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.
//
// Packages that define a Context Key should provide type-safe accessors for the
// Values stores using that Key:
//
// // package foo defines a value that's stored in Contexts.
// package foo
//
// import "clive/x/code.google.com/p/go.net/context"
//
// // Foo is the type of value stored in the Contexts.
// type Foo struct {...}
//
// // contextKey is the Key for foo.Foo values in Contexts. It is
// // unexported; foo clients use foo.NewContext and foo.FromContext
// // instead of using this Key directly.
// var contextKey = context.NewKey("import/path/of/foo.Foo")
//
// // NewContext returns a new Context that carries value foo.
// func NewContext(ctx context.Context, foo *Foo) context.Context {
// return context.WithValue(contextKey, foo)
// }
//
// // FromContext returns the Foo value stored in ctx, if any.
// func FromContext(ctx context.Context) (*Foo, bool) {
// foo, ok := ctx.Value(contextKey).(*Foo)
// return foo, ok
// }
struct Key {
name string
}
var keys = make(map[string]Key)
// NewKey allocates a new Key with the provided name. The name must be
// non-empty and globally unique: if NewKey is called multiple times with the
// same name it panics. NewKey should only be called during initalization.
func NewKey(name string) Key {
if name == "" {
panic("context.NewKey called with an empty name")
}
if _, ok := keys[name]; ok {
panic(fmt.Sprintf("context.NewKey(%q) called multiple times", name))
}
k := Key{name}
keys[name] = k
return k
}
// String returns the Key's name.
func (k Key) String() string {
return k.name
}
// A Context carries deadlines, and cancellation signals, and other values
// across API boundaries.
//
// Context's methods may be called by multiple goroutines simultaneously.
interface Context {
// 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.
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.
Value(key Key) face{}
}
// 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.
struct ctx {
parent Context // set by newCtx
done chan struct{} // closed by the first cancel call. nil if uncancelable.
key Key // set by WithValue
val face{} // 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 Key) face{} {
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 an ambient background context, which is never nil. This
// context represents the intrinsic state of the application at startup time,
// independent of any incoming request state.
//
// The Background context is typically only used by the main function and tests.
func Background() Context {
return background
}
// TODO returns an ambient background context, which is never nil. 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.
//
// Cancelling 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)).
//
// Cancelling 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 k is v.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
func WithValue(parent Context, k Key, v face{}) Context {
c := newCtx(parent, neverCanceled)
c.key, c.val = k, v
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()
}
}