aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/runtime/mgc.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/mgc.go')
-rw-r--r--libgo/go/runtime/mgc.go71
1 files changed, 34 insertions, 37 deletions
diff --git a/libgo/go/runtime/mgc.go b/libgo/go/runtime/mgc.go
index 626f088..4ef982d 100644
--- a/libgo/go/runtime/mgc.go
+++ b/libgo/go/runtime/mgc.go
@@ -232,21 +232,10 @@ func setGCPercent(in int32) (out int32) {
gcSetTriggerRatio(memstats.triggerRatio)
unlock(&mheap_.lock)
- // If we just disabled GC, wait for any concurrent GC to
+ // If we just disabled GC, wait for any concurrent GC mark 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)
- }
+ gcWaitOnMark(atomic.Load(&work.cycles))
}
return out
@@ -1091,21 +1080,10 @@ func GC() {
// GC may move ahead on its own. For example, when we block
// until mark termination N, we may wake up in cycle N+2.
- gp := getg()
-
- // Prevent the GC phase or cycle count from changing.
- lock(&work.sweepWaiters.lock)
+ // Wait until the current sweep termination, mark, and mark
+ // termination complete.
n := atomic.Load(&work.cycles)
- if gcphase == _GCmark {
- // Wait until sweep termination, mark, and mark
- // termination of cycle N complete.
- gp.schedlink = work.sweepWaiters.head
- work.sweepWaiters.head.set(gp)
- goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
- } else {
- // We're in sweep N already.
- unlock(&work.sweepWaiters.lock)
- }
+ gcWaitOnMark(n)
// We're now in sweep N or later. Trigger GC cycle N+1, which
// will first finish sweep N if necessary and then enter sweep
@@ -1113,14 +1091,7 @@ func GC() {
gcStart(gcBackgroundMode, gcTrigger{kind: gcTriggerCycle, n: n + 1})
// Wait for mark termination N+1 to complete.
- lock(&work.sweepWaiters.lock)
- if gcphase == _GCmark && atomic.Load(&work.cycles) == n+1 {
- gp.schedlink = work.sweepWaiters.head
- work.sweepWaiters.head.set(gp)
- goparkunlock(&work.sweepWaiters.lock, "wait for GC cycle", traceEvGoBlock, 1)
- } else {
- unlock(&work.sweepWaiters.lock)
- }
+ gcWaitOnMark(n + 1)
// Finish sweep N+1 before returning. We do this both to
// complete the cycle and because runtime.GC() is often used
@@ -1157,6 +1128,32 @@ func GC() {
releasem(mp)
}
+// gcWaitOnMark blocks until GC finishes the Nth mark phase. If GC has
+// already completed this mark phase, it returns immediately.
+func gcWaitOnMark(n uint32) {
+ for {
+ // Disable phase transitions.
+ lock(&work.sweepWaiters.lock)
+ nMarks := atomic.Load(&work.cycles)
+ if gcphase != _GCmark {
+ // We've already completed this cycle's mark.
+ nMarks++
+ }
+ if nMarks > n {
+ // We're done.
+ unlock(&work.sweepWaiters.lock)
+ return
+ }
+
+ // Wait until sweep termination, mark, and mark
+ // termination of cycle N complete.
+ gp := getg()
+ gp.schedlink = work.sweepWaiters.head
+ work.sweepWaiters.head.set(gp)
+ goparkunlock(&work.sweepWaiters.lock, waitReasonWaitForGCCycle, traceEvGoBlock, 1)
+ }
+}
+
// gcMode indicates how concurrent a GC cycle should be.
type gcMode int
@@ -1531,7 +1528,7 @@ func gcMarkTermination(nextTriggerRatio float64) {
_g_.m.traceback = 2
gp := _g_.m.curg
casgstatus(gp, _Grunning, _Gwaiting)
- gp.waitreason = "garbage collection"
+ gp.waitreason = waitReasonGarbageCollection
// Run gc on the g0 stack. We do this so that the g stack
// we're currently running on will no longer change. Cuts
@@ -1800,7 +1797,7 @@ func gcBgMarkWorker(_p_ *p) {
}
}
return true
- }, unsafe.Pointer(park), "GC worker (idle)", traceEvGoBlock, 0)
+ }, unsafe.Pointer(park), waitReasonGCWorkerIdle, traceEvGoBlock, 0)
// Loop until the P dies and disassociates this
// worker (the P may later be reused, in which case