diff options
| author | Srdjan Petrovic <spetrovic@google.com> | 2015-04-09 11:12:12 -0700 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2015-04-24 05:19:39 +0000 |
| commit | 5c8fbc6f1e4ba78133c53ce73f82ad10e81b42f8 (patch) | |
| tree | d6e877ab0831d38259d2cf332236354de74f205d /src/runtime | |
| parent | b075d1fc2eaacde75261969372fb3275ef694668 (diff) | |
| download | go-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.go | 3 | ||||
| -rw-r--r-- | src/runtime/signal1_unix.go | 10 | ||||
| -rw-r--r-- | src/runtime/signal_linux.go | 52 | ||||
| -rw-r--r-- | src/runtime/sys_linux_386.s | 38 | ||||
| -rw-r--r-- | src/runtime/sys_linux_amd64.s | 39 | ||||
| -rw-r--r-- | src/runtime/sys_linux_arm.s | 36 | ||||
| -rw-r--r-- | src/runtime/sys_linux_arm64.s | 35 | ||||
| -rw-r--r-- | src/runtime/sys_linux_ppc64x.s | 36 |
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 |
