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);
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
}
}
+static void
+mhelpgc(void)
+{
+ m->helpgc = 1;
+}
+
void
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);
}
}
if(runtime·iscgo)
runtime·newextram();
}
+
+ if(m->mstartfn)
+ m->mstartfn();
if(m->helpgc) {
m->helpgc = false;
}
-// 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;
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.
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) {
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)
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(;;) {
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*);
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)
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)
// 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)
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
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
}
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) {
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);
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(¶m, sizeof param);
runtime·sigprocmask(&oset, nil);
};
void
-runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
+runtime·newosproc(M *mp, void *stk)
{
int32 ret;
int32 flags;
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) {
}
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
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);
}
void
-runtime·newosproc(M *mp, G *gp, void *stk, void (*fn)(void))
+runtime·newosproc(M *mp, void *stk)
{
Tfork param;
Sigset oset;
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
param.tf_stack = stk;
oset = runtime·sigprocmask(SIG_SETMASK, sigset_all);
- ret = runtime·tfork((byte*)¶m, sizeof(param), mp, gp, fn);
+ ret = runtime·tfork((byte*)¶m, sizeof(param), mp, mp->g0, runtime·mstart);
runtime·sigprocmask(SIG_SETMASK, oset);
if(ret < 0) {
}
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");
}
#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);