// It kicks off the background sweeper goroutine and enables GC.
func gcenable() {
c := make(chan int, 1)
+ expectSystemGoroutine()
go bgsweep(c)
<-c
memstats.enablegc = true // now that runtime is initialized, GC is okay
break
}
if p.gcBgMarkWorker == 0 {
+ expectSystemGoroutine()
go gcBgMarkWorker(p)
notetsleepg(&work.bgMarkReady, -1)
noteclear(&work.bgMarkReady)
// start forcegc helper goroutine
func init() {
+ expectSystemGoroutine()
go forcegchelper()
}
return newg
}
+// expectedSystemGoroutines counts the number of goroutines expected
+// to mark themselves as system goroutines. After they mark themselves
+// by calling setSystemGoroutine, this is decremented. NumGoroutines
+// uses this to wait for all system goroutines to mark themselves
+// before it counts them.
+var expectedSystemGoroutines uint32
+
+// expectSystemGoroutine is called when starting a goroutine that will
+// call setSystemGoroutine. It increments expectedSystemGoroutines.
+func expectSystemGoroutine() {
+ atomic.Xadd(&expectedSystemGoroutines, +1)
+}
+
+// waitForSystemGoroutines waits for all currently expected system
+// goroutines to register themselves.
+func waitForSystemGoroutines() {
+ for atomic.Load(&expectedSystemGoroutines) > 0 {
+ Gosched()
+ osyield()
+ }
+}
+
// setSystemGoroutine marks this goroutine as a "system goroutine".
// In the gc toolchain this is done by comparing startpc to a list of
// saved special PCs. In gccgo that approach does not work as startpc
func setSystemGoroutine() {
getg().isSystemGoroutine = true
atomic.Xadd(&sched.ngsys, +1)
+ atomic.Xadd(&expectedSystemGoroutines, -1)
}
// Put on gfree list.