From 64b68bedc52d0b6eb7f464793c2be38382fadb6b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Tue, 21 Nov 2017 17:19:43 -0500 Subject: [PATCH] runtime/debug: make SetGCPercent(-1) wait for concurrent GC 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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/runtime/mgc.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index a28ecdec2d..ab90c289a5 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -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 } -- 2.50.0