diff options
author | Ian Lance Taylor <iant@golang.org> | 2011-01-08 10:22:37 -0800 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2011-01-08 10:22:37 -0800 |
commit | 2d393034290661f5e78cf9b481aa8255b39eb488 (patch) | |
tree | 75bd8108bba27322f7eb97a2f8b4479f174208b7 | |
parent | 66a45b486b21f367e506bc7ef1b995a7649ab899 (diff) | |
download | go-2d393034290661f5e78cf9b481aa8255b39eb488.tar.gz go-2d393034290661f5e78cf9b481aa8255b39eb488.zip |
runtime: Restore scheduler stack position if cgo callback panics.
If we don't do this, then when C code calls back to Go code
which panics, we lose space on the scheduler stack. If that
happens a lot, eventually there is no space left on the
scheduler stack.
R=rsc
CC=golang-dev
https://golang.org/cl/3898042
-rw-r--r-- | src/pkg/runtime/proc.c | 33 |
1 files changed, 33 insertions, 0 deletions
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index d30d5985ec..d469e7c5b7 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -619,26 +619,59 @@ runtime·exitsyscall(void) runtime·gosched(); } +// Restore the position of m's scheduler stack if we unwind the stack +// through a cgo callback. +static void +runtime·unwindcgocallback(void **spaddr, void *sp) +{ + *spaddr = sp; +} + // Start scheduling g1 again for a cgo callback. void runtime·startcgocallback(G* g1) { + Defer *d; + uintptr arg; + runtime·lock(&runtime·sched); g1->status = Grunning; runtime·sched.msyscall--; runtime·sched.mcpu++; runtime·unlock(&runtime·sched); + + // Add an entry to the defer stack which restores the old + // position of m's scheduler stack. This is so that if the + // code we are calling panics, we won't lose the space on the + // scheduler stack. Note that we are locked to this m here. + d = runtime·malloc(sizeof(*d) + 2*sizeof(void*) - sizeof(d->args)); + d->fn = (byte*)runtime·unwindcgocallback; + d->siz = 2 * sizeof(uintptr); + ((void**)d->args)[0] = &m->sched.sp; + ((void**)d->args)[1] = m->sched.sp; + d->link = g1->defer; + g1->defer = d; } // Stop scheduling g1 after a cgo callback. void runtime·endcgocallback(G* g1) { + Defer *d; + runtime·lock(&runtime·sched); g1->status = Gsyscall; runtime·sched.mcpu--; runtime·sched.msyscall++; runtime·unlock(&runtime·sched); + + // Remove the entry on the defer stack added by + // startcgocallback. + d = g1->defer; + if (d == nil || d->fn != (byte*)runtime·unwindcgocallback) + runtime·throw("bad defer entry in endcgocallback"); + g1->defer = d->link; + runtime·free(d); } /* |