]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: clear locked bit when goroutine exits
authorRuss Cox <rsc@golang.org>
Fri, 8 Mar 2013 16:26:00 +0000 (11:26 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 8 Mar 2013 16:26:00 +0000 (11:26 -0500)
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

src/pkg/runtime/cgocall.c
src/pkg/runtime/proc.c
src/pkg/runtime/syscall_windows_test.go

index 3ed1243aacc84e43670307d8db06254029ad4704..0c96187495312a8682d7823a24d0f91225b930d4 100644 (file)
@@ -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);
 }
index d0f6745aa7ddc72cfb8286cd3945bef8c6470375..8429826974c11331631c408931b50ff3c44add54 100644 (file)
@@ -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();
index 0b6503b1e880c4635c7de573f9176916b4605bf7..f04d2cd543d28763bce697023cb52a725c600876 100644 (file)
@@ -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")