mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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
3 changed files with 77 additions and 4 deletions
|
|
@ -127,14 +127,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sigfillset(&ign);
|
sigfillset(&ign);
|
||||||
sigprocmask(SIG_SETMASK, &ign, &oset);
|
pthread_sigmask(SIG_SETMASK, &ign, &oset);
|
||||||
|
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_getstacksize(&attr, &size);
|
pthread_attr_getstacksize(&attr, &size);
|
||||||
ts->g->stackguard = size;
|
ts->g->stackguard = size;
|
||||||
err = pthread_create(&p, &attr, threadentry, ts);
|
err = pthread_create(&p, &attr, threadentry, ts);
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oset, nil);
|
pthread_sigmask(SIG_SETMASK, &oset, nil);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
|
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
|
||||||
|
|
|
||||||
|
|
@ -97,14 +97,14 @@ libcgo_sys_thread_start(ThreadStart *ts)
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
sigfillset(&ign);
|
sigfillset(&ign);
|
||||||
sigprocmask(SIG_SETMASK, &ign, &oset);
|
pthread_sigmask(SIG_SETMASK, &ign, &oset);
|
||||||
|
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
pthread_attr_getstacksize(&attr, &size);
|
pthread_attr_getstacksize(&attr, &size);
|
||||||
ts->g->stackguard = size;
|
ts->g->stackguard = size;
|
||||||
err = pthread_create(&p, &attr, threadentry, ts);
|
err = pthread_create(&p, &attr, threadentry, ts);
|
||||||
|
|
||||||
sigprocmask(SIG_SETMASK, &oset, nil);
|
pthread_sigmask(SIG_SETMASK, &oset, nil);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
|
fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,14 @@ func TestLockedDeadlock2(t *testing.T) {
|
||||||
testDeadlock(t, lockedDeadlockSource2)
|
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 = `
|
const crashSource = `
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|
@ -183,3 +191,68 @@ func main() {
|
||||||
select {}
|
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…
Add table
Add a link
Reference in a new issue