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