]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: Restore scheduler stack position if cgo callback panics.
authorIan Lance Taylor <iant@golang.org>
Sat, 8 Jan 2011 18:22:37 +0000 (10:22 -0800)
committerIan Lance Taylor <iant@golang.org>
Sat, 8 Jan 2011 18:22:37 +0000 (10:22 -0800)
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

src/pkg/runtime/proc.c

index d30d5985ece9145700adba887181fa0007b3ee4d..d469e7c5b798a54cac33b0081d8af388ff06cb67 100644 (file)
@@ -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);
 }
 
 /*