pre_go17.go (8136B)
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 8 package context 9 10 import ( 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. 19 type emptyCtx int 20 21 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { 22 return 23 } 24 25 func (*emptyCtx) Done() <-chan struct{} { 26 return nil 27 } 28 29 func (*emptyCtx) Err() error { 30 return nil 31 } 32 33 func (*emptyCtx) Value(key interface{}) interface{} { 34 return nil 35 } 36 37 func (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 47 var ( 48 background = new(emptyCtx) 49 todo = new(emptyCtx) 50 ) 51 52 // Canceled is the error returned by Context.Err when the context is canceled. 53 var Canceled = errors.New("context canceled") 54 55 // DeadlineExceeded is the error returned by Context.Err when the context's 56 // deadline passes. 57 var 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. 65 func 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. 72 func 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. 80 func 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. 110 func 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. 126 func 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. 140 type 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. 147 type 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 157 func (c *cancelCtx) Done() <-chan struct{} { 158 return c.done 159 } 160 161 func (c *cancelCtx) Err() error { 162 c.mu.Lock() 163 defer c.mu.Unlock() 164 return c.err 165 } 166 167 func (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. 173 func (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. 205 func 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. 233 type timerCtx struct { 234 *cancelCtx 235 timer *time.Timer // Under cancelCtx.mu. 236 237 deadline time.Time 238 } 239 240 func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 241 return c.deadline, true 242 } 243 244 func (c *timerCtx) String() string { 245 return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) 246 } 247 248 func (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 // } 272 func 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. 281 func 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. 287 type valueCtx struct { 288 Context 289 key, val interface{} 290 } 291 292 func (c *valueCtx) String() string { 293 return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) 294 } 295 296 func (c *valueCtx) Value(key interface{}) interface{} { 297 if c.key == key { 298 return c.val 299 } 300 return c.Context.Value(key) 301 }