Commit e6a3e22c authored by Russ Cox's avatar Russ Cox

runtime: start all threads with runtime.mstart

Putting the M initialization in multiple places will not scale.
Various code assumes mstart is the start already. Make it so.

R=golang-dev, devon.odell
CC=golang-dev
https://golang.org/cl/7420048
parent d0d7416d
......@@ -84,7 +84,7 @@ static void schedule(void);
static void procresize(int32);
static void acquirep(P*);
static P* releasep(void);
static void newm(void(*)(void), P*, bool, bool);
static void newm(void(*)(void), P*);
static void goidle(void);
static void stopm(void);
static void startm(P*, bool);
......@@ -161,7 +161,7 @@ static FuncVal scavenger = {runtime·MHeap_Scavenger};
void
runtime·main(void)
{
newm(sysmon, nil, false, false);
newm(sysmon, nil);
// Lock the main goroutine onto this, the main OS thread,
// during initialization. Most programs won't care, but a few
......@@ -381,6 +381,12 @@ runtime·stoptheworld(void)
}
}
static void
mhelpgc(void)
{
m->helpgc = 1;
}
void
runtime·starttheworld(void)
{
......@@ -428,7 +434,7 @@ runtime·starttheworld(void)
// 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.
newm(runtime·mstart, nil, true, false);
newm(mhelpgc, nil);
}
}
......@@ -460,6 +466,9 @@ runtime·mstart(void)
if(runtime·iscgo)
runtime·newextram();
}
if(m->mstartfn)
m->mstartfn();
if(m->helpgc) {
m->helpgc = false;
......@@ -726,16 +735,15 @@ unlockextra(M *mp)
}
// Create a new m. It will start off with a call to fn.
// Create a new m. It will start off with a call to fn, or else the scheduler.
static void
newm(void(*fn)(void), P *p, bool helpgc, bool spinning)
newm(void(*fn)(void), P *p)
{
M *mp;
mp = runtime·allocm(p);
mp->nextp = p;
mp->helpgc = helpgc;
mp->spinning = spinning;
mp->mstartfn = fn;
if(runtime·iscgo) {
CgoThreadStart ts;
......@@ -744,11 +752,11 @@ newm(void(*fn)(void), P *p, bool helpgc, bool spinning)
runtime·throw("_cgo_thread_start missing");
ts.m = mp;
ts.g = mp->g0;
ts.fn = fn;
ts.fn = runtime·mstart;
runtime·asmcgocall(_cgo_thread_start, &ts);
return;
}
runtime·newosproc(mp, mp->g0, (byte*)mp->g0->stackbase, fn);
runtime·newosproc(mp, (byte*)mp->g0->stackbase);
}
// Stops execution of the current m until new work is available.
......@@ -781,12 +789,19 @@ retry:
m->nextp = nil;
}
static void
mspinning(void)
{
m->spinning = true;
}
// Schedules some M to run the p (creates an M if necessary).
// If p==nil, tries to get an idle P, if no idle P's returns false.
static void
startm(P *p, bool spinning)
{
M *mp;
void (*fn)(void);
runtime·lock(&runtime·sched);
if(p == nil) {
......@@ -801,7 +816,10 @@ startm(P *p, bool spinning)
mp = mget();
runtime·unlock(&runtime·sched);
if(mp == nil) {
newm(runtime·mstart, p, false, spinning);
fn = nil;
if(spinning)
fn = mspinning;
newm(fn, p);
return;
}
if(mp->spinning)
......@@ -1887,11 +1905,6 @@ sysmon(void)
uint32 idle, delay;
uint32 ticks[MaxGomaxprocs];
// This is a special dedicated thread that retakes P's from blocking syscalls.
// It works w/o mcache nor stackalloc, it may work concurrently with GC.
runtime·asminit();
runtime·minit();
idle = 0; // how many cycles in succession we had not wokeup somebody
delay = 0;
for(;;) {
......
......@@ -702,7 +702,8 @@ void runtime·exit1(int32);
void runtime·ready(G*);
byte* runtime·getenv(int8*);
int32 runtime·atoi(byte*);
void runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void));
void runtime·newosproc(M *mp, void *stk);
void runtime·mstart(void);
G* runtime·malg(int32);
void runtime·asminit(void);
void runtime·mpreinit(M*);
......
......@@ -38,12 +38,7 @@ TEXT runtime·thr_start(SB),7,$0
MOVL AX, m(CX)
CALL runtime·stackcheck(SB) // smashes AX
// newosproc left the function we should call in mp->mstartfn.
get_tls(CX)
MOVL m(CX), AX
MOVL m_mstartfn(AX), AX
CALL AX
CALL runtime·mstart(SB)
MOVL 0, AX // crash (not reached)
......
......@@ -38,13 +38,8 @@ TEXT runtime·thr_start(SB),7,$0
MOVQ m_g0(R13), DI
MOVQ DI, g(CX)
CALL runtime·stackcheck(SB)
// newosproc left the function we should call in mp->mstartfn.
get_tls(CX)
MOVQ m(CX), AX
MOVQ m_mstartfn(AX), AX
CALL AX
CALL runtime·stackcheck(SB)
CALL runtime·mstart(SB)
MOVQ 0, AX // crash (not reached)
......
......@@ -33,10 +33,7 @@ TEXT runtime·thr_start(SB),7,$0
// set up g
MOVW m_g0(R9), R10
BL runtime·emptyfunc(SB) // fault if stack check is wrong
// newosproc left the function we should call in mp->tls[2] for us.
MOVW (m_tls+8)(m), R0
BL (R0)
BL runtime·mstart(SB)
MOVW $2, R9 // crash (not reached)
MOVW R9, (R9)
......
......@@ -259,12 +259,7 @@ TEXT runtime·tstart(SB),7,$0
CLD
CALL runtime·stackcheck(SB) // clobbers AX,CX
// newosproc left the function we should call in mp->mstartfn.
get_tls(CX)
MOVL m(CX), AX
MOVL m_mstartfn(AX), AX
CALL AX
CALL runtime·mstart(SB)
RET
......
......@@ -329,11 +329,7 @@ TEXT runtime·tstart_stdcall(SB),7,$0
CLD
CALL runtime·stackcheck(SB) // clobbers AX,CX
get_tls(CX)
MOVQ m(CX), AX
MOVQ m_mstartfn(AX), AX
CALL AX
CALL runtime·mstart(SB)
XORL AX, AX // return 0 == success
RET
......
......@@ -87,19 +87,19 @@ runtime·goenvs(void)
}
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
int32 errno;
Sigset oset;
mp->tls[0] = mp->id; // so 386 asm can find it
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, mp->id, (int32)mp->tls[0], &mp);
runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
}
runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
errno = runtime·bsdthread_create(stk, mp, gp, fn);
errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
runtime·sigprocmask(SIG_SETMASK, &oset, nil);
if(errno < 0) {
......
......@@ -77,18 +77,14 @@ runtime·futexwakeup(uint32 *addr, uint32 cnt)
void runtime·thr_start(void*);
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
ThrParam param;
Sigset oset;
// thr_start assumes gp == mp->g0
if(gp != mp->g0)
runtime·throw("invalid newosproc gp");
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, mp->id, (int32)mp->tls[0], &mp);
runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
}
runtime·sigprocmask(&sigset_all, &oset);
......@@ -96,15 +92,18 @@ runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
param.start_func = runtime·thr_start;
param.arg = (byte*)mp;
param.stack_base = (void*)gp->stackbase;
param.stack_size = (byte*)stk - (byte*)gp->stackbase;
// NOTE(rsc): This code is confused. stackbase is the top of the stack
// and is equal to stk. However, it's working, so I'm not changing it.
param.stack_base = (void*)mp->g0->stackbase;
param.stack_size = (byte*)stk - (byte*)mp->g0->stackbase;
param.child_tid = (intptr*)&mp->procid;
param.parent_tid = nil;
param.tls_base = (void*)&mp->tls[0];
param.tls_size = sizeof mp->tls;
mp->tls[0] = mp->id; // so 386 asm can find it
mp->mstartfn = fn;
runtime·thr_new(&param, sizeof param);
runtime·sigprocmask(&oset, nil);
......
......@@ -124,7 +124,7 @@ enum
};
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
int32 ret;
int32 flags;
......@@ -142,14 +142,14 @@ runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
mp->tls[0] = mp->id; // so 386 asm can find it
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p clone=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, runtime·clone, mp->id, (int32)mp->tls[0], &mp);
runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n",
stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp);
}
// Disable signals during clone, so that the new thread starts
// with signals disabled. It will enable them in minit.
runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset);
ret = runtime·clone(flags, stk, mp, gp, fn);
ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart);
runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset);
if(ret < 0) {
......
......@@ -145,15 +145,15 @@ runtime·semawakeup(M *mp)
}
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
UcontextT uc;
int32 ret;
if(0) {
runtime·printf(
"newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, mp->id, (int32)mp->tls[0], &mp);
"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
}
mp->tls[0] = mp->id; // so 386 asm can find it
......@@ -164,7 +164,7 @@ runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
uc.uc_link = nil;
uc.uc_sigmask = sigset_all;
runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, gp, fn);
runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
ret = runtime·lwp_create(&uc, 0, &mp->procid);
......
......@@ -123,7 +123,7 @@ runtime·semawakeup(M *mp)
}
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
Tfork param;
Sigset oset;
......@@ -132,7 +132,7 @@ runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
if(0) {
runtime·printf(
"newosproc stk=%p m=%p g=%p fn=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, mp->id, (int32)mp->tls[0], &mp);
stk, mp, mp->g0, fn, mp->id, (int32)mp->tls[0], &mp);
}
mp->tls[0] = mp->id; // so 386 asm can find it
......@@ -142,7 +142,7 @@ runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
param.tf_stack = stk;
oset = runtime·sigprocmask(SIG_SETMASK, sigset_all);
ret = runtime·tfork((byte*)&param, sizeof(param), mp, gp, fn);
ret = runtime·tfork((byte*)&param, sizeof(param), mp, mp->g0, runtime·mstart);
runtime·sigprocmask(SIG_SETMASK, oset);
if(ret < 0) {
......
......@@ -223,15 +223,15 @@ runtime·exit(int32 e)
}
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
mp->tls[0] = mp->id; // so 386 asm can find it
if(0){
runtime·printf("newosproc stk=%p m=%p g=%p fn=%p rfork=%p id=%d/%d ostk=%p\n",
stk, mp, gp, fn, runtime·rfork, mp->id, (int32)mp->tls[0], &mp);
stk, mp, mp->g0, fn, runtime·rfork, mp->id, (int32)mp->tls[0], &mp);
}
if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, gp, fn) < 0)
if(runtime·rfork(RFPROC|RFMEM|RFNOWAIT, stk, mp, mp->g0, runtime·mstart) < 0)
runtime·throw("newosproc: rfork failed");
}
......
......@@ -187,18 +187,12 @@ runtime·semacreate(void)
#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
void
runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
runtime·newosproc(M *mp, void *stk)
{
void *thandle;
USED(stk);
// assume gp == mp->g0
if(gp != mp->g0)
runtime·throw("invalid newosproc gp");
mp->mstartfn = fn;
thandle = runtime·stdcall(runtime·CreateThread, 6,
nil, (uintptr)0x20000, runtime·tstart_stdcall, mp,
STACK_SIZE_PARAM_IS_A_RESERVATION, nil);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment