diff options
Diffstat (limited to 'libgo/runtime/proc.c')
-rw-r--r-- | libgo/runtime/proc.c | 720 |
1 files changed, 374 insertions, 346 deletions
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index defb0a5..1ac03a4 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -19,7 +19,6 @@ #include "defs.h" #include "malloc.h" #include "go-type.h" -#include "go-defer.h" #ifdef USING_SPLIT_STACK @@ -62,7 +61,6 @@ static void gtraceback(G*); #endif static __thread G *g; -static __thread M *m; #ifndef SETCONTEXT_CLOBBERS_TLS @@ -179,14 +177,15 @@ M* runtime_m(void) __attribute__ ((noinline, no_split_stack)); M* runtime_m(void) { - return m; + if(g == nil) + return nil; + return g->m; } -// Set m and g. +// Set g. void -runtime_setmg(M* mp, G* gp) +runtime_setg(G* gp) { - m = mp; g = gp; } @@ -242,12 +241,12 @@ void runtime_gogo(G* newg) { #ifdef USING_SPLIT_STACK - __splitstack_setcontext(&newg->stack_context[0]); + __splitstack_setcontext(&newg->stackcontext[0]); #endif g = newg; newg->fromgogo = true; - fixcontext(&newg->context); - setcontext(&newg->context); + fixcontext((ucontext_t*)&newg->context[0]); + setcontext((ucontext_t*)&newg->context[0]); runtime_throw("gogo setcontext returned"); } @@ -266,37 +265,37 @@ runtime_mcall(void (*pfn)(G*)) // collector. __builtin_unwind_init(); - mp = m; gp = g; + mp = gp->m; if(gp == mp->g0) runtime_throw("runtime: mcall called on m->g0 stack"); if(gp != nil) { #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - gp->gcnext_sp = &pfn; + gp->gcnextsp = &pfn; #endif gp->fromgogo = false; - getcontext(&gp->context); + getcontext((ucontext_t*)&gp->context[0]); // When we return from getcontext, we may be running - // in a new thread. That means that m and g may have - // changed. They are global variables so we will - // reload them, but the addresses of m and g may be - // cached in our local stack frame, and those - // addresses may be wrong. Call functions to reload - // the values for this thread. - mp = runtime_m(); + // in a new thread. That means that g may have + // changed. It is a global variables so we will + // reload it, but the address of g may be cached in + // our local stack frame, and that address may be + // wrong. Call the function to reload the value for + // this thread. gp = runtime_g(); + mp = gp->m; if(gp->traceback != nil) gtraceback(gp); } if (gp == nil || !gp->fromgogo) { #ifdef USING_SPLIT_STACK - __splitstack_setcontext(&mp->g0->stack_context[0]); + __splitstack_setcontext(&mp->g0->stackcontext[0]); #endif mp->g0->entry = (byte*)pfn; mp->g0->param = gp; @@ -306,8 +305,8 @@ runtime_mcall(void (*pfn)(G*)) // the getcontext call just above. g = mp->g0; - fixcontext(&mp->g0->context); - setcontext(&mp->g0->context); + fixcontext((ucontext_t*)&mp->g0->context[0]); + setcontext((ucontext_t*)&mp->g0->context[0]); runtime_throw("runtime: mcall function returned"); } } @@ -360,10 +359,6 @@ struct Sched { enum { - // The max value of GOMAXPROCS. - // There are no fundamental restrictions on the value. - MaxGomaxprocs = 1<<8, - // Number of goroutine ids to grab from runtime_sched.goidgen to local per-P cache at once. // 16 seems to provide enough amortization, but other than that it's mostly arbitrary number. GoidCacheBatch = 16, @@ -442,6 +437,7 @@ bool runtime_isstarted; void runtime_schedinit(void) { + M *m; int32 n, procs; String s; const byte *p; @@ -481,11 +477,11 @@ runtime_schedinit(void) s = runtime_getenv("GOMAXPROCS"); p = s.str; if(p != nil && (n = runtime_atoi(p, s.len)) > 0) { - if(n > MaxGomaxprocs) - n = MaxGomaxprocs; + if(n > _MaxGomaxprocs) + n = _MaxGomaxprocs; procs = n; } - runtime_allp = runtime_malloc((MaxGomaxprocs+1)*sizeof(runtime_allp[0])); + runtime_allp = runtime_malloc((_MaxGomaxprocs+1)*sizeof(runtime_allp[0])); procresize(procs); // Can not enable GC until all roots are registered. @@ -583,17 +579,17 @@ runtime_main(void* dummy __attribute__((unused))) runtime_lockOSThread(); // Defer unlock so that runtime.Goexit during init does the unlock too. - d.__pfn = initDone; - d.__next = g->defer; - d.__arg = (void*)-1; - d.__panic = g->panic; - d.__retaddr = nil; - d.__makefunc_can_recover = 0; - d.__frame = &frame; - d.__special = true; - g->defer = &d; - - if(m != &runtime_m0) + d.pfn = (uintptr)(void*)initDone; + d.next = g->_defer; + d.arg = (void*)-1; + d._panic = g->_panic; + d.retaddr = 0; + d.makefunccanrecover = 0; + d.frame = &frame; + d.special = true; + g->_defer = &d; + + if(g->m != &runtime_m0) runtime_throw("runtime_main not on m0"); __go_go(runtime_MHeap_Scavenger, nil); @@ -605,9 +601,9 @@ runtime_main(void* dummy __attribute__((unused))) closechan(runtime_main_init_done); - if(g->defer != &d || d.__pfn != initDone) + if(g->_defer != &d || (void*)d.pfn != initDone) runtime_throw("runtime: bad defer entry after init"); - g->defer = d.__next; + g->_defer = d.next; runtime_unlockOSThread(); // For gccgo we have to wait until after main is initialized @@ -640,42 +636,42 @@ runtime_main(void* dummy __attribute__((unused))) void runtime_goroutineheader(G *gp) { - const char *status; + String status; int64 waitfor; - switch(gp->status) { - case Gidle: - status = "idle"; + switch(gp->atomicstatus) { + case _Gidle: + status = runtime_gostringnocopy((const byte*)"idle"); break; - case Grunnable: - status = "runnable"; + case _Grunnable: + status = runtime_gostringnocopy((const byte*)"runnable"); break; - case Grunning: - status = "running"; + case _Grunning: + status = runtime_gostringnocopy((const byte*)"running"); break; - case Gsyscall: - status = "syscall"; + case _Gsyscall: + status = runtime_gostringnocopy((const byte*)"syscall"); break; - case Gwaiting: - if(gp->waitreason) + case _Gwaiting: + if(gp->waitreason.len > 0) status = gp->waitreason; else - status = "waiting"; + status = runtime_gostringnocopy((const byte*)"waiting"); break; default: - status = "???"; + status = runtime_gostringnocopy((const byte*)"???"); break; } // approx time the G is blocked, in minutes waitfor = 0; - if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->waitsince != 0) + if((gp->atomicstatus == _Gwaiting || gp->atomicstatus == _Gsyscall) && gp->waitsince != 0) waitfor = (runtime_nanotime() - gp->waitsince) / (60LL*1000*1000*1000); if(waitfor < 1) - runtime_printf("goroutine %D [%s]:\n", gp->goid, status); + runtime_printf("goroutine %D [%S]:\n", gp->goid, status); else - runtime_printf("goroutine %D [%s, %D minutes]:\n", gp->goid, status, waitfor); + runtime_printf("goroutine %D [%S, %D minutes]:\n", gp->goid, status, waitfor); } void @@ -693,13 +689,6 @@ runtime_printcreatedby(G *g) } } -struct Traceback -{ - G* gp; - Location locbuf[TracebackMaxFrames]; - int32 c; -}; - void runtime_tracebackothers(G * volatile me) { @@ -712,15 +701,15 @@ runtime_tracebackothers(G * volatile me) traceback = runtime_gotraceback(nil); // Show the current goroutine first, if we haven't already. - if((gp = m->curg) != nil && gp != me) { + if((gp = g->m->curg) != nil && gp != me) { runtime_printf("\n"); runtime_goroutineheader(gp); gp->traceback = &tb; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&me->stack_context[0]); + __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext(&me->context); + getcontext((ucontext_t*)&me->context[0]); if(gp->traceback != nil) { runtime_gogo(gp); @@ -733,7 +722,7 @@ runtime_tracebackothers(G * volatile me) runtime_lock(&allglock); for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - if(gp == me || gp == m->curg || gp->status == Gdead) + if(gp == me || gp == g->m->curg || gp->atomicstatus == _Gdead) continue; if(gp->issystem && traceback < 2) continue; @@ -749,19 +738,19 @@ runtime_tracebackothers(G * volatile me) // This means that if g is running or in a syscall, we // can't reliably print a stack trace. FIXME. - if(gp->status == Grunning) { + if(gp->atomicstatus == _Grunning) { runtime_printf("\tgoroutine running on other thread; stack unavailable\n"); runtime_printcreatedby(gp); - } else if(gp->status == Gsyscall) { + } else if(gp->atomicstatus == _Gsyscall) { runtime_printf("\tgoroutine in C code; stack unavailable\n"); runtime_printcreatedby(gp); } else { gp->traceback = &tb; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&me->stack_context[0]); + __splitstack_getcontext(&me->stackcontext[0]); #endif - getcontext(&me->context); + getcontext((ucontext_t*)&me->context[0]); if(gp->traceback != nil) { runtime_gogo(gp); @@ -794,8 +783,12 @@ gtraceback(G* gp) traceback = gp->traceback; gp->traceback = nil; + if(gp->m != nil) + runtime_throw("gtraceback: m is not nil"); + gp->m = traceback->gp->m; traceback->c = runtime_callers(1, traceback->locbuf, sizeof traceback->locbuf / sizeof traceback->locbuf[0], false); + gp->m = nil; runtime_gogo(traceback->gp); } @@ -804,7 +797,7 @@ mcommoninit(M *mp) { // If there is no mcache runtime_callers() will crash, // and we are most likely in sysmon thread so the stack is senseless anyway. - if(m->mcache) + if(g->m->mcache) runtime_callers(1, mp->createstack, nelem(mp->createstack), false); mp->fastrand = 0x49f6428aUL + mp->id + runtime_cputicks(); @@ -828,16 +821,16 @@ void runtime_ready(G *gp) { // Mark runnable. - m->locks++; // disable preemption because it can be holding p in a local var - if(gp->status != Gwaiting) { - runtime_printf("goroutine %D has status %d\n", gp->goid, gp->status); - runtime_throw("bad g->status in ready"); + g->m->locks++; // disable preemption because it can be holding p in a local var + if(gp->atomicstatus != _Gwaiting) { + runtime_printf("goroutine %D has status %d\n", gp->goid, gp->atomicstatus); + runtime_throw("bad g->atomicstatus in ready"); } - gp->status = Grunnable; - runqput(m->p, gp); + gp->atomicstatus = _Grunnable; + runqput((P*)g->m->p, gp); if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0) // TODO: fast atomic wakep(); - m->locks--; + g->m->locks--; } int32 @@ -884,7 +877,7 @@ runtime_helpgc(int32 nproc) runtime_lock(&runtime_sched); pos = 0; for(n = 1; n < nproc; n++) { // one M is currently running - if(runtime_allp[pos]->mcache == m->mcache) + if(runtime_allp[pos]->mcache == g->m->mcache) pos++; mp = mget(); if(mp == nil) @@ -938,18 +931,18 @@ runtime_stoptheworld(void) runtime_atomicstore((uint32*)&runtime_sched.gcwaiting, 1); preemptall(); // stop current P - m->p->status = Pgcstop; + ((P*)g->m->p)->status = _Pgcstop; runtime_sched.stopwait--; - // try to retake all P's in Psyscall status + // try to retake all P's in _Psyscall status for(i = 0; i < runtime_gomaxprocs; i++) { p = runtime_allp[i]; s = p->status; - if(s == Psyscall && runtime_cas(&p->status, s, Pgcstop)) + if(s == _Psyscall && runtime_cas(&p->status, s, _Pgcstop)) runtime_sched.stopwait--; } // stop idle P's while((p = pidleget()) != nil) { - p->status = Pgcstop; + p->status = _Pgcstop; runtime_sched.stopwait--; } wait = runtime_sched.stopwait > 0; @@ -964,7 +957,7 @@ runtime_stoptheworld(void) runtime_throw("stoptheworld: not stopped"); for(i = 0; i < runtime_gomaxprocs; i++) { p = runtime_allp[i]; - if(p->status != Pgcstop) + if(p->status != _Pgcstop) runtime_throw("stoptheworld: not stopped"); } } @@ -972,7 +965,7 @@ runtime_stoptheworld(void) static void mhelpgc(void) { - m->helpgc = -1; + g->m->helpgc = -1; } void @@ -983,7 +976,7 @@ runtime_starttheworld(void) G *gp; bool add; - m->locks++; // disable preemption because it can be holding p in a local var + g->m->locks++; // disable preemption because it can be holding p in a local var gp = runtime_netpoll(false); // non-blocking injectglist(gp); add = needaddgcproc(); @@ -1003,8 +996,8 @@ runtime_starttheworld(void) pidleput(p); break; } - p->m = mget(); - p->link = p1; + p->m = (uintptr)mget(); + p->link = (uintptr)p1; p1 = p; } if(runtime_sched.sysmonwait) { @@ -1015,13 +1008,13 @@ runtime_starttheworld(void) while(p1) { p = p1; - p1 = p1->link; + p1 = (P*)p1->link; if(p->m) { - mp = p->m; - p->m = nil; + mp = (M*)p->m; + p->m = 0; if(mp->nextp) runtime_throw("starttheworld: inconsistent mp->nextp"); - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); } else { // Start M to run P. Do not start another M below. @@ -1040,15 +1033,18 @@ runtime_starttheworld(void) // the maximum number of procs. newm(mhelpgc, nil); } - m->locks--; + g->m->locks--; } // Called to start an M. void* runtime_mstart(void* mp) { + M *m; + m = (M*)mp; g = m->g0; + g->m = m; initcontext(); @@ -1059,15 +1055,15 @@ runtime_mstart(void* mp) // Once we call schedule we're never coming back, // so other calls can reuse this stack space. #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - g->gcinitial_sp = ∓ - // Setting gcstack_size to 0 is a marker meaning that gcinitial_sp + g->gcinitialsp = ∓ + // Setting gcstacksize to 0 is a marker meaning that gcinitialsp // is the top of the stack, not the bottom. - g->gcstack_size = 0; - g->gcnext_sp = ∓ + g->gcstacksize = 0; + g->gcnextsp = ∓ #endif - getcontext(&g->context); + getcontext((ucontext_t*)&g->context[0]); if(g->entry != nil) { // Got here from mcall. @@ -1097,14 +1093,14 @@ runtime_mstart(void* mp) } if(m->mstartfn) - m->mstartfn(); + ((void (*)(void))m->mstartfn)(); if(m->helpgc) { m->helpgc = 0; stopm(); } else if(m != &runtime_m0) { - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } schedule(); @@ -1127,12 +1123,12 @@ struct CgoThreadStart // Allocate a new m unassociated with any thread. // Can use p for allocation context if needed. M* -runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacksize) +runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, uintptr* ret_g0_stacksize) { M *mp; - m->locks++; // disable GC because it can be called from sysmon - if(m->p == nil) + g->m->locks++; // disable GC because it can be called from sysmon + if(g->m->p == 0) acquirep(p); // temporarily borrow p for mallocs in this function #if 0 if(mtype == nil) { @@ -1145,10 +1141,11 @@ runtime_allocm(P *p, int32 stacksize, byte** ret_g0_stack, size_t* ret_g0_stacks mp = runtime_mal(sizeof *mp); mcommoninit(mp); mp->g0 = runtime_malg(stacksize, ret_g0_stack, ret_g0_stacksize); + mp->g0->m = mp; - if(p == m->p) + if(p == (P*)g->m->p) releasep(); - m->locks--; + g->m->locks--; return mp; } @@ -1235,26 +1232,26 @@ runtime_needm(void) // after exitsyscall makes sure it is okay to be // running at all (that is, there's no garbage collection // running right now). - mp->needextram = mp->schedlink == nil; - unlockextra(mp->schedlink); + mp->needextram = mp->schedlink == 0; + unlockextra((M*)mp->schedlink); - // Install m and g (= m->curg). - runtime_setmg(mp, mp->curg); + // Install g (= m->curg). + runtime_setg(mp->curg); // Initialize g's context as in mstart. initcontext(); - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; g->entry = nil; g->param = nil; #ifdef USING_SPLIT_STACK - __splitstack_getcontext(&g->stack_context[0]); + __splitstack_getcontext(&g->stackcontext[0]); #else - g->gcinitial_sp = ∓ + g->gcinitialsp = ∓ g->gcstack = nil; - g->gcstack_size = 0; - g->gcnext_sp = ∓ + g->gcstacksize = 0; + g->gcnextsp = ∓ #endif - getcontext(&g->context); + getcontext((ucontext_t*)&g->context[0]); if(g->entry != nil) { // Got here from mcall. @@ -1284,7 +1281,7 @@ runtime_newextram(void) M *mp, *mnext; G *gp; byte *g0_sp, *sp; - size_t g0_spsize, spsize; + uintptr g0_spsize, spsize; // Create extra goroutine locked to extra m. // The goroutine is the context in which the cgo callback will run. @@ -1293,9 +1290,10 @@ runtime_newextram(void) // the goroutine stack ends. mp = runtime_allocm(nil, StackMin, &g0_sp, &g0_spsize); gp = runtime_malg(StackMin, &sp, &spsize); - gp->status = Gdead; + gp->atomicstatus = _Gdead; + gp->m = mp; mp->curg = gp; - mp->locked = LockInternal; + mp->locked = _LockInternal; mp->lockedg = gp; gp->lockedm = mp; gp->goid = runtime_xadd64(&runtime_sched.goidgen, 1); @@ -1304,14 +1302,14 @@ runtime_newextram(void) // The context for gp will be set up in runtime_needm. But // here we need to set up the context for g0. - getcontext(&mp->g0->context); - mp->g0->context.uc_stack.ss_sp = g0_sp; - mp->g0->context.uc_stack.ss_size = g0_spsize; - makecontext(&mp->g0->context, kickoff, 0); + getcontext((ucontext_t*)&mp->g0->context[0]); + ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_sp = g0_sp; + ((ucontext_t*)&mp->g0->context[0])->uc_stack.ss_size = (size_t)g0_spsize; + makecontext((ucontext_t*)&mp->g0->context[0], kickoff, 0); // Add m to the extra list. mnext = lockextra(true); - mp->schedlink = mnext; + mp->schedlink = (uintptr)mnext; unlockextra(mp); } @@ -1347,16 +1345,16 @@ runtime_dropm(void) runtime_unminit(); // Clear m and g, and return m to the extra list. - // After the call to setmg we can only call nosplit functions. - mp = m; - runtime_setmg(nil, nil); + // After the call to setg we can only call nosplit functions. + mp = g->m; + runtime_setg(nil); - mp->curg->status = Gdead; + mp->curg->atomicstatus = _Gdead; mp->curg->gcstack = nil; - mp->curg->gcnext_sp = nil; + mp->curg->gcnextsp = nil; mnext = lockextra(true); - mp->schedlink = mnext; + mp->schedlink = (uintptr)mnext; unlockextra(mp); } @@ -1417,7 +1415,7 @@ countextra() continue; } c = 0; - for(mc = mp; mc != nil; mc = mc->schedlink) + for(mc = mp; mc != nil; mc = (M*)mc->schedlink) c++; runtime_atomicstorep(&runtime_extram, mp); return c; @@ -1431,8 +1429,8 @@ newm(void(*fn)(void), P *p) M *mp; mp = runtime_allocm(p, -1, nil, nil); - mp->nextp = p; - mp->mstartfn = fn; + mp->nextp = (uintptr)p; + mp->mstartfn = (uintptr)(void*)fn; runtime_newosproc(mp); } @@ -1442,6 +1440,9 @@ newm(void(*fn)(void), P *p) static void stopm(void) { + M* m; + + m = g->m; if(m->locks) runtime_throw("stopm holding locks"); if(m->p) @@ -1456,6 +1457,7 @@ retry: mput(m); runtime_unlock(&runtime_sched); runtime_notesleep(&m->park); + m = g->m; runtime_noteclear(&m->park); if(m->helpgc) { runtime_gchelper(); @@ -1463,14 +1465,14 @@ retry: m->mcache = nil; goto retry; } - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } static void mspinning(void) { - m->spinning = true; + g->m->spinning = true; } // Schedules some M to run the p (creates an M if necessary). @@ -1505,7 +1507,7 @@ startm(P *p, bool spinning) if(mp->nextp) runtime_throw("startm: m has p"); mp->spinning = spinning; - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); } @@ -1527,7 +1529,7 @@ handoffp(P *p) } runtime_lock(&runtime_sched); if(runtime_sched.gcwaiting) { - p->status = Pgcstop; + p->status = _Pgcstop; if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); runtime_unlock(&runtime_sched); @@ -1565,8 +1567,10 @@ wakep(void) static void stoplockedm(void) { + M *m; P *p; + m = g->m; if(m->lockedg == nil || m->lockedg->lockedm != m) runtime_throw("stoplockedm: inconsistent locking"); if(m->p) { @@ -1577,11 +1581,12 @@ stoplockedm(void) incidlelocked(1); // Wait until another thread schedules lockedg again. runtime_notesleep(&m->park); + m = g->m; runtime_noteclear(&m->park); - if(m->lockedg->status != Grunnable) + if(m->lockedg->atomicstatus != _Grunnable) runtime_throw("stoplockedm: not runnable"); - acquirep(m->nextp); - m->nextp = nil; + acquirep((P*)m->nextp); + m->nextp = 0; } // Schedules the locked m to run the locked gp. @@ -1592,14 +1597,14 @@ startlockedm(G *gp) P *p; mp = gp->lockedm; - if(mp == m) + if(mp == g->m) runtime_throw("startlockedm: locked to me"); if(mp->nextp) runtime_throw("startlockedm: m has p"); // directly handoff current P to the locked m incidlelocked(-1); p = releasep(); - mp->nextp = p; + mp->nextp = (uintptr)p; runtime_notewakeup(&mp->park); stopm(); } @@ -1613,13 +1618,13 @@ gcstopm(void) if(!runtime_sched.gcwaiting) runtime_throw("gcstopm: not waiting for gc"); - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; runtime_xadd(&runtime_sched.nmspinning, -1); } p = releasep(); runtime_lock(&runtime_sched); - p->status = Pgcstop; + p->status = _Pgcstop; if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); runtime_unlock(&runtime_sched); @@ -1633,19 +1638,19 @@ execute(G *gp) { int32 hz; - if(gp->status != Grunnable) { - runtime_printf("execute: bad g status %d\n", gp->status); + if(gp->atomicstatus != _Grunnable) { + runtime_printf("execute: bad g status %d\n", gp->atomicstatus); runtime_throw("execute: bad g status"); } - gp->status = Grunning; + gp->atomicstatus = _Grunning; gp->waitsince = 0; - m->p->schedtick++; - m->curg = gp; - gp->m = m; + ((P*)g->m->p)->schedtick++; + g->m->curg = gp; + gp->m = g->m; // Check whether the profiler needs to be turned on or off. hz = runtime_sched.profilehz; - if(m->profilehz != hz) + if(g->m->profilehz != hz) runtime_resetcpuprofiler(hz); runtime_gogo(gp); @@ -1668,13 +1673,13 @@ top: if(runtime_fingwait && runtime_fingwake && (gp = runtime_wakefing()) != nil) runtime_ready(gp); // local runq - gp = runqget(m->p); + gp = runqget((P*)g->m->p); if(gp) return gp; // global runq if(runtime_sched.runqsize) { runtime_lock(&runtime_sched); - gp = globrunqget(m->p, 0); + gp = globrunqget((P*)g->m->p, 0); runtime_unlock(&runtime_sched); if(gp) return gp; @@ -1682,17 +1687,17 @@ top: // poll network gp = runtime_netpoll(false); // non-blocking if(gp) { - injectglist(gp->schedlink); - gp->status = Grunnable; + injectglist((G*)gp->schedlink); + gp->atomicstatus = _Grunnable; return gp; } // If number of spinning M's >= number of busy P's, block. // This is necessary to prevent excessive CPU consumption // when GOMAXPROCS>>1 but the program parallelism is low. - if(!m->spinning && 2 * runtime_atomicload(&runtime_sched.nmspinning) >= runtime_gomaxprocs - runtime_atomicload(&runtime_sched.npidle)) // TODO: fast atomic + if(!g->m->spinning && 2 * runtime_atomicload(&runtime_sched.nmspinning) >= runtime_gomaxprocs - runtime_atomicload(&runtime_sched.npidle)) // TODO: fast atomic goto stop; - if(!m->spinning) { - m->spinning = true; + if(!g->m->spinning) { + g->m->spinning = true; runtime_xadd(&runtime_sched.nmspinning, 1); } // random steal from other P's @@ -1700,10 +1705,10 @@ top: if(runtime_sched.gcwaiting) goto top; p = runtime_allp[runtime_fastrand1()%runtime_gomaxprocs]; - if(p == m->p) + if(p == (P*)g->m->p) gp = runqget(p); else - gp = runqsteal(m->p, p); + gp = runqsteal((P*)g->m->p, p); if(gp) return gp; } @@ -1715,15 +1720,15 @@ stop: goto top; } if(runtime_sched.runqsize) { - gp = globrunqget(m->p, 0); + gp = globrunqget((P*)g->m->p, 0); runtime_unlock(&runtime_sched); return gp; } p = releasep(); pidleput(p); runtime_unlock(&runtime_sched); - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; runtime_xadd(&runtime_sched.nmspinning, -1); } // check all runqueues once again @@ -1742,9 +1747,9 @@ stop: } // poll network if(runtime_xchg64(&runtime_sched.lastpoll, 0) != 0) { - if(m->p) + if(g->m->p) runtime_throw("findrunnable: netpoll with p"); - if(m->spinning) + if(g->m->spinning) runtime_throw("findrunnable: netpoll with spinning"); gp = runtime_netpoll(true); // block until new work is available runtime_atomicstore64(&runtime_sched.lastpoll, runtime_nanotime()); @@ -1754,8 +1759,8 @@ stop: runtime_unlock(&runtime_sched); if(p) { acquirep(p); - injectglist(gp->schedlink); - gp->status = Grunnable; + injectglist((G*)gp->schedlink); + gp->atomicstatus = _Grunnable; return gp; } injectglist(gp); @@ -1770,8 +1775,8 @@ resetspinning(void) { int32 nmspinning; - if(m->spinning) { - m->spinning = false; + if(g->m->spinning) { + g->m->spinning = false; nmspinning = runtime_xadd(&runtime_sched.nmspinning, -1); if(nmspinning < 0) runtime_throw("findrunnable: negative nmspinning"); @@ -1797,8 +1802,8 @@ injectglist(G *glist) runtime_lock(&runtime_sched); for(n = 0; glist; n++) { gp = glist; - glist = gp->schedlink; - gp->status = Grunnable; + glist = (G*)gp->schedlink; + gp->atomicstatus = _Grunnable; globrunqput(gp); } runtime_unlock(&runtime_sched); @@ -1815,7 +1820,7 @@ schedule(void) G *gp; uint32 tick; - if(m->locks) + if(g->m->locks) runtime_throw("schedule: holding locks"); top: @@ -1828,19 +1833,19 @@ top: // Check the global runnable queue once in a while to ensure fairness. // Otherwise two goroutines can completely occupy the local runqueue // by constantly respawning each other. - tick = m->p->schedtick; + tick = ((P*)g->m->p)->schedtick; // This is a fancy way to say tick%61==0, // it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors. if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime_sched.runqsize > 0) { runtime_lock(&runtime_sched); - gp = globrunqget(m->p, 1); + gp = globrunqget((P*)g->m->p, 1); runtime_unlock(&runtime_sched); if(gp) resetspinning(); } if(gp == nil) { - gp = runqget(m->p); - if(gp && m->spinning) + gp = runqget((P*)g->m->p); + if(gp && g->m->spinning) runtime_throw("schedule: spinning with local work"); } if(gp == nil) { @@ -1863,11 +1868,11 @@ top: void runtime_park(bool(*unlockf)(G*, void*), void *lock, const char *reason) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); - m->waitlock = lock; - m->waitunlockf = unlockf; - g->waitreason = reason; + g->m->waitlock = lock; + g->m->waitunlockf = unlockf; + g->waitreason = runtime_gostringnocopy((const byte*)reason); runtime_mcall(park0); } @@ -1891,17 +1896,19 @@ runtime_parkunlock(Lock *lock, const char *reason) static void park0(G *gp) { + M *m; bool ok; - gp->status = Gwaiting; + m = g->m; + gp->atomicstatus = _Gwaiting; gp->m = nil; m->curg = nil; if(m->waitunlockf) { - ok = m->waitunlockf(gp, m->waitlock); + ok = ((bool (*)(G*, void*))m->waitunlockf)(gp, m->waitlock); m->waitunlockf = nil; m->waitlock = nil; if(!ok) { - gp->status = Grunnable; + gp->atomicstatus = _Grunnable; execute(gp); // Schedule it back, never returns. } } @@ -1916,7 +1923,7 @@ park0(G *gp) void runtime_gosched(void) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); runtime_mcall(runtime_gosched0); } @@ -1925,7 +1932,10 @@ runtime_gosched(void) void runtime_gosched0(G *gp) { - gp->status = Grunnable; + M *m; + + m = g->m; + gp->atomicstatus = _Grunnable; gp->m = nil; m->curg = nil; runtime_lock(&runtime_sched); @@ -1946,7 +1956,7 @@ void runtime_goexit(void) __attribute__ ((noinline)); void runtime_goexit(void) { - if(g->status != Grunning) + if(g->atomicstatus != _Grunning) runtime_throw("bad g status"); runtime_mcall(goexit0); } @@ -1955,25 +1965,28 @@ runtime_goexit(void) static void goexit0(G *gp) { - gp->status = Gdead; + M *m; + + m = g->m; + gp->atomicstatus = _Gdead; gp->entry = nil; gp->m = nil; gp->lockedm = nil; gp->paniconfault = 0; - gp->defer = nil; // should be true already but just in case. - gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data. + gp->_defer = nil; // should be true already but just in case. + gp->_panic = nil; // non-nil for Goexit during panic. points at stack-allocated data. gp->writenbuf = 0; gp->writebuf = nil; - gp->waitreason = nil; + gp->waitreason = runtime_gostringnocopy(nil); gp->param = nil; m->curg = nil; m->lockedg = nil; - if(m->locked & ~LockExternal) { + if(m->locked & ~_LockExternal) { runtime_printf("invalid m->locked = %d\n", m->locked); runtime_throw("internal lockOSThread error"); } m->locked = 0; - gfput(m->p, gp); + gfput((P*)m->p, gp); schedule(); } @@ -1994,7 +2007,7 @@ runtime_entersyscall() { // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext(&g->gcregs); + getcontext((ucontext_t*)&g->gcregs[0]); // Do the work in a separate function, so that this function // doesn't save any registers on its own stack. If this @@ -2011,24 +2024,24 @@ runtime_entersyscall() static void doentersyscall() { - // Disable preemption because during this function g is in Gsyscall status, + // Disable preemption because during this function g is in _Gsyscall status, // but can have inconsistent g->sched, do not let GC observe it. - m->locks++; + g->m->locks++; // Leave SP around for GC and traceback. #ifdef USING_SPLIT_STACK - g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size, - &g->gcnext_segment, &g->gcnext_sp, - &g->gcinitial_sp); + g->gcstack = __splitstack_find(nil, nil, &g->gcstacksize, + &g->gcnextsegment, &g->gcnextsp, + &g->gcinitialsp); #else { void *v; - g->gcnext_sp = (byte *) &v; + g->gcnextsp = (byte *) &v; } #endif - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; if(runtime_atomicload(&runtime_sched.sysmonwait)) { // TODO: fast atomic runtime_lock(&runtime_sched); @@ -2039,19 +2052,19 @@ doentersyscall() runtime_unlock(&runtime_sched); } - m->mcache = nil; - m->p->m = nil; - runtime_atomicstore(&m->p->status, Psyscall); + g->m->mcache = nil; + ((P*)(g->m->p))->m = 0; + runtime_atomicstore(&((P*)g->m->p)->status, _Psyscall); if(runtime_atomicload(&runtime_sched.gcwaiting)) { runtime_lock(&runtime_sched); - if (runtime_sched.stopwait > 0 && runtime_cas(&m->p->status, Psyscall, Pgcstop)) { + if (runtime_sched.stopwait > 0 && runtime_cas(&((P*)g->m->p)->status, _Psyscall, _Pgcstop)) { if(--runtime_sched.stopwait == 0) runtime_notewakeup(&runtime_sched.stopnote); } runtime_unlock(&runtime_sched); } - m->locks--; + g->m->locks--; } // The same as runtime_entersyscall(), but with a hint that the syscall is blocking. @@ -2060,29 +2073,29 @@ runtime_entersyscallblock(void) { P *p; - m->locks++; // see comment in entersyscall + g->m->locks++; // see comment in entersyscall // Leave SP around for GC and traceback. #ifdef USING_SPLIT_STACK - g->gcstack = __splitstack_find(nil, nil, &g->gcstack_size, - &g->gcnext_segment, &g->gcnext_sp, - &g->gcinitial_sp); + g->gcstack = __splitstack_find(nil, nil, &g->gcstacksize, + &g->gcnextsegment, &g->gcnextsp, + &g->gcinitialsp); #else - g->gcnext_sp = (byte *) &p; + g->gcnextsp = (byte *) &p; #endif // Save the registers in the g structure so that any pointers // held in registers will be seen by the garbage collector. - getcontext(&g->gcregs); + getcontext((ucontext_t*)&g->gcregs[0]); - g->status = Gsyscall; + g->atomicstatus = _Gsyscall; p = releasep(); handoffp(p); if(g->isbackground) // do not consider blocked scavenger for deadlock detection incidlelocked(1); - m->locks--; + g->m->locks--; } // The goroutine g exited its system call. @@ -2094,29 +2107,29 @@ runtime_exitsyscall(void) { G *gp; - m->locks++; // see comment in entersyscall - gp = g; + gp->m->locks++; // see comment in entersyscall + if(gp->isbackground) // do not consider blocked scavenger for deadlock detection incidlelocked(-1); - g->waitsince = 0; + gp->waitsince = 0; if(exitsyscallfast()) { // There's a cpu for us, so we can run. - m->p->syscalltick++; - gp->status = Grunning; + ((P*)gp->m->p)->syscalltick++; + gp->atomicstatus = _Grunning; // Garbage collector isn't running (since we are), // so okay to clear gcstack and gcsp. #ifdef USING_SPLIT_STACK gp->gcstack = nil; #endif - gp->gcnext_sp = nil; - runtime_memclr(&gp->gcregs, sizeof gp->gcregs); - m->locks--; + gp->gcnextsp = nil; + runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs); + gp->m->locks--; return; } - m->locks--; + gp->m->locks--; // Call the scheduler. runtime_mcall(exitsyscall0); @@ -2130,34 +2143,37 @@ runtime_exitsyscall(void) #ifdef USING_SPLIT_STACK gp->gcstack = nil; #endif - gp->gcnext_sp = nil; - runtime_memclr(&gp->gcregs, sizeof gp->gcregs); + gp->gcnextsp = nil; + runtime_memclr(&gp->gcregs[0], sizeof gp->gcregs); - // Don't refer to m again, we might be running on a different - // thread after returning from runtime_mcall. - runtime_m()->p->syscalltick++; + // Note that this gp->m might be different than the earlier + // gp->m after returning from runtime_mcall. + ((P*)gp->m->p)->syscalltick++; } static bool exitsyscallfast(void) { + G *gp; P *p; + gp = g; + // Freezetheworld sets stopwait but does not retake P's. if(runtime_sched.stopwait) { - m->p = nil; + gp->m->p = 0; return false; } // Try to re-acquire the last P. - if(m->p && m->p->status == Psyscall && runtime_cas(&m->p->status, Psyscall, Prunning)) { + if(gp->m->p && ((P*)gp->m->p)->status == _Psyscall && runtime_cas(&((P*)gp->m->p)->status, _Psyscall, _Prunning)) { // There's a cpu for us, so we can run. - m->mcache = m->p->mcache; - m->p->m = m; + gp->m->mcache = ((P*)gp->m->p)->mcache; + ((P*)gp->m->p)->m = (uintptr)gp->m; return true; } // Try to get any other idle P. - m->p = nil; + gp->m->p = 0; if(runtime_sched.pidle) { runtime_lock(&runtime_sched); p = pidleget(); @@ -2179,9 +2195,11 @@ exitsyscallfast(void) static void exitsyscall0(G *gp) { + M *m; P *p; - gp->status = Grunnable; + m = g->m; + gp->atomicstatus = _Grunnable; gp->m = nil; m->curg = nil; runtime_lock(&runtime_sched); @@ -2235,7 +2253,7 @@ syscall_runtime_AfterFork(void) // Allocate a new g, with a stack big enough for stacksize bytes. G* -runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) +runtime_malg(int32 stacksize, byte** ret_stack, uintptr* ret_stacksize) { G *newg; @@ -2243,11 +2261,13 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) if(stacksize >= 0) { #if USING_SPLIT_STACK int dont_block_signals = 0; + size_t ss_stacksize; *ret_stack = __splitstack_makecontext(stacksize, - &newg->stack_context[0], - ret_stacksize); - __splitstack_block_signals_context(&newg->stack_context[0], + &newg->stackcontext[0], + &ss_stacksize); + *ret_stacksize = (uintptr)ss_stacksize; + __splitstack_block_signals_context(&newg->stackcontext[0], &dont_block_signals, nil); #else // In 64-bit mode, the maximum Go allocation space is @@ -2265,9 +2285,9 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) *ret_stack = runtime_mallocgc(stacksize, 0, FlagNoProfiling|FlagNoGC); runtime_xadd(&runtime_stacks_sys, stacksize); } - *ret_stacksize = stacksize; - newg->gcinitial_sp = *ret_stack; - newg->gcstack_size = (size_t)stacksize; + *ret_stacksize = (uintptr)stacksize; + newg->gcinitialsp = *ret_stack; + newg->gcstacksize = (uintptr)stacksize; #endif } return newg; @@ -2310,36 +2330,39 @@ __go_go(void (*fn)(void*), void* arg) //runtime_printf("newproc1 %p %p narg=%d nret=%d\n", fn->fn, argp, narg, nret); if(fn == nil) { - m->throwing = -1; // do not dump full stacks + g->m->throwing = -1; // do not dump full stacks runtime_throw("go of nil func value"); } - m->locks++; // disable preemption because it can be holding p in a local var + g->m->locks++; // disable preemption because it can be holding p in a local var - p = m->p; + p = (P*)g->m->p; if((newg = gfget(p)) != nil) { #ifdef USING_SPLIT_STACK int dont_block_signals = 0; - sp = __splitstack_resetcontext(&newg->stack_context[0], + sp = __splitstack_resetcontext(&newg->stackcontext[0], &spsize); - __splitstack_block_signals_context(&newg->stack_context[0], + __splitstack_block_signals_context(&newg->stackcontext[0], &dont_block_signals, nil); #else - sp = newg->gcinitial_sp; - spsize = newg->gcstack_size; + sp = newg->gcinitialsp; + spsize = newg->gcstacksize; if(spsize == 0) runtime_throw("bad spsize in __go_go"); - newg->gcnext_sp = sp; + newg->gcnextsp = sp; #endif } else { - newg = runtime_malg(StackMin, &sp, &spsize); + uintptr malsize; + + newg = runtime_malg(StackMin, &sp, &malsize); + spsize = (size_t)malsize; allgadd(newg); } newg->entry = (byte*)fn; newg->param = arg; newg->gopc = (uintptr)__builtin_return_address(0); - newg->status = Grunnable; + newg->atomicstatus = _Grunnable; if(p->goidcache == p->goidcacheend) { p->goidcache = runtime_xadd64(&runtime_sched.goidgen, GoidCacheBatch); p->goidcacheend = p->goidcache + GoidCacheBatch; @@ -2353,19 +2376,19 @@ __go_go(void (*fn)(void*), void* arg) size_t volatile vspsize = spsize; G * volatile vnewg = newg; - getcontext(&vnewg->context); - vnewg->context.uc_stack.ss_sp = vsp; + getcontext((ucontext_t*)&vnewg->context[0]); + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp = vsp; #ifdef MAKECONTEXT_STACK_TOP - vnewg->context.uc_stack.ss_sp += vspsize; + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_sp += vspsize; #endif - vnewg->context.uc_stack.ss_size = vspsize; - makecontext(&vnewg->context, kickoff, 0); + ((ucontext_t*)&vnewg->context[0])->uc_stack.ss_size = vspsize; + makecontext((ucontext_t*)&vnewg->context[0], kickoff, 0); runqput(p, vnewg); if(runtime_atomicload(&runtime_sched.npidle) != 0 && runtime_atomicload(&runtime_sched.nmspinning) == 0 && fn != runtime_main) // TODO: fast atomic wakep(); - m->locks--; + g->m->locks--; return vnewg; } } @@ -2400,7 +2423,7 @@ allgadd(G *gp) static void gfput(P *p, G *gp) { - gp->schedlink = p->gfree; + gp->schedlink = (uintptr)p->gfree; p->gfree = gp; p->gfreecnt++; if(p->gfreecnt >= 64) { @@ -2408,8 +2431,8 @@ gfput(P *p, G *gp) while(p->gfreecnt >= 32) { p->gfreecnt--; gp = p->gfree; - p->gfree = gp->schedlink; - gp->schedlink = runtime_sched.gfree; + p->gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)runtime_sched.gfree; runtime_sched.gfree = gp; } runtime_unlock(&runtime_sched.gflock); @@ -2430,15 +2453,15 @@ retry: while(p->gfreecnt < 32 && runtime_sched.gfree) { p->gfreecnt++; gp = runtime_sched.gfree; - runtime_sched.gfree = gp->schedlink; - gp->schedlink = p->gfree; + runtime_sched.gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)p->gfree; p->gfree = gp; } runtime_unlock(&runtime_sched.gflock); goto retry; } if(gp) { - p->gfree = gp->schedlink; + p->gfree = (G*)gp->schedlink; p->gfreecnt--; } return gp; @@ -2454,8 +2477,8 @@ gfpurge(P *p) while(p->gfreecnt) { p->gfreecnt--; gp = p->gfree; - p->gfree = gp->schedlink; - gp->schedlink = runtime_sched.gfree; + p->gfree = (G*)gp->schedlink; + gp->schedlink = (uintptr)runtime_sched.gfree; runtime_sched.gfree = gp; } runtime_unlock(&runtime_sched.gflock); @@ -2482,8 +2505,8 @@ runtime_gomaxprocsfunc(int32 n) { int32 ret; - if(n > MaxGomaxprocs) - n = MaxGomaxprocs; + if(n > _MaxGomaxprocs) + n = _MaxGomaxprocs; runtime_lock(&runtime_sched); ret = runtime_gomaxprocs; if(n <= 0 || n == ret) { @@ -2493,10 +2516,10 @@ runtime_gomaxprocsfunc(int32 n) runtime_unlock(&runtime_sched); runtime_semacquire(&runtime_worldsema, false); - m->gcing = 1; + g->m->gcing = 1; runtime_stoptheworld(); newprocs = n; - m->gcing = 0; + g->m->gcing = 0; runtime_semrelease(&runtime_worldsema); runtime_starttheworld(); @@ -2509,22 +2532,22 @@ runtime_gomaxprocsfunc(int32 n) static void lockOSThread(void) { - m->lockedg = g; - g->lockedm = m; + g->m->lockedg = g; + g->lockedm = g->m; } void runtime_LockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.LockOSThread"); void runtime_LockOSThread(void) { - m->locked |= LockExternal; + g->m->locked |= _LockExternal; lockOSThread(); } void runtime_lockOSThread(void) { - m->locked += LockInternal; + g->m->locked += _LockInternal; lockOSThread(); } @@ -2535,9 +2558,9 @@ runtime_lockOSThread(void) static void unlockOSThread(void) { - if(m->locked != 0) + if(g->m->locked != 0) return; - m->lockedg = nil; + g->m->lockedg = nil; g->lockedm = nil; } @@ -2546,23 +2569,23 @@ void runtime_UnlockOSThread(void) __asm__ (GOSYM_PREFIX "runtime.UnlockOSThread" void runtime_UnlockOSThread(void) { - m->locked &= ~LockExternal; + g->m->locked &= ~_LockExternal; unlockOSThread(); } void runtime_unlockOSThread(void) { - if(m->locked < LockInternal) + if(g->m->locked < _LockInternal) runtime_throw("runtime: internal error: misuse of lockOSThread/unlockOSThread"); - m->locked -= LockInternal; + g->m->locked -= _LockInternal; unlockOSThread(); } bool runtime_lockedOSThread(void) { - return g->lockedm != nil && m->lockedg != nil; + return g->lockedm != nil && g->m->lockedg != nil; } int32 @@ -2580,8 +2603,8 @@ runtime_gcount(void) // Compromise solution is to introduce per-P counters of active goroutines. for(i = 0; i < runtime_allglen; i++) { gp = runtime_allg[i]; - s = gp->status; - if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting) + s = gp->atomicstatus; + if(s == _Grunnable || s == _Grunning || s == _Gsyscall || s == _Gwaiting) n++; } runtime_unlock(&allglock); @@ -2609,7 +2632,7 @@ static void GC(void) {} void runtime_sigprof() { - M *mp = m; + M *mp = g->m; int32 n, i; bool traceback; @@ -2675,7 +2698,7 @@ runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) // Disable preemption, otherwise we can be rescheduled to another thread // that has profiling enabled. - m->locks++; + g->m->locks++; // Stop profiler on this thread so that it is safe to lock prof. // if a profiling signal came in while we had prof locked, @@ -2693,7 +2716,7 @@ runtime_setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) if(hz != 0) runtime_resetcpuprofiler(hz); - m->locks--; + g->m->locks--; } // Change number of processors. The world is stopped, sched is locked. @@ -2706,7 +2729,7 @@ procresize(int32 new) P *p; old = runtime_gomaxprocs; - if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs) + if(old < 0 || old > _MaxGomaxprocs || new <= 0 || new >_MaxGomaxprocs) runtime_throw("procresize: invalid arg"); // initialize new P's for(i = 0; i < new; i++) { @@ -2714,12 +2737,12 @@ procresize(int32 new) if(p == nil) { p = (P*)runtime_mallocgc(sizeof(*p), 0, FlagNoInvokeGC); p->id = i; - p->status = Pgcstop; + p->status = _Pgcstop; runtime_atomicstorep(&runtime_allp[i], p); } if(p->mcache == nil) { if(old==0 && i==0) - p->mcache = m->mcache; // bootstrap + p->mcache = g->m->mcache; // bootstrap else p->mcache = runtime_allocmcache(); } @@ -2739,9 +2762,9 @@ procresize(int32 new) empty = false; // pop from tail of local queue p->runqtail--; - gp = p->runq[p->runqtail%nelem(p->runq)]; + gp = (G*)p->runq[p->runqtail%nelem(p->runq)]; // push onto head of global queue - gp->schedlink = runtime_sched.runqhead; + gp->schedlink = (uintptr)runtime_sched.runqhead; runtime_sched.runqhead = gp; if(runtime_sched.runqtail == nil) runtime_sched.runqtail = gp; @@ -2753,7 +2776,7 @@ procresize(int32 new) // so if we have a spare G we want to put it into allp[1]. for(i = 1; (uint32)i < (uint32)new * nelem(p->runq)/2 && runtime_sched.runqsize > 0; i++) { gp = runtime_sched.runqhead; - runtime_sched.runqhead = gp->schedlink; + runtime_sched.runqhead = (G*)gp->schedlink; if(runtime_sched.runqhead == nil) runtime_sched.runqtail = nil; runtime_sched.runqsize--; @@ -2766,21 +2789,21 @@ procresize(int32 new) runtime_freemcache(p->mcache); p->mcache = nil; gfpurge(p); - p->status = Pdead; + p->status = _Pdead; // can't free P itself because it can be referenced by an M in syscall } - if(m->p) - m->p->m = nil; - m->p = nil; - m->mcache = nil; + if(g->m->p) + ((P*)g->m->p)->m = 0; + g->m->p = 0; + g->m->mcache = nil; p = runtime_allp[0]; - p->m = nil; - p->status = Pidle; + p->m = 0; + p->status = _Pidle; acquirep(p); for(i = new-1; i > 0; i--) { p = runtime_allp[i]; - p->status = Pidle; + p->status = _Pidle; pidleput(p); } runtime_atomicstore((uint32*)&runtime_gomaxprocs, new); @@ -2790,36 +2813,41 @@ procresize(int32 new) static void acquirep(P *p) { + M *m; + + m = g->m; if(m->p || m->mcache) runtime_throw("acquirep: already in go"); - if(p->m || p->status != Pidle) { - runtime_printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status); + if(p->m || p->status != _Pidle) { + runtime_printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? ((M*)p->m)->id : 0, p->status); runtime_throw("acquirep: invalid p state"); } m->mcache = p->mcache; - m->p = p; - p->m = m; - p->status = Prunning; + m->p = (uintptr)p; + p->m = (uintptr)m; + p->status = _Prunning; } // Disassociate p and the current m. static P* releasep(void) { + M *m; P *p; - if(m->p == nil || m->mcache == nil) + m = g->m; + if(m->p == 0 || m->mcache == nil) runtime_throw("releasep: invalid arg"); - p = m->p; - if(p->m != m || p->mcache != m->mcache || p->status != Prunning) { + p = (P*)m->p; + if((M*)p->m != m || p->mcache != m->mcache || p->status != _Prunning) { runtime_printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n", m, m->p, p->m, m->mcache, p->mcache, p->status); runtime_throw("releasep: invalid p state"); } - m->p = nil; + m->p = 0; m->mcache = nil; - p->m = nil; - p->status = Pidle; + p->m = 0; + p->status = _Pidle; return p; } @@ -2870,10 +2898,10 @@ checkdead(void) gp = runtime_allg[i]; if(gp->isbackground) continue; - s = gp->status; - if(s == Gwaiting) + s = gp->atomicstatus; + if(s == _Gwaiting) grunning++; - else if(s == Grunnable || s == Grunning || s == Gsyscall) { + else if(s == _Grunnable || s == _Grunning || s == _Gsyscall) { runtime_unlock(&allglock); runtime_printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s); runtime_throw("checkdead: runnable g"); @@ -2882,7 +2910,7 @@ checkdead(void) runtime_unlock(&allglock); if(grunning == 0) // possible if main goroutine calls runtime_Goexit() runtime_throw("no goroutines (main called runtime.Goexit) - deadlock!"); - m->throwing = -1; // do not dump full stacks + g->m->throwing = -1; // do not dump full stacks runtime_throw("all goroutines are asleep - deadlock!"); } @@ -2958,7 +2986,7 @@ struct Pdesc uint32 syscalltick; int64 syscallwhen; }; -static Pdesc pdesc[MaxGomaxprocs]; +static Pdesc pdesc[_MaxGomaxprocs]; static uint32 retake(int64 now) @@ -2975,7 +3003,7 @@ retake(int64 now) continue; pd = &pdesc[i]; s = p->status; - if(s == Psyscall) { + if(s == _Psyscall) { // Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us). t = p->syscalltick; if(pd->syscalltick != t) { @@ -2995,12 +3023,12 @@ retake(int64 now) // Otherwise the M from which we retake can exit the syscall, // increment nmidle and report deadlock. incidlelocked(-1); - if(runtime_cas(&p->status, s, Pidle)) { + if(runtime_cas(&p->status, s, _Pidle)) { n++; handoffp(p); } incidlelocked(1); - } else if(s == Prunning) { + } else if(s == _Prunning) { // Preempt G if it's running for more than 10ms. t = p->schedtick; if(pd->schedtick != t) { @@ -3060,7 +3088,7 @@ runtime_schedtrace(bool detailed) p = runtime_allp[i]; if(p == nil) continue; - mp = p->m; + mp = (M*)p->m; h = runtime_atomicload(&p->runqhead); t = runtime_atomicload(&p->runqtail); if(detailed) @@ -3084,7 +3112,7 @@ runtime_schedtrace(bool detailed) return; } for(mp = runtime_allm; mp; mp = mp->alllink) { - p = mp->p; + p = (P*)mp->p; gp = mp->curg; lockedg = mp->lockedg; id1 = -1; @@ -3100,15 +3128,15 @@ runtime_schedtrace(bool detailed) " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n", mp->id, id1, id2, mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc, - mp->spinning, m->blocked, id3); + mp->spinning, mp->blocked, id3); } runtime_lock(&allglock); for(gi = 0; gi < runtime_allglen; gi++) { gp = runtime_allg[gi]; mp = gp->m; lockedm = gp->lockedm; - runtime_printf(" G%D: status=%d(%s) m=%d lockedm=%d\n", - gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1, + runtime_printf(" G%D: status=%d(%S) m=%d lockedm=%d\n", + gp->goid, gp->atomicstatus, gp->waitreason, mp ? mp->id : -1, lockedm ? lockedm->id : -1); } runtime_unlock(&allglock); @@ -3120,7 +3148,7 @@ runtime_schedtrace(bool detailed) static void mput(M *mp) { - mp->schedlink = runtime_sched.midle; + mp->schedlink = (uintptr)runtime_sched.midle; runtime_sched.midle = mp; runtime_sched.nmidle++; checkdead(); @@ -3134,7 +3162,7 @@ mget(void) M *mp; if((mp = runtime_sched.midle) != nil){ - runtime_sched.midle = mp->schedlink; + runtime_sched.midle = (M*)mp->schedlink; runtime_sched.nmidle--; } return mp; @@ -3145,9 +3173,9 @@ mget(void) static void globrunqput(G *gp) { - gp->schedlink = nil; + gp->schedlink = 0; if(runtime_sched.runqtail) - runtime_sched.runqtail->schedlink = gp; + runtime_sched.runqtail->schedlink = (uintptr)gp; else runtime_sched.runqhead = gp; runtime_sched.runqtail = gp; @@ -3159,9 +3187,9 @@ globrunqput(G *gp) static void globrunqputbatch(G *ghead, G *gtail, int32 n) { - gtail->schedlink = nil; + gtail->schedlink = 0; if(runtime_sched.runqtail) - runtime_sched.runqtail->schedlink = ghead; + runtime_sched.runqtail->schedlink = (uintptr)ghead; else runtime_sched.runqhead = ghead; runtime_sched.runqtail = gtail; @@ -3189,11 +3217,11 @@ globrunqget(P *p, int32 max) if(runtime_sched.runqsize == 0) runtime_sched.runqtail = nil; gp = runtime_sched.runqhead; - runtime_sched.runqhead = gp->schedlink; + runtime_sched.runqhead = (G*)gp->schedlink; n--; while(n--) { gp1 = runtime_sched.runqhead; - runtime_sched.runqhead = gp1->schedlink; + runtime_sched.runqhead = (G*)gp1->schedlink; runqput(p, gp1); } return gp; @@ -3204,7 +3232,7 @@ globrunqget(P *p, int32 max) static void pidleput(P *p) { - p->link = runtime_sched.pidle; + p->link = (uintptr)runtime_sched.pidle; runtime_sched.pidle = p; runtime_xadd(&runtime_sched.npidle, 1); // TODO: fast atomic } @@ -3218,7 +3246,7 @@ pidleget(void) p = runtime_sched.pidle; if(p) { - runtime_sched.pidle = p->link; + runtime_sched.pidle = (P*)p->link; runtime_xadd(&runtime_sched.npidle, -1); // TODO: fast atomic } return p; @@ -3236,7 +3264,7 @@ retry: h = runtime_atomicload(&p->runqhead); // load-acquire, synchronize with consumers t = p->runqtail; if(t - h < nelem(p->runq)) { - p->runq[t%nelem(p->runq)] = gp; + p->runq[t%nelem(p->runq)] = (uintptr)gp; runtime_atomicstore(&p->runqtail, t+1); // store-release, makes the item available for consumption return; } @@ -3260,13 +3288,13 @@ runqputslow(P *p, G *gp, uint32 h, uint32 t) if(n != nelem(p->runq)/2) runtime_throw("runqputslow: queue is not full"); for(i=0; i<n; i++) - batch[i] = p->runq[(h+i)%nelem(p->runq)]; + batch[i] = (G*)p->runq[(h+i)%nelem(p->runq)]; if(!runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume return false; batch[n] = gp; // Link the goroutines. for(i=0; i<n; i++) - batch[i]->schedlink = batch[i+1]; + batch[i]->schedlink = (uintptr)batch[i+1]; // Now put the batch on global queue. runtime_lock(&runtime_sched); globrunqputbatch(batch[0], batch[n], n+1); @@ -3287,7 +3315,7 @@ runqget(P *p) t = p->runqtail; if(t == h) return nil; - gp = p->runq[h%nelem(p->runq)]; + gp = (G*)p->runq[h%nelem(p->runq)]; if(runtime_cas(&p->runqhead, h, h+1)) // cas-release, commits consume return gp; } @@ -3311,7 +3339,7 @@ runqgrab(P *p, G **batch) if(n > nelem(p->runq)/2) // read inconsistent h and t continue; for(i=0; i<n; i++) - batch[i] = p->runq[(h+i)%nelem(p->runq)]; + batch[i] = (G*)p->runq[(h+i)%nelem(p->runq)]; if(runtime_cas(&p->runqhead, h, h+n)) // cas-release, commits consume break; } @@ -3340,7 +3368,7 @@ runqsteal(P *p, P *p2) if(t - h + n >= nelem(p->runq)) runtime_throw("runqsteal: runq overflow"); for(i=0; i<n; i++, t++) - p->runq[t%nelem(p->runq)] = batch[i]; + p->runq[t%nelem(p->runq)] = (uintptr)batch[i]; runtime_atomicstore(&p->runqtail, t); // store-release, makes the item available for consumption return gp; } @@ -3480,7 +3508,7 @@ sync_runtime_canSpin(intgo i) if (i >= ACTIVE_SPIN || runtime_ncpu <= 1 || runtime_gomaxprocs <= (int32)(runtime_sched.npidle+runtime_sched.nmspinning)+1) { return false; } - p = m->p; + p = (P*)g->m->p; return p != nil && p->runqhead == p->runqtail; } |