// Call from Go to C.
-static FuncVal unlockOSThread = { runtime·unlockOSThread };
+static void endcgo(void);
+static FuncVal endcgoV = { endcgo };
void
runtime·cgocall(void (*fn)(void*), void *arg)
* cgo callback. Add entry to defer stack in case of panic.
*/
runtime·lockOSThread();
- d.fn = &unlockOSThread;
+ d.fn = &endcgoV;
d.siz = 0;
d.link = g->defer;
d.argp = (void*)-1; // unused because unlockm never recovers
runtime·asmcgocall(fn, arg);
runtime·exitsyscall();
+ if(g->defer != &d || d.fn != &endcgoV)
+ runtime·throw("runtime: bad defer entry in cgocallback");
+ g->defer = d.link;
+ endcgo();
+}
+
+static void
+endcgo(void)
+{
+ runtime·unlockOSThread();
m->ncgo--;
if(m->ncgo == 0) {
// We are going back to Go and are not in a recursive
m->cgomal = nil;
}
- if(g->defer != &d || d.fn != &unlockOSThread)
- runtime·throw("runtime: bad defer entry in cgocallback");
- g->defer = d.link;
- runtime·unlockOSThread();
-
if(raceenabled)
runtime·raceacquire(&cgosync);
}
gp->lockedm = nil;
m->curg = nil;
m->lockedg = nil;
+ if(m->locked & ~LockExternal) {
+ runtime·printf("invalid m->locked = %d", m->locked);
+ runtime·throw("internal lockOSThread error");
+ }
+ m->locked = 0;
runtime·unwindstack(gp, nil);
gfput(m->p, gp);
schedule();
}
func TestCallbackPanic(t *testing.T) {
- // TODO(brainman): http://golang.org/issue/4971
- t.Skip("TestCallbackPanic disabled: http://golang.org/issue/4971")
-
// Make sure panic during callback unwinds properly.
if runtime.LockedOSThread() {
t.Fatal("locked OS thread on entry to TestCallbackPanic")