diff options
author | Michael Anthony Knyszek <mknyszek@google.com> | 2021-07-08 21:42:01 +0000 |
---|---|---|
committer | Michael Knyszek <mknyszek@google.com> | 2021-10-29 17:12:47 +0000 |
commit | 3aecb3a8f7e1435c76003a20068c0208fd73649a (patch) | |
tree | 2862c933092a5dcf54f70bb397bfc0ebfd259ad9 /src/runtime/mgc.go | |
parent | f2885263748364a2a7f4e0d47abd5095699cd39f (diff) | |
download | go-3aecb3a8f7e1435c76003a20068c0208fd73649a.tar.gz go-3aecb3a8f7e1435c76003a20068c0208fd73649a.zip |
runtime: fix sweep termination condition
Currently, there is a chance that the sweep termination condition could
flap, causing e.g. runtime.GC to return before all sweep work has not
only been drained, but also completed. CL 307915 and CL 307916 attempted
to fix this problem, but it is still possible that mheap_.sweepDrained is
marked before any outstanding sweepers are accounted for in
mheap_.sweepers, leaving a window in which a thread could observe
isSweepDone as true before it actually was (and after some time it would
revert to false, then true again, depending on the number of outstanding
sweepers at that point).
This change fixes the sweep termination condition by merging
mheap_.sweepers and mheap_.sweepDrained into a single atomic value.
This value is updated such that a new potential sweeper will increment
the oustanding sweeper count iff there are still outstanding spans to be
swept without an outstanding sweeper to pick them up. This design
simplifies the sweep termination condition into a single atomic load and
comparison and ensures the condition never flaps.
Updates #46500.
Fixes #45315.
Change-Id: I6d69aff156b8d48428c4cc8cfdbf28be346dbf04
Reviewed-on: https://go-review.googlesource.com/c/go/+/333389
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/mgc.go')
-rw-r--r-- | src/runtime/mgc.go | 12 |
1 files changed, 7 insertions, 5 deletions
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go index 429b907322..e7c023919c 100644 --- a/src/runtime/mgc.go +++ b/src/runtime/mgc.go @@ -154,7 +154,7 @@ func gcinit() { throw("size of Workbuf is suboptimal") } // No sweep on the first cycle. - mheap_.sweepDrained = 1 + sweep.active.state.Store(sweepDrainedMask) // Initialize GC pacer state. // Use the environment variable GOGC for the initial gcPercent value. @@ -1022,8 +1022,10 @@ func gcMarkTermination(nextTriggerRatio float64) { // Those aren't tracked in any sweep lists, so we need to // count them against sweep completion until we ensure all // those spans have been forced out. - sl := newSweepLocker() - sl.blockCompletion() + sl := sweep.active.begin() + if !sl.valid { + throw("failed to set sweep barrier") + } systemstack(func() { startTheWorldWithSema(true) }) @@ -1050,7 +1052,7 @@ func gcMarkTermination(nextTriggerRatio float64) { }) // Now that we've swept stale spans in mcaches, they don't // count against unswept spans. - sl.dispose() + sweep.active.end(sl) // Print gctrace before dropping worldsema. As soon as we drop // worldsema another cycle could start and smash the stats @@ -1457,7 +1459,7 @@ func gcSweep(mode gcMode) { lock(&mheap_.lock) mheap_.sweepgen += 2 - mheap_.sweepDrained = 0 + sweep.active.reset() mheap_.pagesSwept.Store(0) mheap_.sweepArenas = mheap_.allArenas mheap_.reclaimIndex.Store(0) |