]>
Commit | Line | Data |
---|---|---|
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 | } |