--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "fmt"
+
+/*
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+static void sigsegv() {
+ *p = 1;
+ fprintf(stderr, "ERROR: C SIGSEGV not thrown on caught?.\n");
+ exit(2);
+}
+
+static void sighandler(int signum) {
+ if (signum == SIGSEGV) {
+ exit(0); // success
+ }
+}
+
+static void __attribute__ ((constructor)) sigsetup(void) {
+ struct sigaction act;
+ act.sa_handler = &sighandler;
+ sigaction(SIGSEGV, &act, 0);
+}
+*/
+import "C"
+
+var p *byte
+
+func f() (ret bool) {
+ defer func() {
+ if recover() == nil {
+ fmt.Errorf("ERROR: couldn't raise SIGSEGV in Go.")
+ C.exit(2)
+ }
+ ret = true
+ }()
+ *p = 1
+ return false
+}
+
+func main() {
+ // Test that the signal originating in Go is handled (and recovered) by Go.
+ if !f() {
+ fmt.Errorf("couldn't recover from SIGSEGV in Go.")
+ C.exit(2)
+ }
+
+ // Test that the signal originating in C is handled by C.
+ C.sigsegv()
+}
if t.hasBash() && t.goos != "android" && !iOS && t.gohostos != "windows" {
t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash")
}
+ if t.gohostos == "linux" && t.extLink() {
+ t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
+ }
}
if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !iOS {
t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
//go:noescape
func sigaltstack(new, old *sigaltstackt)
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
//go:noescape
func setitimer(mode int32, new, old *itimerval)
_SIG_IGN uintptr = 1
)
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Linux.
+var fwdSig [_NSIG]uintptr
+
func initsig() {
// _NSIG is the number of signals on this operating system.
// sigtable should describe what to do for all the possible signals.
if t.flags == 0 || t.flags&_SigDefault != 0 {
continue
}
-
+ fwdSig[i] = getsig(i)
// For some signals, we respect an inherited SIG_IGN handler
// rather than insist on installing our own default handler.
// Even these signals can be fetched using the os/signal package.
package runtime
+import "unsafe"
+
type sigTabT struct {
flags int32
name string
/* 63 */ {_SigNotify, "signal 63"},
/* 64 */ {_SigNotify, "signal 64"},
}
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's. Returns whether the
+// signal was forwarded.
+//go:nosplit
+func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+ g := getg()
+ c := &sigctxt{info, ctx}
+ if sig >= uint32(len(sigtable)) {
+ return false
+ }
+ fwdFn := fwdSig[sig]
+ flags := sigtable[sig].flags
+
+ // If there is no handler to forward to, no need to forward.
+ if fwdFn == _SIG_DFL {
+ return false
+ }
+ // Only forward synchronous signals.
+ if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+ return false
+ }
+ // Determine if the signal occurred inside Go code. We test that:
+ // (1) we were in a goroutine (i.e., m.curg != nil), and
+ // (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+ if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+ return false
+ }
+ // Signal not handled by Go, forward it.
+ if fwdFn != _SIG_IGN {
+ sigfwd(fwdFn, sig, info, ctx)
+ }
+ return true
+}
+
+// Continuation of the (assembly) sigtramp() logic.
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+ if sigfwdgo(sig, info, ctx) {
+ return
+ }
+ g := getg()
+ if g == nil {
+ badsignal(uintptr(sig))
+ return
+ }
+ setg(g.m.gsignal)
+ sighandler(sig, info, ctx, g)
+ setg(g)
+}
MOVL AX, ret+16(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$44
- get_tls(CX)
-
- // check that g exists
- MOVL g(CX), DI
- CMPL DI, $0
- JNE 6(PC)
- MOVL sig+0(FP), BX
- MOVL BX, 0(SP)
- MOVL $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+ MOVL sig+4(FP), AX
+ MOVL AX, 0(SP)
+ MOVL info+8(FP), AX
+ MOVL AX, 4(SP)
+ MOVL ctx+12(FP), AX
+ MOVL AX, 8(SP)
+ MOVL fn+0(FP), AX
CALL AX
RET
- // save g
- MOVL DI, 20(SP)
-
- // g = m->gsignal
- MOVL g_m(DI), BX
- MOVL m_gsignal(BX), BX
- MOVL BX, g(CX)
-
- // copy arguments for call to sighandler
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
MOVL sig+0(FP), BX
MOVL BX, 0(SP)
MOVL info+4(FP), BX
MOVL BX, 4(SP)
MOVL context+8(FP), BX
MOVL BX, 8(SP)
- MOVL DI, 12(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(CX)
- MOVL 20(SP), BX
- MOVL BX, g(CX)
-
+ CALL runtime·sigtrampgo(SB)
RET
TEXT runtime·sigreturn(SB),NOSPLIT,$0
MOVL AX, ret+32(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
- get_tls(BX)
-
- // check that g exists
- MOVQ g(BX), R10
- CMPQ R10, $0
- JNE 5(PC)
- MOVQ DI, 0(SP)
- MOVQ $runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVQ sig+8(FP), DI
+ MOVQ info+16(FP), SI
+ MOVQ ctx+24(FP), DX
+ MOVQ fn+0(FP), AX
CALL AX
RET
- // save g
- MOVQ R10, 40(SP)
-
- // g = m->gsignal
- MOVQ g_m(R10), AX
- MOVQ m_gsignal(AX), AX
- MOVQ AX, g(BX)
-
- MOVQ DI, 0(SP)
- MOVQ SI, 8(SP)
- MOVQ DX, 16(SP)
- MOVQ R10, 24(SP)
-
- CALL runtime·sighandler(SB)
-
- // restore g
- get_tls(BX)
- MOVQ 40(SP), R10
- MOVQ R10, g(BX)
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+ MOVQ DI, 0(SP) // signum
+ MOVQ SI, 8(SP) // info
+ MOVQ DX, 16(SP) // ctx
+ MOVQ $runtime·sigtrampgo(SB), AX
+ CALL AX
RET
TEXT runtime·sigreturn(SB),NOSPLIT,$0
MOVW.HI R8, (R8)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+ MOVW sig+4(FP), R0
+ MOVW info+8(FP), R1
+ MOVW ctx+12(FP), R2
+ MOVW fn+0(FP), R11
+ BL (R11)
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
CMP $0, R0
BL.NE runtime·load_g(SB)
- CMP $0, g
- BNE 4(PC)
- // signal number is already prepared in 4(R13)
- MOVW $runtime·badsignal(SB), R11
- BL (R11)
- RET
-
- // save g
- MOVW g, R3
- MOVW g, 20(R13)
-
- // g = m->gsignal
- MOVW g_m(g), R8
- MOVW m_gsignal(R8), g
-
- // copy arguments for call to sighandler
- // R0 is already saved above
MOVW R1, 8(R13)
MOVW R2, 12(R13)
- MOVW R3, 16(R13)
-
- BL runtime·sighandler(SB)
-
- // restore g
- MOVW 20(R13), g
-
+ MOVW $runtime·sigtrampgo(SB), R11
+ BL (R11)
RET
TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
MOVW R0, ret+32(FP)
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVW sig+8(FP), R0
+ MOVD info+16(FP), R1
+ MOVD ctx+24(FP), R2
+ MOVD fn+0(FP), R11
+ BL (R11)
+ RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
// this might be called in external code context,
// where g is not set.
// first save R0, because runtime·load_g will clobber it
BEQ 2(PC)
BL runtime·load_g(SB)
- // check that g exists
- CMP g, ZR
- BNE ok
- MOVD $runtime·badsignal(SB), R0
- BL (R0)
- RET
-
-ok:
- // save g
- MOVD g, 40(RSP)
- MOVD g, R6
-
- // g = m->gsignal
- MOVD g_m(g), R7
- MOVD m_gsignal(R7), g
-
- // R0 is already saved above
MOVD R1, 16(RSP)
MOVD R2, 24(RSP)
- MOVD R6, 32(RSP)
-
- BL runtime·sighandler(SB)
-
- // restore g
- MOVD 40(RSP), g
+ MOVD $runtime·sigtrampgo(SB), R0
+ BL (R0)
RET
TEXT runtime·mmap(SB),NOSPLIT,$-8
MOVW R3, ret+32(FP)
RETURN
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+ MOVW sig+8(FP), R3
+ MOVD info+16(FP), R4
+ MOVD ctx+24(FP), R5
+ MOVD fn+0(FP), R31
+ MOVD R31, CTR
+ BL (CTR)
+ RETURN
+
#ifdef GOARCH_ppc64le
// ppc64le doesn't need function descriptors
TEXT runtime·sigtramp(SB),NOSPLIT,$64
BEQ 2(PC)
BL runtime·load_g(SB)
- // check that g exists
- CMP g, $0
- BNE 6(PC)
- MOVD R3, 8(R1)
- MOVD $runtime·badsignal(SB), R31
- MOVD R31, CTR
- BL (CTR)
- RETURN
-
- // save g
- MOVD g, 40(R1)
- MOVD g, R6
-
- // g = m->gsignal
- MOVD g_m(g), R7
- MOVD m_gsignal(R7), g
-
MOVW R3, 8(R1)
MOVD R4, 16(R1)
MOVD R5, 24(R1)
- MOVD R6, 32(R1)
-
- BL runtime·sighandler(SB)
-
- // restore g
- MOVD 40(R1), g
-
+ MOVD $runtime·sigtrampgo(SB), R31
+ MOVD R31, CTR
+ BL (CTR)
RETURN
TEXT runtime·mmap(SB),NOSPLIT,$-8