diff options
| author | Dmitriy Vyukov <dvyukov@google.com> | 2014-08-29 11:08:10 +0400 |
|---|---|---|
| committer | Dmitriy Vyukov <dvyukov@google.com> | 2014-08-29 11:08:10 +0400 |
| commit | 42486ffc5d435e01ca9491b64d3a52d39de169d7 (patch) | |
| tree | ac32833280ed781ec93442594b7e7a13154fcc02 /src/pkg/runtime/proc.c | |
| parent | ef64d9ffcc237fde9bcaed1fd00c5036c4f489de (diff) | |
| download | go-42486ffc5d435e01ca9491b64d3a52d39de169d7.tar.xz | |
runtime: convert forcegc helper to Go
Also fix a bunch of bugs:
1. Accesses to last_gc must be atomic (it's int64).
2. last_gc still can be 0 during first checks in sysmon, check for 0.
3. forcegc.g can be unitialized when sysmon accesses it:
forcegc.g is initialized by main goroutine (forcegc.g = newproc1(...)),
and main goroutine is unsynchronized with both sysmon and forcegc goroutine.
Initialize forcegc.g in the forcegc goroutine itself instead.
LGTM=khr
R=golang-codereviews, khr
CC=golang-codereviews, rsc
https://golang.org/cl/136770043
Diffstat (limited to 'src/pkg/runtime/proc.c')
| -rw-r--r-- | src/pkg/runtime/proc.c | 44 |
1 files changed, 9 insertions, 35 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 194928373c..66c5d475bb 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -88,6 +88,7 @@ static Mutex allglock; // the following vars are protected by this lock or by st G** runtime·allg; uintptr runtime·allglen; static uintptr allgcap; +ForceGCState runtime·forcegc; void runtime·mstart(void); static void runqput(P*, G*); @@ -130,15 +131,6 @@ static bool exitsyscallfast(void); static bool haveexperiment(int8*); static void allgadd(G*); -static void forcegchelper(void); -static struct -{ - Mutex lock; - G* g; - FuncVal fv; - uint32 idle; -} forcegc; - extern String runtime·buildVersion; // The bootstrap sequence is: @@ -254,8 +246,6 @@ runtime·main(void) if(g->m != &runtime·m0) runtime·throw("runtime·main not on m0"); - forcegc.fv.fn = forcegchelper; - forcegc.g = runtime·newproc1(&forcegc.fv, nil, 0, 0, runtime·main); main·init(); if(g->defer != &d || d.fn != &initDone) @@ -2779,7 +2769,7 @@ static void sysmon(void) { uint32 idle, delay, nscavenge; - int64 now, unixnow, lastpoll, lasttrace; + int64 now, unixnow, lastpoll, lasttrace, lastgc; int64 forcegcperiod, scavengelimit, lastscavenge, maxsleep; G *gp; @@ -2854,12 +2844,13 @@ sysmon(void) idle++; // check if we need to force a GC - if(unixnow - mstats.last_gc > forcegcperiod && runtime·atomicload(&forcegc.idle)) { - runtime·lock(&forcegc.lock); - forcegc.idle = 0; - forcegc.g->schedlink = nil; - injectglist(forcegc.g); - runtime·unlock(&forcegc.lock); + 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); + runtime·unlock(&runtime·forcegc.lock); } // scavenge heap once in a while @@ -2943,23 +2934,6 @@ retake(int64 now) return n; } -static void -forcegchelper(void) -{ - g->issystem = true; - for(;;) { - runtime·lock(&forcegc.lock); - if(forcegc.idle) - runtime·throw("forcegc: phase error"); - runtime·atomicstore(&forcegc.idle, 1); - runtime·parkunlock(&forcegc.lock, runtime·gostringnocopy((byte*)"force gc (idle)")); - // this goroutine is explicitly resumed by sysmon - if(runtime·debug.gctrace > 0) - runtime·printf("GC forced\n"); - runtime·gc(1); - } -} - // Tell all goroutines that they have been preempted and they should stop. // This function is purely best-effort. It can fail to inform a goroutine if a // processor just started running it. |
