]> Cypherpunks repositories - gostls13.git/commitdiff
runtime/cgo: fix deadlock involving signals on darwin
authorDmitriy Vyukov <dvyukov@google.com>
Mon, 25 Feb 2013 21:36:29 +0000 (16:36 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 25 Feb 2013 21:36:29 +0000 (16:36 -0500)
sigprocmask() is process-wide on darwin, so two concurrent
libcgo_sys_thread_start() can result in all signals permanently
blocked, which in particular blocks handling of nil derefs.
Fixes #4833.

R=golang-dev, dave, rsc
CC=golang-dev
https://golang.org/cl/7324058

src/pkg/runtime/cgo/gcc_darwin_386.c
src/pkg/runtime/cgo/gcc_darwin_amd64.c
src/pkg/runtime/crash_test.go

index 2c30c666fc44ad14f44355e8a55e27f8230790d1..20a03959751a4d6bfbb4c03d8c65ab334011753b 100644 (file)
@@ -127,14 +127,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
        int err;
 
        sigfillset(&ign);
-       sigprocmask(SIG_SETMASK, &ign, &oset);
+       pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
        pthread_attr_init(&attr);
        pthread_attr_getstacksize(&attr, &size);
        ts->g->stackguard = size;
        err = pthread_create(&p, &attr, threadentry, ts);
 
-       sigprocmask(SIG_SETMASK, &oset, nil);
+       pthread_sigmask(SIG_SETMASK, &oset, nil);
 
        if (err != 0) {
                fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
index 89dc7a4e8ebfac8577d4f3b187a4dd4a0c151938..1c3fe0968c34424c8cb8ccbd586cbf79e72b8c1e 100644 (file)
@@ -97,14 +97,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
        int err;
 
        sigfillset(&ign);
-       sigprocmask(SIG_SETMASK, &ign, &oset);
+       pthread_sigmask(SIG_SETMASK, &ign, &oset);
 
        pthread_attr_init(&attr);
        pthread_attr_getstacksize(&attr, &size);
        ts->g->stackguard = size;
        err = pthread_create(&p, &attr, threadentry, ts);
 
-       sigprocmask(SIG_SETMASK, &oset, nil);
+       pthread_sigmask(SIG_SETMASK, &oset, nil);
 
        if (err != 0) {
                fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
index b2db1d7b95c93dccf07a485e07da440497c150f4..90a5e099a3e73dfad057c085f9f89769028711c6 100644 (file)
@@ -99,6 +99,14 @@ func TestLockedDeadlock2(t *testing.T) {
        testDeadlock(t, lockedDeadlockSource2)
 }
 
+func TestCgoSignalDeadlock(t *testing.T) {
+       got := executeTest(t, cgoSignalDeadlockSource, nil)
+       want := "OK\n"
+       if got != want {
+               t.Fatalf("expected %q, but got %q", want, got)
+       }
+}
+
 const crashSource = `
 package main
 
@@ -183,3 +191,68 @@ func main() {
        select {}
 }
 `
+
+const cgoSignalDeadlockSource = `
+package main
+
+import "C"
+
+import (
+       "fmt"
+       "runtime"
+       "time"
+)
+
+func main() {
+       runtime.GOMAXPROCS(100)
+       ping := make(chan bool)
+       go func() {
+               for i := 0; ; i++ {
+                       runtime.Gosched()
+                       select {
+                       case done := <-ping:
+                               if done {
+                                       ping <- true
+                                       return
+                               }
+                               ping <- true
+                       default:
+                       }
+                       func() {
+                               defer func() {
+                                       recover()
+                               }()
+                               var s *string
+                               *s = ""
+                       }()
+               }
+       }()
+       time.Sleep(time.Millisecond)
+       for i := 0; i < 64; i++ {
+               go func() {
+                       runtime.LockOSThread()
+                       select {}
+               }()
+               go func() {
+                       runtime.LockOSThread()
+                       select {}
+               }()
+               time.Sleep(time.Millisecond)
+               ping <- false
+               select {
+               case <-ping:
+               case <-time.After(time.Second):
+                       fmt.Printf("HANG\n")
+                       return
+               }
+       }
+       ping <- true
+       select {
+       case <-ping:
+       case <-time.After(time.Second):
+               fmt.Printf("HANG\n")
+               return
+       }
+       fmt.Printf("OK\n")
+}
+`