@@ -51,6 +51,10 @@ func (g *ContextGuard) Quit() {
51
51
cancel ()
52
52
}
53
53
54
+ // Clear cancelFns. It is safe to use nil, because no write
55
+ // operations to it can happen after g.quit is closed.
56
+ g .cancelFns = nil
57
+
54
58
close (g .quit )
55
59
})
56
60
}
@@ -149,7 +153,7 @@ func (g *ContextGuard) Create(ctx context.Context,
149
153
}
150
154
151
155
if opts .blocking {
152
- g .ctxBlocking (ctx , cancel )
156
+ g .ctxBlocking (ctx )
153
157
154
158
return ctx , cancel
155
159
}
@@ -169,9 +173,10 @@ func (g *ContextGuard) Create(ctx context.Context,
169
173
return ctx , cancel
170
174
}
171
175
172
- // ctxQuitUnsafe spins off a goroutine that will block until the passed context
173
- // is cancelled or until the quit channel has been signaled after which it will
174
- // call the passed cancel function and decrement the wait group.
176
+ // ctxQuitUnsafe increases the wait group counter, waits until the context is
177
+ // cancelled and decreases the wait group counter. It stores the passed cancel
178
+ // function and returns a wrapped version, which removed the stored one and
179
+ // calls it. The Quit method calls all the stored cancel functions.
175
180
//
176
181
// NOTE: the caller must hold the ContextGuard's mutex before calling this
177
182
// function.
@@ -181,35 +186,27 @@ func (g *ContextGuard) ctxQuitUnsafe(ctx context.Context,
181
186
cancel = g .addCancelFnUnsafe (cancel )
182
187
183
188
g .wg .Add (1 )
184
- go func () {
185
- defer cancel ()
186
- defer g .wg .Done ()
187
-
188
- select {
189
- case <- g .quit :
190
189
191
- case <- ctx .Done ():
192
- }
193
- }()
190
+ // We don't have to wait on g.quit here: g.quit can be closed only in
191
+ // the Quit method, which also closes the context we are waiting for.
192
+ context .AfterFunc (ctx , func () {
193
+ g .wg .Done ()
194
+ })
194
195
195
196
return cancel
196
197
}
197
198
198
- // ctxBlocking spins off a goroutine that will block until the passed context
199
- // is cancelled after which it will call the passed cancel function and
200
- // decrement the wait group.
201
- func ( g * ContextGuard ) ctxBlocking ( ctx context. Context ,
202
- cancel context. CancelFunc ) {
203
-
199
+ // ctxBlocking increases the wait group counter, waits until the context is
200
+ // cancelled and decreases the wait group counter.
201
+ //
202
+ // NOTE: the caller must hold the ContextGuard's mutex before calling this
203
+ // function.
204
+ func ( g * ContextGuard ) ctxBlocking ( ctx context. Context ) {
204
205
g .wg .Add (1 )
205
- go func () {
206
- defer cancel ()
207
- defer g .wg .Done ()
208
206
209
- select {
210
- case <- ctx .Done ():
211
- }
212
- }()
207
+ context .AfterFunc (ctx , func () {
208
+ g .wg .Done ()
209
+ })
213
210
}
214
211
215
212
// addCancelFnUnsafe adds a context cancel function to the manager and returns a
0 commit comments