aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2011-01-08 10:22:37 -0800
committerIan Lance Taylor <iant@golang.org>2011-01-08 10:22:37 -0800
commit2d393034290661f5e78cf9b481aa8255b39eb488 (patch)
tree75bd8108bba27322f7eb97a2f8b4479f174208b7
parent66a45b486b21f367e506bc7ef1b995a7649ab899 (diff)
downloadgo-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.c33
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);
}
/*