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// +build !go1.7 6 7package context 8 9import ( 10 "errors" 11 "fmt" 12 "sync" 13 "time" 14) 15 16// An emptyCtx is never canceled, has no values, and has no deadline. It is not 17// struct{}, since vars of this type must have distinct addresses. 18type emptyCtx int 19 20func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { 21 return 22} 23 24func (*emptyCtx) Done() <-chan struct{} { 25 return nil 26} 27 28func (*emptyCtx) Err() error { 29 return nil 30} 31 32func (*emptyCtx) Value(key interface{}) interface{} { 33 return nil 34} 35 36func (e *emptyCtx) String() string { 37 switch e { 38 case background: 39 return "context.Background" 40 case todo: 41 return "context.TODO" 42 } 43 return "unknown empty Context" 44} 45 46var ( 47 background = new(emptyCtx) 48 todo = new(emptyCtx) 49) 50 51// Canceled is the error returned by Context.Err when the context is canceled. 52var Canceled = errors.New("context canceled") 53 54// DeadlineExceeded is the error returned by Context.Err when the context's 55// deadline passes. 56var DeadlineExceeded = errors.New("context deadline exceeded") 57 58// WithCancel returns a copy of parent with a new Done channel. The returned 59// context's Done channel is closed when the returned cancel function is called 60// or when the parent context's Done channel is closed, whichever happens first. 61// 62// Canceling this context releases resources associated with it, so code should 63// call cancel as soon as the operations running in this Context complete. 64func WithCancel(parent Context) (ctx Context, cancel CancelFunc) { 65 c := newCancelCtx(parent) 66 propagateCancel(parent, c) 67 return c, func() { c.cancel(true, Canceled) } 68} 69 70// newCancelCtx returns an initialized cancelCtx. 71func newCancelCtx(parent Context) *cancelCtx { 72 return &cancelCtx{ 73 Context: parent, 74 done: make(chan struct{}), 75 } 76} 77 78// propagateCancel arranges for child to be canceled when parent is. 79func propagateCancel(parent Context, child canceler) { 80 if parent.Done() == nil { 81 return // parent is never canceled 82 } 83 if p, ok := parentCancelCtx(parent); ok { 84 p.mu.Lock() 85 if p.err != nil { 86 // parent has already been canceled 87 child.cancel(false, p.err) 88 } else { 89 if p.children == nil { 90 p.children = make(map[canceler]bool) 91 } 92 p.children[child] = true 93 } 94 p.mu.Unlock() 95 } else { 96 go func() { 97 select { 98 case <-parent.Done(): 99 child.cancel(false, parent.Err()) 100 case <-child.Done(): 101 } 102 }() 103 } 104} 105 106// parentCancelCtx follows a chain of parent references until it finds a 107// *cancelCtx. This function understands how each of the concrete types in this 108// package represents its parent. 109func parentCancelCtx(parent Context) (*cancelCtx, bool) { 110 for { 111 switch c := parent.(type) { 112 case *cancelCtx: 113 return c, true 114 case *timerCtx: 115 return c.cancelCtx, true 116 case *valueCtx: 117 parent = c.Context 118 default: 119 return nil, false 120 } 121 } 122} 123 124// removeChild removes a context from its parent. 125func removeChild(parent Context, child canceler) { 126 p, ok := parentCancelCtx(parent) 127 if !ok { 128 return 129 } 130 p.mu.Lock() 131 if p.children != nil { 132 delete(p.children, child) 133 } 134 p.mu.Unlock() 135} 136 137// A canceler is a context type that can be canceled directly. The 138// implementations are *cancelCtx and *timerCtx. 139type canceler interface { 140 cancel(removeFromParent bool, err error) 141 Done() <-chan struct{} 142} 143 144// A cancelCtx can be canceled. When canceled, it also cancels any children 145// that implement canceler. 146type cancelCtx struct { 147 Context 148 149 done chan struct{} // closed by the first cancel call. 150 151 mu sync.Mutex 152 children map[canceler]bool // set to nil by the first cancel call 153 err error // set to non-nil by the first cancel call 154} 155 156func (c *cancelCtx) Done() <-chan struct{} { 157 return c.done 158} 159 160func (c *cancelCtx) Err() error { 161 c.mu.Lock() 162 defer c.mu.Unlock() 163 return c.err 164} 165 166func (c *cancelCtx) String() string { 167 return fmt.Sprintf("%v.WithCancel", c.Context) 168} 169 170// cancel closes c.done, cancels each of c's children, and, if 171// removeFromParent is true, removes c from its parent's children. 172func (c *cancelCtx) cancel(removeFromParent bool, err error) { 173 if err == nil { 174 panic("context: internal error: missing cancel error") 175 } 176 c.mu.Lock() 177 if c.err != nil { 178 c.mu.Unlock() 179 return // already canceled 180 } 181 c.err = err 182 close(c.done) 183 for child := range c.children { 184 // NOTE: acquiring the child's lock while holding parent's lock. 185 child.cancel(false, err) 186 } 187 c.children = nil 188 c.mu.Unlock() 189 190 if removeFromParent { 191 removeChild(c.Context, c) 192 } 193} 194 195// WithDeadline returns a copy of the parent context with the deadline adjusted 196// to be no later than d. If the parent's deadline is already earlier than d, 197// WithDeadline(parent, d) is semantically equivalent to parent. The returned 198// context's Done channel is closed when the deadline expires, when the returned 199// cancel function is called, or when the parent context's Done channel is 200// closed, whichever happens first. 201// 202// Canceling this context releases resources associated with it, so code should 203// call cancel as soon as the operations running in this Context complete. 204func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) { 205 if cur, ok := parent.Deadline(); ok && cur.Before(deadline) { 206 // The current deadline is already sooner than the new one. 207 return WithCancel(parent) 208 } 209 c := &timerCtx{ 210 cancelCtx: newCancelCtx(parent), 211 deadline: deadline, 212 } 213 propagateCancel(parent, c) 214 d := deadline.Sub(time.Now()) 215 if d <= 0 { 216 c.cancel(true, DeadlineExceeded) // deadline has already passed 217 return c, func() { c.cancel(true, Canceled) } 218 } 219 c.mu.Lock() 220 defer c.mu.Unlock() 221 if c.err == nil { 222 c.timer = time.AfterFunc(d, func() { 223 c.cancel(true, DeadlineExceeded) 224 }) 225 } 226 return c, func() { c.cancel(true, Canceled) } 227} 228 229// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to 230// implement Done and Err. It implements cancel by stopping its timer then 231// delegating to cancelCtx.cancel. 232type timerCtx struct { 233 *cancelCtx 234 timer *time.Timer // Under cancelCtx.mu. 235 236 deadline time.Time 237} 238 239func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 240 return c.deadline, true 241} 242 243func (c *timerCtx) String() string { 244 return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) 245} 246 247func (c *timerCtx) cancel(removeFromParent bool, err error) { 248 c.cancelCtx.cancel(false, err) 249 if removeFromParent { 250 // Remove this timerCtx from its parent cancelCtx's children. 251 removeChild(c.cancelCtx.Context, c) 252 } 253 c.mu.Lock() 254 if c.timer != nil { 255 c.timer.Stop() 256 c.timer = nil 257 } 258 c.mu.Unlock() 259} 260 261// WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). 262// 263// Canceling this context releases resources associated with it, so code should 264// call cancel as soon as the operations running in this Context complete: 265// 266// func slowOperationWithTimeout(ctx context.Context) (Result, error) { 267// ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond) 268// defer cancel() // releases resources if slowOperation completes before timeout elapses 269// return slowOperation(ctx) 270// } 271func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) { 272 return WithDeadline(parent, time.Now().Add(timeout)) 273} 274 275// WithValue returns a copy of parent in which the value associated with key is 276// val. 277// 278// Use context Values only for request-scoped data that transits processes and 279// APIs, not for passing optional parameters to functions. 280func WithValue(parent Context, key interface{}, val interface{}) Context { 281 return &valueCtx{parent, key, val} 282} 283 284// A valueCtx carries a key-value pair. It implements Value for that key and 285// delegates all other calls to the embedded Context. 286type valueCtx struct { 287 Context 288 key, val interface{} 289} 290 291func (c *valueCtx) String() string { 292 return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) 293} 294 295func (c *valueCtx) Value(key interface{}) interface{} { 296 if c.key == key { 297 return c.val 298 } 299 return c.Context.Value(key) 300} 301