aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-02 19:18:46 -0400
committerRuss Cox <rsc@golang.org>2014-09-02 19:18:46 -0400
commit9aa7d136f52928587a6bd2db320f4f4f2b6b0666 (patch)
treea96197bfb90cf3495ce1803106c670ab78d72bff /src/pkg/runtime
parentd8cbbe68024256ef4ead0a9d4d9d874c28f41a31 (diff)
downloadgo-9aa7d136f52928587a6bd2db320f4f4f2b6b0666.tar.xz
runtime: avoid race with forcegc helper
While we are here, give the gc helper a real function name that will appear in stack traces. LGTM=rlh R=rlh CC=dvyukov, golang-codereviews https://golang.org/cl/133470043
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/proc.c9
-rw-r--r--src/pkg/runtime/proc.go34
2 files changed, 24 insertions, 19 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index d1ebd853bb..9229c53a8c 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -2846,9 +2846,12 @@ sysmon(void)
lastgc = runtime·atomicload64(&mstats.last_gc);
if(lastgc != 0 && unixnow - lastgc > forcegcperiod && runtime·atomicload(&runtime·forcegc.idle)) {
runtime·lock(&runtime·forcegc.lock);
- runtime·forcegc.idle = 0;
- runtime·forcegc.g->schedlink = nil;
- injectglist(runtime·forcegc.g);
+ if(runtime·forcegc.g != nil) {
+ // Goroutine may be started but has not initialized g yet.
+ runtime·forcegc.idle = 0;
+ runtime·forcegc.g->schedlink = nil;
+ injectglist(runtime·forcegc.g);
+ }
runtime·unlock(&runtime·forcegc.lock);
}
diff --git a/src/pkg/runtime/proc.go b/src/pkg/runtime/proc.go
index 6c295c7b18..d47503e230 100644
--- a/src/pkg/runtime/proc.go
+++ b/src/pkg/runtime/proc.go
@@ -31,23 +31,25 @@ var parkunlock_c byte
// start forcegc helper goroutine
func init() {
- go func() {
- forcegc.g = getg()
- forcegc.g.issystem = true
- for {
- lock(&forcegc.lock)
- if forcegc.idle != 0 {
- gothrow("forcegc: phase error")
- }
- atomicstore(&forcegc.idle, 1)
- goparkunlock(&forcegc.lock, "force gc (idle)")
- // this goroutine is explicitly resumed by sysmon
- if debug.gctrace > 0 {
- println("GC forced")
- }
- gogc(1)
+ go forcegchelper()
+}
+
+func forcegchelper() {
+ forcegc.g = getg()
+ forcegc.g.issystem = true
+ for {
+ lock(&forcegc.lock)
+ if forcegc.idle != 0 {
+ gothrow("forcegc: phase error")
}
- }()
+ atomicstore(&forcegc.idle, 1)
+ goparkunlock(&forcegc.lock, "force gc (idle)")
+ // this goroutine is explicitly resumed by sysmon
+ if debug.gctrace > 0 {
+ println("GC forced")
+ }
+ gogc(1)
+ }
}
// Gosched yields the processor, allowing other goroutines to run. It does not