aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/proc.c
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2014-08-29 11:08:10 +0400
committerDmitriy Vyukov <dvyukov@google.com>2014-08-29 11:08:10 +0400
commit42486ffc5d435e01ca9491b64d3a52d39de169d7 (patch)
treeac32833280ed781ec93442594b7e7a13154fcc02 /src/pkg/runtime/proc.c
parentef64d9ffcc237fde9bcaed1fd00c5036c4f489de (diff)
downloadgo-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.c44
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.