Commit 1a4599b4 authored by Russ Cox's avatar Russ Cox

runtime: clear locked bit when goroutine exits

Otherwise the next goroutine run on the m
can get inadvertently locked if it executes a cgo call
that turns on the internal lock.

While we're here, fix the cgo panic unwind to
decrement m->ncgo like the non-panic unwind does.

Fixes #4971.

R=golang-dev, iant, dvyukov
CC=golang-dev
https://golang.org/cl/7627043
parent 091d7210
......@@ -95,7 +95,8 @@ static void unwindm(void);
// 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)
......@@ -123,7 +124,7 @@ 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
......@@ -148,6 +149,16 @@ runtime·cgocall(void (*fn)(void*), void *arg)
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
......@@ -156,11 +167,6 @@ runtime·cgocall(void (*fn)(void*), void *arg)
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);
}
......
......@@ -1173,6 +1173,11 @@ goexit0(G *gp)
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();
......
......@@ -172,9 +172,6 @@ func TestCallbackGC(t *testing.T) {
}
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")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment