]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/debug: make SetGCPercent(-1) wait for concurrent GC
authorAustin Clements <austin@google.com>
Tue, 21 Nov 2017 22:19:43 +0000 (17:19 -0500)
committerAustin Clements <austin@google.com>
Wed, 22 Nov 2017 14:47:12 +0000 (14:47 +0000)
Currently, SetGCPercent(-1) disables GC, but doesn't wait for any
currently running concurrent GC to finish, so GC can still be running
when it returns. This is a change in behavior from Go 1.8, probably
defies user expectations, and can break various runtime tests that
depend on SetGCPercent(-1) to disable garbage collection in order to
prevent preemption deadlocks.

Fix this by making SetGCPercent(-1) block until any concurrently
running GC cycle finishes.

Fixes #22443.

Change-Id: I904133a34acf97a7942ef4531ace0647b13930ef
Reviewed-on: https://go-review.googlesource.com/79195
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/runtime/mgc.go

index a28ecdec2d9b2f4beb20fa57090efdfde59d8bdb..ab90c289a5b5c51508d89cc06f26fa35d7c92106 100644 (file)
@@ -230,6 +230,24 @@ func setGCPercent(in int32) (out int32) {
        // Update pacing in response to gcpercent change.
        gcSetTriggerRatio(memstats.triggerRatio)
        unlock(&mheap_.lock)
+
+       // If we just disabled GC, wait for any concurrent GC to
+       // finish so we always return with no GC running.
+       if in < 0 {
+               // Disable phase transitions.
+               lock(&work.sweepWaiters.lock)
+               if gcphase == _GCmark {
+                       // GC is active. Wait until we reach sweeping.
+                       gp := getg()
+                       gp.schedlink = work.sweepWaiters.head
+                       work.sweepWaiters.head.set(gp)
+                       goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
+               } else {
+                       // GC isn't active.
+                       unlock(&work.sweepWaiters.lock)
+               }
+       }
+
        return out
 }