mirror of
https://github.com/golang/go
synced 2024-11-26 16:57:14 -07:00
runtime/cgo: fix deadlock involving signals on darwin
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
This commit is contained in:
parent
052d845c5c
commit
4eb7ba743d
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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")
|
||||
}
|
||||
`
|
||||
|
Loading…
Reference in New Issue
Block a user