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 | 6763ea99f601d0b5e5a330db9d3901e22769e76d (patch) | |
tree | 06643acfb813b9f0f4433258fdf291899c5102da | |
parent | 94ae060ebca55a9d6993124c9583123bb18d75b8 (diff) | |
download | go-6763ea99f601d0b5e5a330db9d3901e22769e76d.tar.gz |
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
http://codereview.appspot.com/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 d30d5985e..d469e7c5b 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); } /* |