aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mgc.go
diff options
context:
space:
mode:
authorAustin Clements <austin@google.com>2021-04-02 15:54:24 -0400
committerAustin Clements <austin@google.com>2021-04-12 19:22:50 +0000
commita25a77aed2d76b0aebff8892477f27283398a932 (patch)
tree9648dae5b837c12b105be85678ecf56769f8840d /src/runtime/mgc.go
parent07b2fee4607aa6c710411a7ac404f18be4dff6f7 (diff)
downloadgo-a25a77aed2d76b0aebff8892477f27283398a932.tar.gz
go-a25a77aed2d76b0aebff8892477f27283398a932.zip
runtime: block sweep completion on all sweep paths
The runtime currently has two different notions of sweep completion: 1. All spans are either swept or have begun sweeping. 2. The sweeper has *finished* sweeping all spans. Most things depend on condition 1. Notably, GC correctness depends on condition 1, but since all sweep operations a non-preemptible, the STW at the beginning of GC forces condition 1 to become condition 2. runtime.GC(), however, depends on condition 2, since the intent is to complete a complete GC cycle, and also update the heap profile (which can only be done after sweeping is complete). However, the way we compute condition 2 is racy right now and may in fact only indicate condition 1. Specifically, sweepone blocks condition 2 until all sweepone calls are done, but there are many other ways to enter the sweeper that don't block this. Hence, sweepone may see that there are no more spans in the sweep list and see that it's the last sweepone and declare sweeping done, while there's some other sweeper still working on a span. Fix this by making sure every entry to the sweeper participates in the protocol that blocks condition 2. To make sure we get this right, this CL introduces a type to track sweep blocking and (lightly) enforces span sweep ownership via the type system. This has the nice side-effect of abstracting the pattern of acquiring sweep ownership that's currently repeated in many different places. Fixes #45315. Change-Id: I7fab30170c5ae14c8b2f10998628735b8be6d901 Reviewed-on: https://go-review.googlesource.com/c/go/+/307915 Trust: Austin Clements <austin@google.com> Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/mgc.go')
-rw-r--r--src/runtime/mgc.go15
1 files changed, 10 insertions, 5 deletions
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
index ef3436d1f4..8c1ff20936 100644
--- a/src/runtime/mgc.go
+++ b/src/runtime/mgc.go
@@ -1749,6 +1749,13 @@ func gcMarkTermination(nextTriggerRatio float64) {
// so events don't leak into the wrong cycle.
mProf_NextCycle()
+ // There may be stale spans in mcaches that need to be swept.
+ // 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()
+
systemstack(func() { startTheWorldWithSema(true) })
// Flush the heap profile so we can start a new cycle next GC.
@@ -1772,6 +1779,9 @@ func gcMarkTermination(nextTriggerRatio float64) {
_p_.mcache.prepareForSweep()
})
})
+ // Now that we've swept stale spans in mcaches, they don't
+ // count against unswept spans.
+ sl.dispose()
// Print gctrace before dropping worldsema. As soon as we drop
// worldsema another cycle could start and smash the stats
@@ -2391,11 +2401,6 @@ func gcTestIsReachable(ptrs ...unsafe.Pointer) (mask uint64) {
// Force a full GC and sweep.
GC()
- // TODO(austin): Work around issue #45315. One GC() can return
- // without finishing the sweep. Do a second to force the sweep
- // through.
- GC()
-
// Process specials.
for i, s := range specials {
if !s.done {