aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorSrdjan Petrovic <spetrovic@google.com>2015-04-09 11:12:12 -0700
committerIan Lance Taylor <iant@golang.org>2015-04-24 05:19:39 +0000
commit5c8fbc6f1e4ba78133c53ce73f82ad10e81b42f8 (patch)
treed6e877ab0831d38259d2cf332236354de74f205d /src/runtime
parentb075d1fc2eaacde75261969372fb3275ef694668 (diff)
downloadgo-5c8fbc6f1e4ba78133c53ce73f82ad10e81b42f8.tar.xz
runtime: signal forwarding
Forward signals to signal handlers installed before Go installs its own, under certain circumstances. In particular, as iant@ suggests, signals are forwarded iff: (1) a non-SIG_DFL signal handler existed before Go, and (2) signal is synchronous (i.e., one of SIGSEGV, SIGBUS, SIGFPE), and (3a) signal occured on a non-Go thread, or (3b) signal occurred on a Go thread but in CGo code. Supported only on Linux, for now. Change-Id: I403219ee47b26cf65da819fb86cf1ec04d3e25f5 Reviewed-on: https://go-review.googlesource.com/8712 Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/os_linux.go3
-rw-r--r--src/runtime/signal1_unix.go10
-rw-r--r--src/runtime/signal_linux.go52
-rw-r--r--src/runtime/sys_linux_386.s38
-rw-r--r--src/runtime/sys_linux_amd64.s39
-rw-r--r--src/runtime/sys_linux_arm.s36
-rw-r--r--src/runtime/sys_linux_arm64.s35
-rw-r--r--src/runtime/sys_linux_ppc64x.s36
8 files changed, 119 insertions, 130 deletions
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index abea5d61aa..523d28b210 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -19,6 +19,9 @@ func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
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)
//go:noescape
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
index 184fd125fb..7577d43a64 100644
--- a/src/runtime/signal1_unix.go
+++ b/src/runtime/signal1_unix.go
@@ -11,6 +11,14 @@ const (
_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.
@@ -25,7 +33,7 @@ func initsig() {
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.
diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go
index c71e619b1e..1ab4e9ec71 100644
--- a/src/runtime/signal_linux.go
+++ b/src/runtime/signal_linux.go
@@ -4,6 +4,8 @@
package runtime
+import "unsafe"
+
type sigTabT struct {
flags int32
name string
@@ -76,3 +78,53 @@ var sigtable = [...]sigTabT{
/* 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)
+}
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 679a81d66d..f5cfb644c9 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -191,43 +191,25 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
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
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index fa7fa164b5..f36ac8493b 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -212,37 +212,20 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-36
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
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index d0c6d22f31..3936cd93a8 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -327,7 +327,15 @@ TEXT runtime·sigaltstack(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
@@ -336,32 +344,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
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
diff --git a/src/runtime/sys_linux_arm64.s b/src/runtime/sys_linux_arm64.s
index 389fea0dde..0aca3a2010 100644
--- a/src/runtime/sys_linux_arm64.s
+++ b/src/runtime/sys_linux_arm64.s
@@ -215,7 +215,15 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
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
@@ -225,31 +233,10 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
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
diff --git a/src/runtime/sys_linux_ppc64x.s b/src/runtime/sys_linux_ppc64x.s
index 44a22c9c77..232f299ac2 100644
--- a/src/runtime/sys_linux_ppc64x.s
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -196,6 +196,15 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
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
@@ -217,33 +226,12 @@ 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