mirror of
https://github.com/golang/go
synced 2024-11-25 06:57:58 -07:00
runtime: run deferred calls at Goexit
baby step toward panic+recover. Fixes #349. R=r CC=golang-dev https://golang.org/cl/825043
This commit is contained in:
parent
bc32dd9ec4
commit
83727ccf7c
@ -199,11 +199,11 @@ TEXT reflect·call(SB), 7, $0
|
|||||||
MOVL AX, (m_morebuf+gobuf_g)(BX)
|
MOVL AX, (m_morebuf+gobuf_g)(BX)
|
||||||
|
|
||||||
// Set up morestack arguments to call f on a new stack.
|
// Set up morestack arguments to call f on a new stack.
|
||||||
// We set f's frame size to zero, meaning
|
// We set f's frame size to 1, as a hint to newstack
|
||||||
// allocate a standard sized stack segment.
|
// that this is a call from reflect·call.
|
||||||
// If it turns out that f needs a larger frame than this,
|
// If it turns out that f needs a larger frame than
|
||||||
// f's usual stack growth prolog will allocate
|
// the default stack, f's usual stack growth prolog will
|
||||||
// a new segment (and recopy the arguments).
|
// allocate a new segment (and recopy the arguments).
|
||||||
MOVL 4(SP), AX // fn
|
MOVL 4(SP), AX // fn
|
||||||
MOVL 8(SP), DX // arg frame
|
MOVL 8(SP), DX // arg frame
|
||||||
MOVL 12(SP), CX // arg size
|
MOVL 12(SP), CX // arg size
|
||||||
@ -211,7 +211,7 @@ TEXT reflect·call(SB), 7, $0
|
|||||||
MOVL AX, m_morepc(BX) // f's PC
|
MOVL AX, m_morepc(BX) // f's PC
|
||||||
MOVL DX, m_morefp(BX) // argument frame pointer
|
MOVL DX, m_morefp(BX) // argument frame pointer
|
||||||
MOVL CX, m_moreargs(BX) // f's argument size
|
MOVL CX, m_moreargs(BX) // f's argument size
|
||||||
MOVL $0, m_moreframe(BX) // f's frame size
|
MOVL $1, m_moreframe(BX) // f's frame size
|
||||||
|
|
||||||
// Call newstack on m's scheduling stack.
|
// Call newstack on m's scheduling stack.
|
||||||
MOVL m_g0(BX), BP
|
MOVL m_g0(BX), BP
|
||||||
|
@ -143,11 +143,11 @@ TEXT reflect·call(SB), 7, $0
|
|||||||
MOVQ g, (m_morebuf+gobuf_g)(m)
|
MOVQ g, (m_morebuf+gobuf_g)(m)
|
||||||
|
|
||||||
// Set up morestack arguments to call f on a new stack.
|
// Set up morestack arguments to call f on a new stack.
|
||||||
// We set f's frame size to zero, meaning
|
// We set f's frame size to 1, as a hint to newstack
|
||||||
// allocate a standard sized stack segment.
|
// that this is a call from reflect·call.
|
||||||
// If it turns out that f needs a larger frame than this,
|
// If it turns out that f needs a larger frame than
|
||||||
// f's usual stack growth prolog will allocate
|
// the default stack, f's usual stack growth prolog will
|
||||||
// a new segment (and recopy the arguments).
|
// allocate a new segment (and recopy the arguments).
|
||||||
MOVQ 8(SP), AX // fn
|
MOVQ 8(SP), AX // fn
|
||||||
MOVQ 16(SP), BX // arg frame
|
MOVQ 16(SP), BX // arg frame
|
||||||
MOVL 24(SP), CX // arg size
|
MOVL 24(SP), CX // arg size
|
||||||
@ -155,7 +155,7 @@ TEXT reflect·call(SB), 7, $0
|
|||||||
MOVQ AX, m_morepc(m) // f's PC
|
MOVQ AX, m_morepc(m) // f's PC
|
||||||
MOVQ BX, m_morefp(m) // argument frame pointer
|
MOVQ BX, m_morefp(m) // argument frame pointer
|
||||||
MOVL CX, m_moreargs(m) // f's argument size
|
MOVL CX, m_moreargs(m) // f's argument size
|
||||||
MOVL $0, m_moreframe(m) // f's frame size
|
MOVL $1, m_moreframe(m) // f's frame size
|
||||||
|
|
||||||
// Call newstack on m's scheduling stack.
|
// Call newstack on m's scheduling stack.
|
||||||
MOVQ m_g0(m), g
|
MOVQ m_g0(m), g
|
||||||
|
@ -175,11 +175,11 @@ TEXT reflect·call(SB), 7, $-4
|
|||||||
MOVW g, (m_morebuf+gobuf_g)(m)
|
MOVW g, (m_morebuf+gobuf_g)(m)
|
||||||
|
|
||||||
// Set up morestack arguments to call f on a new stack.
|
// Set up morestack arguments to call f on a new stack.
|
||||||
// We set f's frame size to zero, meaning
|
// We set f's frame size to 1, as a hint to newstack
|
||||||
// allocate a standard sized stack segment.
|
// that this is a call from reflect·call.
|
||||||
// If it turns out that f needs a larger frame than this,
|
// If it turns out that f needs a larger frame than
|
||||||
// f's usual stack growth prolog will allocate
|
// the default stack, f's usual stack growth prolog will
|
||||||
// a new segment (and recopy the arguments).
|
// allocate a new segment (and recopy the arguments).
|
||||||
MOVW 4(SP), R0 // fn
|
MOVW 4(SP), R0 // fn
|
||||||
MOVW 8(SP), R1 // arg frame
|
MOVW 8(SP), R1 // arg frame
|
||||||
MOVW 12(SP), R2 // arg size
|
MOVW 12(SP), R2 // arg size
|
||||||
@ -187,7 +187,7 @@ TEXT reflect·call(SB), 7, $-4
|
|||||||
MOVW R0, m_morepc(m) // f's PC
|
MOVW R0, m_morepc(m) // f's PC
|
||||||
MOVW R1, m_morefp(m) // argument frame pointer
|
MOVW R1, m_morefp(m) // argument frame pointer
|
||||||
MOVW R2, m_moreargs(m) // f's argument size
|
MOVW R2, m_moreargs(m) // f's argument size
|
||||||
MOVW $0, R3
|
MOVW $1, R3
|
||||||
MOVW R3, m_moreframe(m) // f's frame size
|
MOVW R3, m_moreframe(m) // f's frame size
|
||||||
|
|
||||||
// Call newstack on m's scheduling stack.
|
// Call newstack on m's scheduling stack.
|
||||||
|
@ -15,6 +15,7 @@ package runtime
|
|||||||
func Gosched()
|
func Gosched()
|
||||||
|
|
||||||
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
|
// Goexit terminates the goroutine that calls it. No other goroutine is affected.
|
||||||
|
// Goexit runs all deferred calls before terminating the goroutine.
|
||||||
func Goexit()
|
func Goexit()
|
||||||
|
|
||||||
// Breakpoint() executes a breakpoint trap.
|
// Breakpoint() executes a breakpoint trap.
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "malloc.h"
|
#include "malloc.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
static void unwindstack(G*, byte*);
|
||||||
|
|
||||||
typedef struct Sched Sched;
|
typedef struct Sched Sched;
|
||||||
|
|
||||||
M m0;
|
M m0;
|
||||||
@ -223,26 +225,6 @@ mget(G *g)
|
|||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put on gfree list. Sched must be locked.
|
|
||||||
static void
|
|
||||||
gfput(G *g)
|
|
||||||
{
|
|
||||||
g->schedlink = sched.gfree;
|
|
||||||
sched.gfree = g;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get from gfree list. Sched must be locked.
|
|
||||||
static G*
|
|
||||||
gfget(void)
|
|
||||||
{
|
|
||||||
G *g;
|
|
||||||
|
|
||||||
g = sched.gfree;
|
|
||||||
if(g)
|
|
||||||
sched.gfree = g->schedlink;
|
|
||||||
return g;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mark g ready to run.
|
// Mark g ready to run.
|
||||||
void
|
void
|
||||||
ready(G *g)
|
ready(G *g)
|
||||||
@ -494,6 +476,7 @@ scheduler(void)
|
|||||||
gp->lockedm = nil;
|
gp->lockedm = nil;
|
||||||
m->lockedg = nil;
|
m->lockedg = nil;
|
||||||
}
|
}
|
||||||
|
unwindstack(gp, nil);
|
||||||
gfput(gp);
|
gfput(gp);
|
||||||
if(--sched.gcount == 0)
|
if(--sched.gcount == 0)
|
||||||
exit(0);
|
exit(0);
|
||||||
@ -684,7 +667,8 @@ oldstack(void)
|
|||||||
}
|
}
|
||||||
goid = old.gobuf.g->goid; // fault if g is bad, before gogo
|
goid = old.gobuf.g->goid; // fault if g is bad, before gogo
|
||||||
|
|
||||||
stackfree(g1->stackguard - StackGuard);
|
if(old.free)
|
||||||
|
stackfree(g1->stackguard - StackGuard);
|
||||||
g1->stackbase = old.stackbase;
|
g1->stackbase = old.stackbase;
|
||||||
g1->stackguard = old.stackguard;
|
g1->stackguard = old.stackguard;
|
||||||
|
|
||||||
@ -699,29 +683,42 @@ newstack(void)
|
|||||||
byte *stk, *sp;
|
byte *stk, *sp;
|
||||||
G *g1;
|
G *g1;
|
||||||
Gobuf label;
|
Gobuf label;
|
||||||
|
bool free;
|
||||||
|
|
||||||
frame = m->moreframe;
|
frame = m->moreframe;
|
||||||
args = m->moreargs;
|
args = m->moreargs;
|
||||||
|
g1 = m->curg;
|
||||||
// Round up to align things nicely.
|
|
||||||
// This is sufficient for both 32- and 64-bit machines.
|
if(frame == 1 && args > 0 && m->morebuf.sp - sizeof(Stktop) - args - 32 > g1->stackguard) {
|
||||||
args = (args+7) & ~7;
|
// special case: called from reflect.call (frame == 1)
|
||||||
|
// to call code with an arbitrary argument size,
|
||||||
if(frame < StackBig)
|
// and we have enough space on the current stack.
|
||||||
frame = StackBig;
|
// the new Stktop* is necessary to unwind, but
|
||||||
frame += 1024; // for more functions, Stktop.
|
// we don't need to create a new segment.
|
||||||
stk = stackalloc(frame);
|
top = (Stktop*)(m->morebuf.sp - sizeof(*top));
|
||||||
|
stk = g1->stackguard - StackGuard;
|
||||||
|
free = false;
|
||||||
|
} else {
|
||||||
|
// allocate new segment.
|
||||||
|
if(frame == 1) // failed reflect.call hint
|
||||||
|
frame = 0;
|
||||||
|
frame += args;
|
||||||
|
if(frame < StackBig)
|
||||||
|
frame = StackBig;
|
||||||
|
frame += 1024; // room for more functions, Stktop.
|
||||||
|
stk = stackalloc(frame);
|
||||||
|
top = (Stktop*)(stk+frame-sizeof(*top));
|
||||||
|
free = true;
|
||||||
|
}
|
||||||
|
|
||||||
//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
|
//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
|
||||||
|
|
||||||
g1 = m->curg;
|
|
||||||
top = (Stktop*)(stk+frame-sizeof(*top));
|
|
||||||
top->stackbase = g1->stackbase;
|
top->stackbase = g1->stackbase;
|
||||||
top->stackguard = g1->stackguard;
|
top->stackguard = g1->stackguard;
|
||||||
top->gobuf = m->morebuf;
|
top->gobuf = m->morebuf;
|
||||||
top->fp = m->morefp;
|
top->fp = m->morefp;
|
||||||
top->args = args;
|
top->args = args;
|
||||||
|
top->free = free;
|
||||||
|
|
||||||
g1->stackbase = (byte*)top;
|
g1->stackbase = (byte*)top;
|
||||||
g1->stackguard = stk + StackGuard;
|
g1->stackguard = stk + StackGuard;
|
||||||
@ -792,6 +789,8 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
|
|||||||
|
|
||||||
if((newg = gfget()) != nil){
|
if((newg = gfget()) != nil){
|
||||||
newg->status = Gwaiting;
|
newg->status = Gwaiting;
|
||||||
|
if(newg->stackguard - StackGuard != newg->stack0)
|
||||||
|
throw("invalid stack in newg");
|
||||||
} else {
|
} else {
|
||||||
newg = malg(4096);
|
newg = malg(4096);
|
||||||
newg->status = Gwaiting;
|
newg->status = Gwaiting;
|
||||||
@ -853,7 +852,63 @@ void
|
|||||||
fn = d->fn;
|
fn = d->fn;
|
||||||
free(d);
|
free(d);
|
||||||
jmpdefer(fn, sp);
|
jmpdefer(fn, sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rundefer(void)
|
||||||
|
{
|
||||||
|
Defer *d;
|
||||||
|
|
||||||
|
while((d = g->defer) != nil) {
|
||||||
|
g->defer = d->link;
|
||||||
|
reflect·call(d->fn, d->args, d->siz);
|
||||||
|
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)
|
||||||
|
throw("unwindstack on self");
|
||||||
|
|
||||||
|
while((top = (Stktop*)gp->stackbase) != nil && top->stackbase != nil) {
|
||||||
|
stk = gp->stackguard - StackGuard;
|
||||||
|
if(stk <= sp && sp < gp->stackbase)
|
||||||
|
break;
|
||||||
|
gp->stackbase = top->stackbase;
|
||||||
|
gp->stackguard = top->stackguard;
|
||||||
|
free(stk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put on gfree list. Sched must be locked.
|
||||||
|
static void
|
||||||
|
gfput(G *g)
|
||||||
|
{
|
||||||
|
if(g->stackguard - StackGuard != g->stack0)
|
||||||
|
throw("invalid stack in gfput");
|
||||||
|
g->schedlink = sched.gfree;
|
||||||
|
sched.gfree = g;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get from gfree list. Sched must be locked.
|
||||||
|
static G*
|
||||||
|
gfget(void)
|
||||||
|
{
|
||||||
|
G *g;
|
||||||
|
|
||||||
|
g = sched.gfree;
|
||||||
|
if(g)
|
||||||
|
sched.gfree = g->schedlink;
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
·Breakpoint(void)
|
·Breakpoint(void)
|
||||||
@ -864,6 +919,7 @@ void
|
|||||||
void
|
void
|
||||||
·Goexit(void)
|
·Goexit(void)
|
||||||
{
|
{
|
||||||
|
rundefer();
|
||||||
goexit();
|
goexit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +239,7 @@ struct Stktop
|
|||||||
// fp == gobuf.sp except in the case of a reflected
|
// fp == gobuf.sp except in the case of a reflected
|
||||||
// function call, which uses an off-stack argument frame.
|
// function call, which uses an off-stack argument frame.
|
||||||
uint8* fp;
|
uint8* fp;
|
||||||
|
bool free; // call stackfree for this frame?
|
||||||
};
|
};
|
||||||
struct Alg
|
struct Alg
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user