void runtime·stoptheworld(void) { uint32 v; schedlock(); runtime·gcwaiting = 1; setmcpumax(1); // while mcpu > 1 for(;;) { v = runtime·sched.atomic; if(atomic_mcpu(v) <= 1) break; // It would be unsafe for multiple threads to be using // the stopped note at once, but there is only // ever one thread doing garbage collection. runtime·noteclear(&runtime·sched.stopped); if(atomic_waitstop(v)) runtime·throw("invalid waitstop"); // atomic { waitstop = 1 }, predicated on mcpu <= 1 check above // still being true. if(!runtime·cas(&runtime·sched.atomic, v, v+(1<<waitstopShift))) continue; schedunlock(); runtime·notesleep(&runtime·sched.stopped); schedlock(); } runtime·singleproc = runtime·gomaxprocs == 1; schedunlock(); }
void runtime·starttheworld(bool extra) { M *m; schedlock(); runtime·gcwaiting = 0; setmcpumax(runtime·gomaxprocs); matchmg(); if(extra && canaddmcpu()) { // Start a new m that will (we hope) be idle // and so available to help when the next // garbage collection happens. // canaddmcpu above did mcpu++ // (necessary, because m will be doing various // initialization work so is definitely running), // but m is not running a specific goroutine, // so set the helpgc flag as a signal to m's // first schedule(nil) to mcpu-- and grunning--. m = runtime·newm(); m->helpgc = 1; runtime·sched.grunning++; } schedunlock(); }
// The main goroutine. void runtime_main(void) { // Lock the main goroutine onto this, the main OS thread, // during initialization. Most programs won't care, but a few // do require certain calls to be made by the main thread. // Those can arrange for main.main to run in the main thread // by calling runtime.LockOSThread during initialization // to preserve the lock. runtime_LockOSThread(); // From now on, newgoroutines may use non-main threads. setmcpumax(runtime_gomaxprocs); runtime_sched.init = true; scvg = __go_go(runtime_MHeap_Scavenger, nil); main_init(); runtime_sched.init = false; if(!runtime_sched.lockmain) runtime_UnlockOSThread(); // For gccgo we have to wait until after main is initialized // to enable GC, because initializing main registers the GC // roots. mstats.enablegc = 1; // The deadlock detection has false negatives. // Let scvg start up, to eliminate the false negative // for the trivial program func main() { select{} }. runtime_gosched(); main_main(); runtime_exit(0); for(;;) *(int32*)0 = 0; }
// The main goroutine. void runtime·main(void) { // Lock the main goroutine onto this, the main OS thread, // during initialization. Most programs won't care, but a few // do require certain calls to be made by the main thread. // Those can arrange for main.main to run in the main thread // by calling runtime.LockOSThread during initialization // to preserve the lock. runtime·LockOSThread(); // From now on, newgoroutines may use non-main threads. setmcpumax(runtime·gomaxprocs); runtime·sched.init = true; scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·main); main·init(); runtime·sched.init = false; if(!runtime·sched.lockmain) runtime·UnlockOSThread(); // The deadlock detection has false negatives. // Let scvg start up, to eliminate the false negative // for the trivial program func main() { select{} }. runtime·gosched(); main·main(); runtime·exit(0); for(;;) *(int32*)runtime·main = 0; }
// The bootstrap sequence is: // // call osinit // call schedinit // make & queue new G // call runtime_mstart // // The new G calls runtime_main. void runtime_schedinit(void) { int32 n; const byte *p; m = &runtime_m0; g = &runtime_g0; m->g0 = g; m->curg = g; g->m = m; initcontext(); inittlssize(); m->nomemprof++; runtime_mallocinit(); mcommoninit(m); runtime_goargs(); runtime_goenvs(); // For debugging: // Allocate internal symbol table representation now, // so that we don't need to call malloc when we crash. // runtime_findfunc(0); runtime_gomaxprocs = 1; p = runtime_getenv("GOMAXPROCS"); if(p != nil && (n = runtime_atoi(p)) != 0) { if(n > maxgomaxprocs) n = maxgomaxprocs; runtime_gomaxprocs = n; } // wait for the main goroutine to start before taking // GOMAXPROCS into account. setmcpumax(1); runtime_singleproc = runtime_gomaxprocs == 1; canaddmcpu(); // mcpu++ to account for bootstrap m m->helpgc = 1; // flag to tell schedule() to mcpu-- runtime_sched.grunning++; // Can not enable GC until all roots are registered. // mstats.enablegc = 1; m->nomemprof--; }
// The bootstrap sequence is: // // call osinit // call schedinit // make & queue new G // call runtime·mstart // // The new G calls runtime·main. void runtime·schedinit(void) { int32 n; byte *p; m->nomemprof++; runtime·mprofinit(); runtime·mallocinit(); mcommoninit(m); runtime·goargs(); runtime·goenvs(); // For debugging: // Allocate internal symbol table representation now, // so that we don't need to call malloc when we crash. // runtime·findfunc(0); runtime·gomaxprocs = 1; p = runtime·getenv("GOMAXPROCS"); if(p != nil && (n = runtime·atoi(p)) != 0) { if(n > maxgomaxprocs) n = maxgomaxprocs; runtime·gomaxprocs = n; } // wait for the main goroutine to start before taking // GOMAXPROCS into account. setmcpumax(1); runtime·singleproc = runtime·gomaxprocs == 1; canaddmcpu(); // mcpu++ to account for bootstrap m m->helpgc = 1; // flag to tell schedule() to mcpu-- runtime·sched.grunning++; mstats.enablegc = 1; m->nomemprof--; if(raceenabled) runtime·raceinit(); }
// Implementation of runtime.GOMAXPROCS. // delete when scheduler is stronger int32 runtime·gomaxprocsfunc(int32 n) { int32 ret; uint32 v; schedlock(); ret = runtime·gomaxprocs; if(n <= 0) n = ret; if(n > maxgomaxprocs) n = maxgomaxprocs; runtime·gomaxprocs = n; if(runtime·gomaxprocs > 1) runtime·singleproc = false; if(runtime·gcwaiting != 0) { if(atomic_mcpumax(runtime·sched.atomic) != 1) runtime·throw("invalid mcpumax during gc"); schedunlock(); return ret; } setmcpumax(n); // If there are now fewer allowed procs // than procs running, stop. v = runtime·atomicload(&runtime·sched.atomic); if(atomic_mcpu(v) > n) { schedunlock(); runtime·gosched(); return ret; } // handle more procs matchmg(); schedunlock(); return ret; }
void runtime·starttheworld(void) { M *mp; int32 max; // Figure out how many CPUs GC could possibly use. max = runtime·gomaxprocs; if(max > runtime·ncpu) max = runtime·ncpu; if(max > MaxGcproc) max = MaxGcproc; schedlock(); runtime·gcwaiting = 0; setmcpumax(runtime·gomaxprocs); matchmg(); if(runtime·gcprocs() < max && canaddmcpu()) { // If GC could have used another helper proc, start one now, // in the hope that it will be available next time. // It would have been even better to start it before the collection, // but doing so requires allocating memory, so it's tricky to // coordinate. This lazy approach works out in practice: // we don't mind if the first couple gc rounds don't have quite // the maximum number of procs. // canaddmcpu above did mcpu++ // (necessary, because m will be doing various // initialization work so is definitely running), // but m is not running a specific goroutine, // so set the helpgc flag as a signal to m's // first schedule(nil) to mcpu-- and grunning--. mp = runtime·newm(); mp->helpgc = 1; runtime·sched.grunning++; } schedunlock(); }
// The bootstrap sequence is: // // call osinit // call schedinit // make & queue new G // call runtime·mstart // // The new G calls runtime·main. void runtime·schedinit(void) { int32 n; byte *p; m->nomemprof++; runtime·mallocinit(); mcommoninit(m); runtime·goargs(); runtime·goenvs(); // For debugging: // Allocate internal symbol table representation now, // so that we don't need to call malloc when we crash. // runtime·findfunc(0); runtime·gomaxprocs = 1; p = runtime·getenv("GOMAXPROCS"); if(p != nil && (n = runtime·atoi(p)) != 0) { if(n > maxgomaxprocs) n = maxgomaxprocs; runtime·gomaxprocs = n; } setmcpumax(runtime·gomaxprocs); runtime·singleproc = runtime·gomaxprocs == 1; canaddmcpu(); // mcpu++ to account for bootstrap m m->helpgc = 1; // flag to tell schedule() to mcpu-- runtime·sched.grunning++; mstats.enablegc = 1; m->nomemprof--; scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runtime·schedinit); }