]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix sleep/wakeup race for GC assists
authorAustin Clements <austin@google.com>
Fri, 15 Jan 2016 18:28:41 +0000 (13:28 -0500)
committerAustin Clements <austin@google.com>
Sat, 16 Jan 2016 02:40:00 +0000 (02:40 +0000)
GC assists check gcBlackenEnabled under the assist queue lock to avoid
going to sleep after gcWakeAllAssists has already woken all assists.
However, currently we clear gcBlackenEnabled shortly *after* waking
all assists, which opens a window where this exact race can happen.

Fix this by clearing gcBlackenEnabled before waking blocked assists.
However, it's unlikely this actually matters because the world is
stopped between waking assists and clearing gcBlackenEnabled and there
aren't any obvious allocations during this window, so I don't think an
assist could actually slip in to this race window.

Updates #13645.

Change-Id: I7571f059530481dc781d8fd96a1a40aadebecb0d
Reviewed-on: https://go-review.googlesource.com/18682
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rick Hudson <rlh@golang.org>
src/runtime/mgc.go
src/runtime/mgcmark.go

index c09f70423d08fa50fdc941f7a1975c6a512b6194..92b811830c37e65f14bd055070cdc76ff298d11a 100644 (file)
@@ -1121,6 +1121,10 @@ top:
                // finalizers have been scanned.
                work.finalizersDone = true
 
+               // Disable assists and background workers. We must do
+               // this before waking blocked assists.
+               atomic.Store(&gcBlackenEnabled, 0)
+
                // Flush the gcWork caches. This must be done before
                // endCycle since endCycle depends on statistics kept
                // in these caches.
index 52545afa2993159fea6baaceaa546e53057584e6..eac45ec16850e64e0e70bfaa7d6612f379058408 100644 (file)
@@ -491,7 +491,8 @@ retry:
 }
 
 // gcWakeAllAssists wakes all currently blocked assists. This is used
-// at the end of a GC cycle.
+// at the end of a GC cycle. gcBlackenEnabled must be false to prevent
+// new assists from going to sleep after this point.
 func gcWakeAllAssists() {
        lock(&work.assistQueue.lock)
        injectglist(work.assistQueue.head.ptr())