diff options
Diffstat (limited to 'src/pkg/runtime/proc.c')
| -rw-r--r-- | src/pkg/runtime/proc.c | 314 |
1 files changed, 1 insertions, 313 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 540f218273..2d837c537f 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -11,7 +11,6 @@ bool runtime·iscgo; -static void unwindstack(G*, byte*); static void schedule(G*); typedef struct Sched Sched; @@ -892,7 +891,7 @@ schedule(G *gp) m->lockedg = nil; } gp->idlem = nil; - unwindstack(gp, nil); + runtime·unwindstack(gp, nil); gfput(gp); if(--runtime·sched.gcount == 0) runtime·exit(0); @@ -1321,285 +1320,6 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) //printf(" goid=%d\n", newg->goid); } -// Create a new deferred function fn with siz bytes of arguments. -// The compiler turns a defer statement into a call to this. -// Cannot split the stack because it assumes that the arguments -// are available sequentially after &fn; they would not be -// copied if a stack split occurred. It's OK for this to call -// functions that split the stack. -#pragma textflag 7 -uintptr -runtime·deferproc(int32 siz, byte* fn, ...) -{ - Defer *d; - int32 mallocsiz; - - mallocsiz = sizeof(*d); - if(siz > sizeof(d->args)) - mallocsiz += siz - sizeof(d->args); - d = runtime·malloc(mallocsiz); - d->fn = fn; - d->siz = siz; - d->pc = runtime·getcallerpc(&siz); - if(thechar == '5') - d->argp = (byte*)(&fn+2); // skip caller's saved link register - else - d->argp = (byte*)(&fn+1); - runtime·memmove(d->args, d->argp, d->siz); - - d->link = g->defer; - g->defer = d; - - // deferproc returns 0 normally. - // a deferred func that stops a panic - // makes the deferproc return 1. - // the code the compiler generates always - // checks the return value and jumps to the - // end of the function if deferproc returns != 0. - return 0; -} - -// Run a deferred function if there is one. -// The compiler inserts a call to this at the end of any -// function which calls defer. -// If there is a deferred function, this will call runtime·jmpdefer, -// which will jump to the deferred function such that it appears -// to have been called by the caller of deferreturn at the point -// just before deferreturn was called. The effect is that deferreturn -// is called again and again until there are no more deferred functions. -// Cannot split the stack because we reuse the caller's frame to -// call the deferred function. -#pragma textflag 7 -void -runtime·deferreturn(uintptr arg0) -{ - Defer *d; - byte *argp, *fn; - - d = g->defer; - if(d == nil) - return; - argp = (byte*)&arg0; - if(d->argp != argp) - return; - runtime·memmove(argp, d->args, d->siz); - g->defer = d->link; - fn = d->fn; - if(!d->nofree) - runtime·free(d); - runtime·jmpdefer(fn, argp); -} - -// Run all deferred functions for the current goroutine. -static void -rundefer(void) -{ - Defer *d; - - while((d = g->defer) != nil) { - g->defer = d->link; - reflect·call(d->fn, (byte*)d->args, d->siz); - if(!d->nofree) - runtime·free(d); - } -} - -// Free stack frames until we hit the last one -// or until we find the one that contains the sp. -static void -unwindstack(G *gp, byte *sp) -{ - Stktop *top; - byte *stk; - - // Must be called from a different goroutine, usually m->g0. - if(g == gp) - runtime·throw("unwindstack on self"); - - while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) { - stk = (byte*)gp->stackguard - StackGuard; - if(stk <= sp && sp < (byte*)gp->stackbase) - break; - gp->stackbase = (uintptr)top->stackbase; - gp->stackguard = (uintptr)top->stackguard; - if(top->free != 0) - runtime·stackfree(stk, top->free); - } - - if(sp != nil && (sp < (byte*)gp->stackguard - StackGuard || (byte*)gp->stackbase < sp)) { - runtime·printf("recover: %p not in [%p, %p]\n", sp, gp->stackguard - StackGuard, gp->stackbase); - runtime·throw("bad unwindstack"); - } -} - -// Print all currently active panics. Used when crashing. -static void -printpanics(Panic *p) -{ - if(p->link) { - printpanics(p->link); - runtime·printf("\t"); - } - runtime·printf("panic: "); - runtime·printany(p->arg); - if(p->recovered) - runtime·printf(" [recovered]"); - runtime·printf("\n"); -} - -static void recovery(G*); - -// The implementation of the predeclared function panic. -void -runtime·panic(Eface e) -{ - Defer *d; - Panic *p; - - p = runtime·mal(sizeof *p); - p->arg = e; - p->link = g->panic; - p->stackbase = (byte*)g->stackbase; - g->panic = p; - - for(;;) { - d = g->defer; - if(d == nil) - break; - // take defer off list in case of recursive panic - g->defer = d->link; - g->ispanic = true; // rock for newstack, where reflect.call ends up - reflect·call(d->fn, (byte*)d->args, d->siz); - if(p->recovered) { - g->panic = p->link; - if(g->panic == nil) // must be done with signal - g->sig = 0; - runtime·free(p); - // put recovering defer back on list - // for scheduler to find. - d->link = g->defer; - g->defer = d; - runtime·mcall(recovery); - runtime·throw("recovery failed"); // mcall should not return - } - if(!d->nofree) - runtime·free(d); - } - - // ran out of deferred calls - old-school panic now - runtime·startpanic(); - printpanics(g->panic); - runtime·dopanic(0); -} - -// Unwind the stack after a deferred function calls recover -// after a panic. Then arrange to continue running as though -// the caller of the deferred function returned normally. -static void -recovery(G *gp) -{ - Defer *d; - - // Rewind gp's stack; we're running on m->g0's stack. - d = gp->defer; - gp->defer = d->link; - - // Unwind to the stack frame with d's arguments in it. - unwindstack(gp, d->argp); - - // Make the deferproc for this d return again, - // this time returning 1. The calling function will - // jump to the standard return epilogue. - // The -2*sizeof(uintptr) makes up for the - // two extra words that are on the stack at - // each call to deferproc. - // (The pc we're returning to does pop pop - // before it tests the return value.) - // On the arm there are 2 saved LRs mixed in too. - if(thechar == '5') - gp->sched.sp = (uintptr)d->argp - 4*sizeof(uintptr); - else - gp->sched.sp = (uintptr)d->argp - 2*sizeof(uintptr); - gp->sched.pc = d->pc; - if(!d->nofree) - runtime·free(d); - runtime·gogo(&gp->sched, 1); -} - -// The implementation of the predeclared function recover. -// Cannot split the stack because it needs to reliably -// find the stack segment of its caller. -#pragma textflag 7 -void -runtime·recover(byte *argp, Eface ret) -{ - Stktop *top, *oldtop; - Panic *p; - - // Must be a panic going on. - if((p = g->panic) == nil || p->recovered) - goto nomatch; - - // Frame must be at the top of the stack segment, - // because each deferred call starts a new stack - // segment as a side effect of using reflect.call. - // (There has to be some way to remember the - // variable argument frame size, and the segment - // code already takes care of that for us, so we - // reuse it.) - // - // As usual closures complicate things: the fp that - // the closure implementation function claims to have - // is where the explicit arguments start, after the - // implicit pointer arguments and PC slot. - // If we're on the first new segment for a closure, - // then fp == top - top->args is correct, but if - // the closure has its own big argument frame and - // allocated a second segment (see below), - // the fp is slightly above top - top->args. - // That condition can't happen normally though - // (stack pointers go down, not up), so we can accept - // any fp between top and top - top->args as - // indicating the top of the segment. - top = (Stktop*)g->stackbase; - if(argp < (byte*)top - top->argsize || (byte*)top < argp) - goto nomatch; - - // The deferred call makes a new segment big enough - // for the argument frame but not necessarily big - // enough for the function's local frame (size unknown - // at the time of the call), so the function might have - // made its own segment immediately. If that's the - // case, back top up to the older one, the one that - // reflect.call would have made for the panic. - // - // The fp comparison here checks that the argument - // frame that was copied during the split (the top->args - // bytes above top->fp) abuts the old top of stack. - // This is a correct test for both closure and non-closure code. - oldtop = (Stktop*)top->stackbase; - if(oldtop != nil && top->argp == (byte*)oldtop - top->argsize) - top = oldtop; - - // Now we have the segment that was created to - // run this call. It must have been marked as a panic segment. - if(!top->panic) - goto nomatch; - - // Okay, this is the top frame of a deferred call - // in response to a panic. It can see the panic argument. - p->recovered = 1; - ret = p->arg; - FLUSH(&ret); - return; - -nomatch: - ret.type = nil; - ret.data = nil; - FLUSH(&ret); -} - - // Put on gfree list. Sched must be locked. static void gfput(G *gp) @@ -1629,13 +1349,6 @@ runtime·Breakpoint(void) } void -runtime·Goexit(void) -{ - rundefer(); - runtime·goexit(); -} - -void runtime·Gosched(void) { runtime·gosched(); @@ -1811,28 +1524,3 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) if(hz != 0) runtime·resetcpuprofiler(hz); } - -void (*libcgo_setenv)(byte**); - -// Update the C environment if cgo is loaded. -// Called from syscall.Setenv. -void -syscall·setenv_c(String k, String v) -{ - byte *arg[2]; - - if(libcgo_setenv == nil) - return; - - arg[0] = runtime·malloc(k.len + 1); - runtime·memmove(arg[0], k.str, k.len); - arg[0][k.len] = 0; - - arg[1] = runtime·malloc(v.len + 1); - runtime·memmove(arg[1], v.str, v.len); - arg[1][v.len] = 0; - - runtime·asmcgocall((void*)libcgo_setenv, arg); - runtime·free(arg[0]); - runtime·free(arg[1]); -} |
