github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/context/pre_go17.go (about) 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 7 package context 8 9 import ( 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. 18 type emptyCtx int 19 20 func (*emptyCtx) Deadline() (deadline time.Time, ok bool) { 21 return 22 } 23 24 func (*emptyCtx) Done() <-chan struct{} { 25 return nil 26 } 27 28 func (*emptyCtx) Err() error { 29 return nil 30 } 31 32 func (*emptyCtx) Value(key interface{}) interface{} { 33 return nil 34 } 35 36 func (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 46 var ( 47 background = new(emptyCtx) 48 todo = new(emptyCtx) 49 ) 50 51 // Canceled is the error returned by Context.Err when the context is canceled. 52 var Canceled = errors.New("context canceled") 53 54 // DeadlineExceeded is the error returned by Context.Err when the context's 55 // deadline passes. 56 var 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. 64 func 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. 71 func 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. 79 func 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. 109 func 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. 125 func 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. 139 type 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. 146 type 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 156 func (c *cancelCtx) Done() <-chan struct{} { 157 return c.done 158 } 159 160 func (c *cancelCtx) Err() error { 161 c.mu.Lock() 162 defer c.mu.Unlock() 163 return c.err 164 } 165 166 func (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. 172 func (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. 204 func 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. 232 type timerCtx struct { 233 *cancelCtx 234 timer *time.Timer // Under cancelCtx.mu. 235 236 deadline time.Time 237 } 238 239 func (c *timerCtx) Deadline() (deadline time.Time, ok bool) { 240 return c.deadline, true 241 } 242 243 func (c *timerCtx) String() string { 244 return fmt.Sprintf("%v.WithDeadline(%s [%s])", c.cancelCtx.Context, c.deadline, c.deadline.Sub(time.Now())) 245 } 246 247 func (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 // } 271 func 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. 280 func 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. 286 type valueCtx struct { 287 Context 288 key, val interface{} 289 } 290 291 func (c *valueCtx) String() string { 292 return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val) 293 } 294 295 func (c *valueCtx) Value(key interface{}) interface{} { 296 if c.key == key { 297 return c.val 298 } 299 return c.Context.Value(key) 300 }