]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: cgo-related fixes
authorRuss Cox <rsc@golang.org>
Fri, 1 Feb 2013 16:34:41 +0000 (08:34 -0800)
committerRuss Cox <rsc@golang.org>
Fri, 1 Feb 2013 16:34:41 +0000 (08:34 -0800)
* Separate internal and external LockOSThread, for cgo safety.
* Show goroutine that made faulting cgo call.
* Never start a panic due to a signal caused by a cgo call.

Fixes #3774.
Fixes #3775.
Fixes #3797.

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7228081

21 files changed:
misc/cgo/test/cgo_test.go
misc/cgo/test/issue3775.go [new file with mode: 0644]
src/pkg/runtime/cgocall.c
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h
src/pkg/runtime/signal_darwin_386.c
src/pkg/runtime/signal_darwin_amd64.c
src/pkg/runtime/signal_freebsd_386.c
src/pkg/runtime/signal_freebsd_amd64.c
src/pkg/runtime/signal_freebsd_arm.c
src/pkg/runtime/signal_linux_386.c
src/pkg/runtime/signal_linux_amd64.c
src/pkg/runtime/signal_linux_arm.c
src/pkg/runtime/signal_netbsd_386.c
src/pkg/runtime/signal_netbsd_amd64.c
src/pkg/runtime/signal_openbsd_386.c
src/pkg/runtime/signal_openbsd_amd64.c
src/pkg/runtime/signal_windows_386.c
src/pkg/runtime/signal_windows_amd64.c
src/pkg/runtime/traceback_arm.c
src/pkg/runtime/traceback_x86.c

index cfb6d0ee833e91bb67273933c32fe5148788a7db..d2514582a243c4fccfa6db0685fe8e0a4a2b2696 100644 (file)
@@ -34,5 +34,6 @@ func TestPrintf(t *testing.T)              { testPrintf(t) }
 func Test4029(t *testing.T)                { test4029(t) }
 func TestBoolAlign(t *testing.T)           { testBoolAlign(t) }
 func Test3729(t *testing.T)                { test3729(t) }
+func Test3775(t *testing.T)                { test3775(t) }
 
 func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/issue3775.go b/misc/cgo/test/issue3775.go
new file mode 100644 (file)
index 0000000..c05a5d4
--- /dev/null
@@ -0,0 +1,29 @@
+package cgotest
+
+/*
+void lockOSThreadCallback(void);
+inline static void lockOSThreadC(void)
+{
+        lockOSThreadCallback();
+}
+int usleep(unsigned usec);
+*/
+import "C"
+
+import (
+       "runtime"
+       "testing"
+)
+
+func test3775(t *testing.T) {
+       // Used to panic because of the UnlockOSThread below.
+       C.lockOSThreadC()
+}
+
+//export lockOSThreadCallback
+func lockOSThreadCallback() {
+       runtime.LockOSThread()
+       runtime.UnlockOSThread()
+       go C.usleep(10000)
+       runtime.Gosched()
+}
index ed859c07b9320736df33ce008e647680f56909de..519a5386b9ab0ac7492bfb09b529247b77e264dc 100644 (file)
@@ -91,7 +91,6 @@ static int64 cgosync;  /* represents possible synchronization in C code */
 void *cgo_load_gm; /* filled in by dynamic linker when Cgo is available */
 void *cgo_save_gm; /* filled in by dynamic linker when Cgo is available */
 
-static void unlockm(void);
 static void unwindm(void);
 
 // Call from Go to C.
@@ -119,22 +118,16 @@ runtime·cgocall(void (*fn)(void*), void *arg)
 
        /*
         * Lock g to m to ensure we stay on the same stack if we do a
-        * cgo callback.
+        * cgo callback. Add entry to defer stack in case of panic.
         */
-       d.special = false;
-       if(m->lockedg == nil) {
-               m->lockedg = g;
-               g->lockedm = m;
-
-               // Add entry to defer stack in case of panic.
-               d.fn = (byte*)unlockm;
-               d.siz = 0;
-               d.link = g->defer;
-               d.argp = (void*)-1;  // unused because unlockm never recovers
-               d.special = true;
-               d.free = false;
-               g->defer = &d;
-       }
+       runtime·lockOSThread();
+       d.fn = (byte*)runtime·unlockOSThread;
+       d.siz = 0;
+       d.link = g->defer;
+       d.argp = (void*)-1;  // unused because unlockm never recovers
+       d.special = true;
+       d.free = false;
+       g->defer = &d;
 
        m->ncgo++;
 
@@ -161,24 +154,15 @@ runtime·cgocall(void (*fn)(void*), void *arg)
                m->cgomal = nil;
        }
 
-       if(d.special) {
-               if(g->defer != &d || d.fn != (byte*)unlockm)
-                       runtime·throw("runtime: bad defer entry in cgocallback");
-               g->defer = d.link;
-               unlockm();
-       }
+       if(g->defer != &d || d.fn != (byte*)runtime·unlockOSThread)
+               runtime·throw("runtime: bad defer entry in cgocallback");
+       g->defer = d.link;
+       runtime·unlockOSThread();
 
        if(raceenabled)
                runtime·raceacquire(&cgosync);
 }
 
-static void
-unlockm(void)
-{
-       m->lockedg = nil;
-       g->lockedm = nil;
-}
-
 void
 runtime·NumCgoCall(int64 ret)
 {
index b589235c1f01f938f9e4d607aadb130bcdfcd8ab..8cf8d9d81f6be06490f1ef30ef93637bd517a9bd 100644 (file)
@@ -79,7 +79,6 @@ struct Sched {
        int32 profilehz;        // cpu profiling rate
 
        bool init;  // running initialization
-       bool lockmain;  // init called runtime.LockOSThread
 
        Note    stopped;        // one g can set waitstop and wait here for m's to stop
 };
@@ -238,7 +237,7 @@ runtime·main(void)
        // Those can arrange for main.main to run in the main thread
        // by calling runtime.LockOSThread during initialization
        // to preserve the lock.
-       runtime·LockOSThread();
+       runtime·lockOSThread();
        // From now on, newgoroutines may use non-main threads.
        setmcpumax(runtime·gomaxprocs);
        runtime·sched.init = true;
@@ -246,8 +245,7 @@ runtime·main(void)
        scvg->issystem = true;
        main·init();
        runtime·sched.init = false;
-       if(!runtime·sched.lockmain)
-               runtime·UnlockOSThread();
+       runtime·unlockOSThread();
 
        // The deadlock detection has false negatives.
        // Let scvg start up, to eliminate the false negative
@@ -917,6 +915,7 @@ schedule(G *gp)
                        if(gp->lockedm) {
                                gp->lockedm = nil;
                                m->lockedg = nil;
+                               m->locked = 0;
                        }
                        gp->idlem = nil;
                        runtime·unwindstack(gp, nil);
@@ -1460,26 +1459,50 @@ runtime·gomaxprocsfunc(int32 n)
        return ret;
 }
 
-void
-runtime·LockOSThread(void)
+static void
+LockOSThread(void)
 {
-       if(m == &runtime·m0 && runtime·sched.init) {
-               runtime·sched.lockmain = true;
-               return;
-       }
        m->lockedg = g;
        g->lockedm = m;
 }
 
 void
-runtime·UnlockOSThread(void)
+runtime·LockOSThread(void)
+{
+       m->locked |= LockExternal;
+       LockOSThread();
+}
+
+void
+runtime·lockOSThread(void)
+{
+       m->locked += LockInternal;
+       LockOSThread();
+}
+
+static void
+UnlockOSThread(void)
 {
-       if(m == &runtime·m0 && runtime·sched.init) {
-               runtime·sched.lockmain = false;
+       if(m->locked != 0)
                return;
-       }
        m->lockedg = nil;
        g->lockedm = nil;
+}      
+
+void
+runtime·UnlockOSThread(void)
+{
+       m->locked &= ~LockExternal;
+       UnlockOSThread();
+}
+
+void
+runtime·unlockOSThread(void)
+{
+       if(m->locked < LockInternal)
+               runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
+       m->locked -= LockInternal;
+       UnlockOSThread();
 }
 
 bool
index 3e99b75beab3227faa288b2cc01c5d6dc9f0bf05..ea46388d7196249361e5cc32cbc245757ae450f8 100644 (file)
@@ -281,6 +281,7 @@ struct      M
        uint32  freglo[16];     // D[i] lsb and F[i]
        uint32  freghi[16];     // D[i] msb and F[i+16]
        uint32  fflag;          // floating point compare flags
+       uint32  locked; // tracking for LockOSThread
        M*      nextwaitm;      // next M waiting for lock
        uintptr waitsema;       // semaphore for parking on locks
        uint32  waitsemacount;
@@ -303,6 +304,15 @@ struct     M
        uintptr end[];
 };
 
+// The m->locked word holds a single bit saying whether
+// external calls to LockOSThread are in effect, and then a counter
+// of the internal nesting depth of lockOSThread / unlockOSThread.
+enum
+{
+       LockExternal = 1,
+       LockInternal = 2,
+};
+
 struct Stktop
 {
        // The offsets of these fields are known to (hard-coded in) libmach.
@@ -858,8 +868,8 @@ void        runtime·semrelease(uint32*);
 int32  runtime·gomaxprocsfunc(int32 n);
 void   runtime·procyield(uint32);
 void   runtime·osyield(void);
-void   runtime·LockOSThread(void);
-void   runtime·UnlockOSThread(void);
+void   runtime·lockOSThread(void);
+void   runtime·unlockOSThread(void);
 
 void   runtime·mapassign(MapType*, Hmap*, byte*, byte*);
 void   runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
index 9e986352b4ce8a7251a177c2b278b9d0c0f955be..aeb0f43223619b6b592bd03fef83026079287abc 100644 (file)
@@ -47,7 +47,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Work around Leopard bug that doesn't set FPE_INTDIV.
                // Look at instruction to see if it is a divide.
@@ -101,7 +101,11 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
        }
 
-       runtime·printf("pc: %x\n", r->eip);
+       runtime·printf("PC=%x\n", r->eip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }       
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index d9c5f48e7c20686318c8b94df886dee61e005f2d..326fdd4f26944410149a85e4984a6ab2f3db8e6e 100644 (file)
@@ -55,7 +55,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Work around Leopard bug that doesn't set FPE_INTDIV.
                // Look at instruction to see if it is a divide.
@@ -111,7 +111,11 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
        }
 
-       runtime·printf("pc: %X\n", r->rip);
+       runtime·printf("PC=%X\n", r->rip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 80da95d98ac68b4f4e4dc09e8cc4959716a1630a..ae9f7321b932709da6d0cbf123c8b5c0a3ab4317 100644 (file)
@@ -54,7 +54,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -97,6 +97,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->mc_eip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index e4307682f4c0504e585e69fc746f8b4874861c4a..19382ec944a2824baddae3305c0cef65096ccbad 100644 (file)
@@ -62,7 +62,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -105,6 +105,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->mc_rip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index cc96280f7aaaf0e2a38fc265309c5519ee9f3aa2..e2bd9e8a2ffe136f5bdae7f15c62b938a6b11658 100644 (file)
@@ -75,7 +75,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -118,6 +118,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%x\n", r->r15);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 4dbcb48f5207dc3014afb99a6078d29677ed76ab..40e64013cff69dd0c0025cb939471f30d3137256 100644 (file)
@@ -50,7 +50,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -93,6 +93,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->eip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 96088f781d68be2bf44e5e745e1f023ea99d3ca1..0c3a1e21737f4a902fb81c8a848883ed8a6f3514 100644 (file)
@@ -60,7 +60,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -103,6 +103,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->rip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 48336c0aff9a15225ee230807af31af6f53fa15d..31444a72433a3b0afea99b64c6ca9513e9ea1b47 100644 (file)
@@ -57,7 +57,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -101,6 +101,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%x\n", r->arm_pc);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 756abe3f5c27f955418ee94ec4fa3ebefbcc4548..34fa90bb2492408ef00308ce87db000a9c9d10f3 100644 (file)
@@ -53,7 +53,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // We need to pass arguments out of band since
@@ -96,6 +96,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", mc->__gregs[REG_EIP]);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 556a7be8b056eca0a2b5ced180c389126e3fc8df..e9e1eaa557cabfd7600f5e214f2b20c6ca8f6fdf 100644 (file)
@@ -61,7 +61,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // We need to pass arguments out of band since augmenting the
@@ -103,6 +103,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", mc->__gregs[REG_RIP]);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index dd2f7c9117f6329d7c1e7138a6a061f4afd6d417..bd040bd0eb9d258dbaced4df1bc2a859a917cd65 100644 (file)
@@ -50,7 +50,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -93,6 +93,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->sc_eip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index eb8f0e2edd06d1da63592aff5cb35d5a64418064..3fdd3fbd18381308c2e2e13d711b61691a43a66e 100644 (file)
@@ -59,7 +59,7 @@ runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
 
        t = &runtime·sigtab[sig];
        if(info->si_code != SI_USER && (t->flags & SigPanic)) {
-               if(gp == nil)
+               if(gp == nil || gp == m->g0)
                        goto Throw;
                // Make it look like a call to the signal func.
                // Have to pass arguments out of band since
@@ -102,6 +102,10 @@ Throw:
                runtime·printf("%s\n", runtime·sigtab[sig].name);
 
        runtime·printf("PC=%X\n", r->sc_rip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index a248374dbd7784e56ac128598ab6f48b9827072c..fc2a2459a049bbd7d9fb97ac0005a69ab7542f3b 100644 (file)
@@ -68,6 +68,10 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
                info->ExceptionInformation[0], info->ExceptionInformation[1]);
 
        runtime·printf("PC=%x\n", r->Eip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 1cdf1cac4c91106af39063c585261412f7c44323..3729aa57b76f8601e2d5dae99801a6fa76051179 100644 (file)
@@ -75,6 +75,10 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
                info->ExceptionInformation[0], info->ExceptionInformation[1]);
 
        runtime·printf("PC=%X\n", r->Rip);
+       if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+               runtime·printf("signal arrived during cgo execution\n");
+               gp = m->lockedg;
+       }
        runtime·printf("\n");
 
        if(runtime·gotraceback()){
index 6082f6acd0d1ede770f3a9b4cd41137908693832..fd60490ae4077875e6ef3719161a62d9022bef66 100644 (file)
@@ -202,6 +202,12 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
 void
 runtime·traceback(byte *pc0, byte *sp, byte *lr, G *gp)
 {
+       if(gp->status == Gsyscall) {
+               // Override signal registers if blocked in system call.
+               pc0 = gp->sched.pc;
+               sp = (byte*)gp->sched.sp;
+               lr = nil;
+       }
        runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100);
 }
 
index 180accb10d7dd90a43d6557182e0cc357331c45e..798be388f38e1b1168b547107620fe5765656f06 100644 (file)
@@ -207,6 +207,11 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
 void
 runtime·traceback(byte *pc0, byte *sp, byte*, G *gp)
 {
+       if(gp->status == Gsyscall) {
+               // Override signal registers if blocked in system call.
+               pc0 = gp->sched.pc;
+               sp = (byte*)gp->sched.sp;
+       }
        runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100);
 }