}
}
+func TestCgoExternalThreadSignal(t *testing.T) {
+ // issue 10139
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("no pthreads on %s", runtime.GOOS)
+ }
+ got := executeTest(t, cgoExternalThreadSignalSource, nil)
+ want := "OK\n"
+ if got != want {
+ t.Fatalf("expected %q, but got %q", want, got)
+ }
+}
+
func TestCgoDLLImports(t *testing.T) {
// test issue 9356
if runtime.GOOS != "windows" {
}
`
+const cgoExternalThreadSignalSource = `
+package main
+
+/*
+#include <pthread.h>
+
+void **nullptr;
+
+void *crash(void *p) {
+ *nullptr = p;
+ return 0;
+}
+
+int start_crashing_thread(void) {
+ pthread_t tid;
+ return pthread_create(&tid, 0, crash, 0);
+}
+*/
+import "C"
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "time"
+)
+
+func main() {
+ if len(os.Args) > 1 && os.Args[1] == "crash" {
+ i := C.start_crashing_thread()
+ if i != 0 {
+ fmt.Println("pthread_create failed:", i)
+ // Exit with 0 because parent expects us to crash.
+ return
+ }
+
+ // We should crash immediately, but give it plenty of
+ // time before failing (by exiting 0) in case we are
+ // running on a slow system.
+ time.Sleep(5 * time.Second)
+ return
+ }
+
+ out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
+ if err == nil {
+ fmt.Println("C signal did not crash as expected\n")
+ fmt.Printf("%s\n", out)
+ os.Exit(1)
+ }
+
+ fmt.Println("OK")
+}
+`
+
const cgoDLLImportsMainSource = `
package main
func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, &m[0], nil)
}
+
+func unblocksig(sig int32) {
+ mask := uint32(1) << (uint32(sig) - 1)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
}
var oset sigset
- sigprocmask(&sigset_all, &oset)
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
params := lwpparams{
start_func: funcPC(lwp_start),
mp.tls[0] = uintptr(mp.id) // XXX so 386 asm can find it
lwp_create(¶ms)
- sigprocmask(&oset, nil)
+ sigprocmask(_SIG_SETMASK, &oset, nil)
}
func osinit() {
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
- sigprocmask(nil, smask)
+ sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m).
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
- sigprocmask(&nmask, nil)
+ sigprocmask(_SIG_SETMASK, &nmask, nil)
}
// Called from dropm to undo the effect of an minit.
func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
- sigprocmask(smask, nil)
+ sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil)
}
func updatesigmask(m sigmask) {
var mask sigset
copy(mask.__bits[:], m[:])
- sigprocmask(&mask, nil)
+ sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+ var mask sigset
+ mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
}
mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
var oset sigset
- sigprocmask(&sigset_all, &oset)
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
thr_new(¶m, int32(unsafe.Sizeof(param)))
- sigprocmask(&oset, nil)
+ sigprocmask(_SIG_SETMASK, &oset, nil)
}
func osinit() {
if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
throw("insufficient storage for signal mask")
}
- sigprocmask(nil, smask)
+ sigprocmask(_SIG_SETMASK, nil, smask)
}
// Called to initialize a new m (including the bootstrap m).
nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
}
}
- sigprocmask(&nmask, nil)
+ sigprocmask(_SIG_SETMASK, &nmask, nil)
}
// Called from dropm to undo the effect of an minit.
func unminit() {
_g_ := getg()
smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
- sigprocmask(smask, nil)
+ sigprocmask(_SIG_SETMASK, smask, nil)
signalstack(nil)
}
func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
var mask sigset
copy(mask.__bits[:], m[:])
- sigprocmask(&mask, nil)
+ sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+ var mask sigset
+ mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
}
copy(mask[:], m[:])
rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
}
+
+func unblocksig(sig int32) {
+ var mask sigset
+ mask[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
+}
var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
+func raisebadsignal(sig int32) {
+ badsignal2()
+}
+
func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
func munmap(addr unsafe.Pointer, n uintptr) {}
func resetcpuprofiler(hz int32) {}
copy(mask.__bits[:], m[:])
sigprocmask(_SIG_SETMASK, &mask, nil)
}
+
+func unblocksig(sig int32) {
+ var mask sigset
+ mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
func updatesigmask(m sigmask) {
sigprocmask(_SIG_SETMASK, m[0])
}
+
+func unblocksig(sig int32) {
+ mask := uint32(1) << (uint32(sig) - 1)
+ sigprocmask(_SIG_UNBLOCK, mask)
+}
exits(&_badsignal[0])
}
+func raisebadsignal(sig int32) {
+ badsignal2()
+}
+
func _atoi(b []byte) int {
n := 0
for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
package runtime
const (
- _NSIG = 33
- _SI_USER = 0x10001
- _SS_DISABLE = 4
- _RLIMIT_AS = 10
+ _NSIG = 33
+ _SI_USER = 0x10001
+ _SS_DISABLE = 4
+ _RLIMIT_AS = 10
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
)
package runtime
const (
- _SS_DISABLE = 4
- _NSIG = 33
- _SI_USER = 0x10001
- _RLIMIT_AS = 10
+ _SS_DISABLE = 4
+ _NSIG = 33
+ _SI_USER = 0x10001
+ _RLIMIT_AS = 10
+ _SIG_BLOCK = 1
+ _SIG_UNBLOCK = 2
+ _SIG_SETMASK = 3
)
_SS_DISABLE = 2
_NSIG = 65
_SI_USER = 0
+ _SIG_BLOCK = 0
+ _SIG_UNBLOCK = 1
_SIG_SETMASK = 2
_RLIMIT_AS = 9
)
const (
_SS_DISABLE = 2
+ _SIG_UNBLOCK = 2
_SIG_SETMASK = 3
_NSIG = 73 /* number of signals in sigtable array */
_SI_USER = 0
sigprocmask(_SIG_SETMASK, &mask, nil)
}
+func unblocksig(sig int32) {
+ var mask sigset
+ mask.__sigbits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+ sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
+
//go:nosplit
func semacreate() uintptr {
var sem *semt
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
//go:noescape
-func sigprocmask(sig uint32, new, old *uint32)
+func sigprocmask(how uint32, new, old *uint32)
//go:noescape
func sigaction(mode uint32, new, old *sigactiont)
func sigaction(sig int32, new, old *sigactiont)
//go:noescape
-func sigprocmask(new, old *sigset)
+func sigprocmask(how int32, new, old *sigset)
//go:noescape
func setitimer(mode int32, new, old *itimerval)
func sigaction(sig int32, new, old *sigactiont)
//go:noescape
-func sigprocmask(new, old *sigset)
+func sigprocmask(how int32, new, old *sigset)
//go:noescape
func setitimer(mode int32, new, old *itimerval)
//go:noescape
func getrlimit(kind int32, limit unsafe.Pointer) int32
-func raise(sig uint32)
-func raiseproc(sig uint32)
+func raise(sig int32)
+func raiseproc(sig int32)
//go:noescape
func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
raise(_SIGPIPE)
}
+// raisebadsignal is called when a signal is received on a non-Go
+// thread, and the Go program does not want to handle it (that is, the
+// program has not called os/signal.Notify for the signal).
+func raisebadsignal(sig int32) {
+ if sig == _SIGPROF {
+ // Ignore profiling signals that arrive on non-Go threads.
+ return
+ }
+
+ var handler uintptr
+ if sig >= _NSIG {
+ handler = _SIG_DFL
+ } else {
+ handler = fwdSig[sig]
+ }
+
+ // Reset the signal handler and raise the signal.
+ // We are currently running inside a signal handler, so the
+ // signal is blocked. We need to unblock it before raising the
+ // signal, or the signal we raise will be ignored until we return
+ // from the signal handler. We know that the signal was unblocked
+ // before entering the handler, or else we would not have received
+ // it. That means that we don't have to worry about blocking it
+ // again.
+ unblocksig(sig)
+ setsig(sig, handler, false)
+ raise(sig)
+
+ // If the signal didn't cause the program to exit, restore the
+ // Go signal handler and carry on.
+ //
+ // We may receive another instance of the signal before we
+ // restore the Go handler, but that is not so bad: we know
+ // that the Go program has been ignoring the signal.
+ setsig(sig, funcPC(sighandler), true)
+}
+
func crash() {
if GOOS == "darwin" {
// OS X core dumps are linear dumps of the mapped memory,
func sigignore(sig uint32) {
}
+func badsignal2()
+
+func raisebadsignal(sig int32) {
+ badsignal2()
+}
+
func crash() {
// TODO: This routine should do whatever is needed
// to make the Windows program abort/crash as it
// This runs on a foreign stack, without an m or a g. No stack split.
//go:nosplit
func badsignal(sig uintptr) {
- cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+ cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+}
+
+func badsignalgo(sig uintptr) {
+ if !sigsend(uint32(sig)) {
+ // A foreign thread received the signal sig, and the
+ // Go code does not want to handle it.
+ raisebadsignal(int32(sig))
+ }
}
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL $3, DI // arg 1 - how (SIG_SETMASK)
- MOVQ new+0(FP), SI // arg 2 - set
- MOVQ old+8(FP), DX // arg 3 - oset
+ MOVL how+0(FP), DI // arg 1 - how
+ MOVQ new+8(FP), SI // arg 2 - set
+ MOVQ old+16(FP), DX // arg 3 - oset
MOVL $340, AX // sys_sigprocmask
SYSCALL
JAE 2(PC)
TEXT runtime·sigprocmask(SB),NOSPLIT,$16
MOVL $0, 0(SP) // syscall gap
- MOVL $3, 4(SP) // arg 1 - how (SIG_SETMASK)
- MOVL new+0(FP), AX
+ MOVL how+0(FP), AX // arg 1 - how
+ MOVL AX, 4(SP)
+ MOVL new+4(FP), AX
MOVL AX, 8(SP) // arg 2 - set
- MOVL old+4(FP), AX
+ MOVL old+8(FP), AX
MOVL AX, 12(SP) // arg 3 - oset
MOVL $340, AX // sys_sigprocmask
INT $0x80
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL $3, DI // arg 1 - how (SIG_SETMASK)
- MOVQ new+0(FP), SI // arg 2 - set
- MOVQ old+8(FP), DX // arg 3 - oset
+ MOVL how+0(FP), DI // arg 1 - how
+ MOVQ new+8(FP), SI // arg 2 - set
+ MOVQ old+16(FP), DX // arg 3 - oset
MOVL $340, AX // sys_sigprocmask
SYSCALL
JAE 2(PC)
RET
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW $3, R0 // arg 1 - how (SIG_SETMASK)
- MOVW new+0(FP), R1 // arg 2 - set
- MOVW old+4(FP), R2 // arg 3 - oset
+ MOVW how+0(FP), R0 // arg 1 - how
+ MOVW new+4(FP), R1 // arg 2 - set
+ MOVW old+8(FP), R2 // arg 3 - oset
MOVW $SYS_sigprocmask, R7
SWI $0
MOVW.CS $0, R8 // crash on syscall failure
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
- MOVQ sig+8(FP), DI
+ MOVL sig+8(FP), DI
MOVQ info+16(FP), SI
MOVQ ctx+24(FP), DX
MOVQ fn+0(FP), AX