File tree Expand file tree Collapse file tree 2 files changed +38
-2
lines changed Expand file tree Collapse file tree 2 files changed +38
-2
lines changed Original file line number Diff line number Diff line change @@ -303,8 +303,12 @@ func WithRootCancel(parent *T) (*T, CancelFunc) {
303
303
// Forward the cancelation from the root context to the newly
304
304
// created context.
305
305
go func () {
306
- <- rootCtx .Done ()
307
- cancel ()
306
+ select {
307
+ case <- rootCtx .Done ():
308
+ cancel ()
309
+ case <- ctx .Done ():
310
+ cancel ()
311
+ }
308
312
}()
309
313
} else if atomic .AddInt32 (& nRootCancelWarning , 1 ) < 3 {
310
314
vlog .Errorf ("context.WithRootCancel: context %+v is not derived from root v23 context.\n " , parent )
Original file line number Diff line number Diff line change 9
9
gocontext "context"
10
10
"fmt"
11
11
"os"
12
+ "runtime"
13
+ "strings"
12
14
"sync"
13
15
"testing"
14
16
"time"
@@ -320,6 +322,36 @@ func TestRootCancelChain(t *testing.T) {
320
322
}
321
323
}
322
324
325
+ func TestRootCancelGoroutineLeak (t * testing.T ) {
326
+ rootCtx , rootcancel := context .RootContext ()
327
+ const iterations = 1024
328
+ for i := 0 ; i != iterations ; i ++ {
329
+ _ , cancel := context .WithRootCancel (rootCtx )
330
+ cancel ()
331
+ }
332
+
333
+ // Arbitrary threshold to wait for the goroutines in the created contexts
334
+ // above to exit. This threshold was arbitrarily created after running
335
+ // `go test -count=10000 -run TestRootCancelGoroutineLeak$` and verifying
336
+ // that the tests did not fail flakily.
337
+ const waitThreshold = 8 * time .Millisecond
338
+ time .Sleep (waitThreshold )
339
+
340
+ // Verify that goroutines no longer exist in the runtime stack.
341
+ buf := make ([]byte , 2 << 20 )
342
+ buf = buf [:runtime .Stack (buf , true )]
343
+ count := 0
344
+ for _ , g := range strings .Split (string (buf ), "\n \n " ) {
345
+ if strings .Contains (g , "v.io/v23/context.WithRootCancel.func1" ) {
346
+ count ++
347
+ }
348
+ }
349
+ if count != 0 {
350
+ t .Errorf ("expected 0 but got %d: goroutine leaking in WithRootCancel" , count )
351
+ }
352
+ rootcancel ()
353
+ }
354
+
323
355
func TestRootCancel_GoContext (t * testing.T ) {
324
356
root , rootcancel := context .RootContext ()
325
357
You can’t perform that action at this time.
0 commit comments