G** runtime·allg;
uintptr runtime·allglen;
static uintptr allgcap;
+ForceGCState runtime·forcegc;
void runtime·mstart(void);
static void runqput(P*, G*);
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:
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)
sysmon(void)
{
uint32 idle, delay, nscavenge;
- int64 now, unixnow, lastpoll, lasttrace;
+ int64 now, unixnow, lastpoll, lasttrace, lastgc;
int64 forcegcperiod, scavengelimit, lastscavenge, maxsleep;
G *gp;
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
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.
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)
+ }
+ }()
+}
+
// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {
typedef struct CgoMal CgoMal;
typedef struct PollDesc PollDesc;
typedef struct DebugVars DebugVars;
+typedef struct ForceGCState ForceGCState;
/*
* Per-CPU declaration.
int32 scavenge;
};
+struct ForceGCState
+{
+ Mutex lock;
+ G* g;
+ uint32 idle;
+};
+
extern bool runtime·precisestack;
extern bool runtime·copystack;
extern DebugVars runtime·debug;
extern uintptr runtime·maxstacksize;
extern Note runtime·signote;
+extern ForceGCState runtime·forcegc;
/*
* common functions and data