Sched runtime·sched;
int32 gomaxprocs;
+// An m which is waiting for notewakeup(&m->havenextg). This may be
+// only be accessed while the scheduler lock is held. This is used to
+// minimize the number of times we call notewakeup while the scheduler
+// lock is held, since the m will normally move quickly to lock the
+// scheduler itself, producing lock contention.
+static M* mwakeup;
+
// Scheduling helpers. Sched must be locked.
static void gput(G*); // put/get on ghead/gtail
static G* gget(void);
m->nomemprof--;
}
+// Lock the scheduler.
+static void
+schedlock(void)
+{
+ runtime·lock(&runtime·sched);
+}
+
+// Unlock the scheduler.
+static void
+schedunlock(void)
+{
+ M *m;
+
+ m = mwakeup;
+ mwakeup = nil;
+ runtime·unlock(&runtime·sched);
+ if(m != nil)
+ runtime·notewakeup(&m->havenextg);
+}
+
// Called after main·init_function; main·main will be called on return.
void
runtime·initdone(void)
// If main·init_function started other goroutines,
// kick off new ms to handle them, like ready
// would have, had it not been pre-dawn.
- runtime·lock(&runtime·sched);
+ schedlock();
matchmg();
- runtime·unlock(&runtime·sched);
+ schedunlock();
}
void
void
runtime·ready(G *g)
{
- runtime·lock(&runtime·sched);
+ schedlock();
readylocked(g);
- runtime·unlock(&runtime·sched);
+ schedunlock();
}
// Mark g ready to run. Sched is already locked.
m->nextg = g;
if(m->waitnextg) {
m->waitnextg = 0;
- runtime·notewakeup(&m->havenextg);
+ if(mwakeup != nil)
+ runtime·notewakeup(&mwakeup->havenextg);
+ mwakeup = m;
}
}
if(m->nextg != nil) {
gp = m->nextg;
m->nextg = nil;
- runtime·unlock(&runtime·sched);
+ schedunlock();
return gp;
}
continue;
}
runtime·sched.mcpu++; // this m will run gp
- runtime·unlock(&runtime·sched);
+ schedunlock();
return gp;
}
// Otherwise, wait on global m queue.
runtime·sched.waitstop = 0;
runtime·notewakeup(&runtime·sched.stopped);
}
- runtime·unlock(&runtime·sched);
+ schedunlock();
runtime·notesleep(&m->havenextg);
if((gp = m->nextg) == nil)
void
runtime·stoptheworld(void)
{
- runtime·lock(&runtime·sched);
+ schedlock();
runtime·gcwaiting = 1;
runtime·sched.mcpumax = 1;
while(runtime·sched.mcpu > 1) {
// so this is okay.
runtime·noteclear(&runtime·sched.stopped);
runtime·sched.waitstop = 1;
- runtime·unlock(&runtime·sched);
+ schedunlock();
runtime·notesleep(&runtime·sched.stopped);
- runtime·lock(&runtime·sched);
+ schedlock();
}
- runtime·unlock(&runtime·sched);
+ schedunlock();
}
// TODO(rsc): Remove. This is only temporary,
void
runtime·starttheworld(void)
{
- runtime·lock(&runtime·sched);
+ schedlock();
runtime·gcwaiting = 0;
runtime·sched.mcpumax = runtime·gomaxprocs;
matchmg();
- runtime·unlock(&runtime·sched);
+ schedunlock();
}
// Called to start an M.
static void
schedule(G *gp)
{
- runtime·lock(&runtime·sched);
+ schedlock();
if(gp != nil) {
if(runtime·sched.predawn)
runtime·throw("init rescheduling");
runtime·gosave(&g->sched);
if(runtime·sched.predawn)
return;
- runtime·lock(&runtime·sched);
+ schedlock();
g->status = Gsyscall;
runtime·sched.mcpu--;
runtime·sched.msyscall++;
runtime·sched.waitstop = 0;
runtime·notewakeup(&runtime·sched.stopped);
}
- runtime·unlock(&runtime·sched);
+ schedunlock();
}
// The goroutine g exited its system call.
if(runtime·sched.predawn)
return;
- runtime·lock(&runtime·sched);
+ schedlock();
runtime·sched.msyscall--;
runtime·sched.mcpu++;
// Fast path - if there's room for this m, we're done.
if(runtime·sched.mcpu <= runtime·sched.mcpumax) {
g->status = Grunning;
- runtime·unlock(&runtime·sched);
+ schedunlock();
return;
}
// Tell scheduler to put g back on the run queue:
// but keeps the garbage collector from thinking
// that g is running right now, which it's not.
g->readyonstop = 1;
- runtime·unlock(&runtime·sched);
+ schedunlock();
// Slow path - all the cpus are taken.
// The scheduler will ready g and put this m to sleep.
if(siz > 1024)
runtime·throw("runtime.newproc: too many args");
- runtime·lock(&runtime·sched);
+ schedlock();
if((newg = gfget()) != nil){
newg->status = Gwaiting;
newg->goid = runtime·goidgen;
newprocreadylocked(newg);
- runtime·unlock(&runtime·sched);
+ schedunlock();
return newg;
//printf(" goid=%d\n", newg->goid);
{
int32 ret;
- runtime·lock(&runtime·sched);
+ schedlock();
ret = runtime·gomaxprocs;
if (n <= 0)
n = ret;
runtime·sched.mcpumax = n;
// handle fewer procs?
if(runtime·sched.mcpu > runtime·sched.mcpumax) {
- runtime·unlock(&runtime·sched);
+ schedunlock();
// just give up the cpu.
// we'll only get rescheduled once the
// number has come down.
}
// handle more procs
matchmg();
- runtime·unlock(&runtime·sched);
+ schedunlock();
return ret;
}