From a5b693b431d0612b97a8978fdfa7d12310d95b6f Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Fri, 24 Apr 2015 12:47:46 -0400 Subject: [PATCH] runtime: signal forwarding for darwin/amd64 Follows the linux signal forwarding semantics from http://golang.org/cl/8712, sharing the implementation of sigfwdgo. Forwarding for 386, arm, and arm64 will follow. Change-Id: I6bf30d563d19da39b6aec6900c7fe12d82ed4f62 Reviewed-on: https://go-review.googlesource.com/9302 Reviewed-by: Ian Lance Taylor --- src/runtime/os_dragonfly.go | 3 ++ src/runtime/os_freebsd.go | 3 ++ src/runtime/os_nacl.go | 4 +++ src/runtime/os_netbsd.go | 5 +++ src/runtime/os_openbsd.go | 5 +++ src/runtime/os_solaris.go | 3 ++ src/runtime/signal_darwin.go | 26 ++++++++++++++ src/runtime/signal_linux.go | 34 ------------------ src/runtime/signal_unix.go | 36 ++++++++++++++++++- src/runtime/sys_darwin_amd64.s | 63 ++++++++++++---------------------- 10 files changed, 106 insertions(+), 76 deletions(-) diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go index 8cffd2b9fd..60234bbdea 100644 --- a/src/runtime/os_dragonfly.go +++ b/src/runtime/os_dragonfly.go @@ -12,6 +12,9 @@ func lwp_create(param *lwpparams) int32 //go:noescape func sigaltstack(new, old *sigaltstackt) +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) + //go:noescape func sigaction(sig int32, new, old *sigactiont) diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go index c274b39d92..b2b5cd1f3f 100644 --- a/src/runtime/os_freebsd.go +++ b/src/runtime/os_freebsd.go @@ -12,6 +12,9 @@ func thr_new(param *thrparam, size int32) //go:noescape func sigaltstack(new, old *stackt) +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) + //go:noescape func sigaction(sig int32, new, old *sigactiont) diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go index efa8fa12b9..3b4c13606f 100644 --- a/src/runtime/os_nacl.go +++ b/src/runtime/os_nacl.go @@ -50,6 +50,10 @@ func sigpanic() { panicmem() } +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) { + throw("sigfwd not implemented") +} + func raiseproc(sig int32) { } diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go index 4fa4a416bd..b542b41b92 100644 --- a/src/runtime/os_netbsd.go +++ b/src/runtime/os_netbsd.go @@ -15,6 +15,11 @@ func sigaction(sig int32, new, old *sigactiont) //go:noescape func sigaltstack(new, old *sigaltstackt) +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) { + throw("sigfwd not implemented") +} + //go:noescape func sigprocmask(mode int32, new, old *sigset) diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go index 8a97a738f7..f94b490285 100644 --- a/src/runtime/os_openbsd.go +++ b/src/runtime/os_openbsd.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + //go:noescape func setitimer(mode int32, new, old *itimerval) @@ -13,6 +15,9 @@ func sigaction(sig int32, new, old *sigactiont) //go:noescape func sigaltstack(new, old *stackt) +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) + //go:noescape func sigprocmask(mode int32, new uint32) uint32 diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go index 6864ef9383..b30270eee3 100644 --- a/src/runtime/os_solaris.go +++ b/src/runtime/os_solaris.go @@ -10,6 +10,9 @@ type libcFunc uintptr var asmsysvicall6 libcFunc +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) + //go:nosplit func sysvicall0(fn libcFunc) uintptr { libcall := &getg().m.libcall diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go index 122648bc33..32ecce0d7d 100644 --- a/src/runtime/signal_darwin.go +++ b/src/runtime/signal_darwin.go @@ -4,6 +4,8 @@ package runtime +import "unsafe" + type sigTabT struct { flags int32 name string @@ -43,3 +45,27 @@ var sigtable = [...]sigTabT{ /* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"}, /* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"}, } + +//go:noescape +func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) + +//go:noescape +func sigreturn(ctx unsafe.Pointer, infostyle uint32) + +//go:nosplit +func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) { + if sigfwdgo(sig, info, ctx) { + sigreturn(ctx, infostyle) + return + } + g := getg() + if g == nil { + badsignal(uintptr(sig)) + sigreturn(ctx, infostyle) + return + } + setg(g.m.gsignal) + sighandler(sig, info, ctx, g) + setg(g) + sigreturn(ctx, infostyle) +} diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go index 1ab4e9ec71..f8250b9fa1 100644 --- a/src/runtime/signal_linux.go +++ b/src/runtime/signal_linux.go @@ -79,40 +79,6 @@ var sigtable = [...]sigTabT{ /* 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) { diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 8834e51f4b..ad3ab31c01 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -6,9 +6,43 @@ package runtime -import _ "unsafe" // for go:linkname +import "unsafe" //go:linkname os_sigpipe os.sigpipe func os_sigpipe() { systemstack(sigpipe) } + +// 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 +} diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s index bcb752a210..692dbca580 100644 --- a/src/runtime/sys_darwin_amd64.s +++ b/src/runtime/sys_darwin_amd64.s @@ -200,7 +200,7 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$0 MOVL $0xf1, 0xf1 // crash RET -TEXT runtime·sigaction(SB),NOSPLIT,$0 +TEXT runtime·sigaction(SB),NOSPLIT,$0-24 MOVL mode+0(FP), DI // arg 1 sig MOVQ new+8(FP), SI // arg 2 act MOVQ old+16(FP), DX // arg 3 oact @@ -212,48 +212,29 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0 MOVL $0xf1, 0xf1 // crash RET -TEXT runtime·sigtramp(SB),NOSPLIT,$64 - get_tls(BX) - - MOVQ R8, 32(SP) // save ucontext - MOVQ SI, 40(SP) // save infostyle - - // check that g exists - MOVQ g(BX), R10 - CMPQ R10, $0 - JNE 5(PC) - MOVL DX, 0(SP) - MOVQ $runtime·badsignal(SB), AX - CALL AX - JMP ret - - // save g - MOVQ R10, 48(SP) - - // g = m->gsignal - MOVQ g_m(R10), BP - MOVQ m_gsignal(BP), BP - MOVQ BP, g(BX) - - MOVL DX, 0(SP) - MOVQ CX, 8(SP) - MOVQ R8, 16(SP) - MOVQ R10, 24(SP) - - CALL DI - - // restore g - get_tls(BX) - MOVQ 48(SP), R10 - MOVQ R10, g(BX) +TEXT runtime·sigfwd(SB),NOSPLIT,$0-32 + MOVQ fn+0(FP), AX + MOVQ sig+8(FP), DI + MOVQ info+16(FP), SI + MOVQ ctx+24(FP), DX + CALL AX + RET -ret: - // call sigreturn - MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) - MOVQ 32(SP), DI // saved ucontext - MOVQ 40(SP), SI // saved infostyle +TEXT runtime·sigreturn(SB),NOSPLIT,$0-12 + MOVQ ctx+0(FP), DI + MOVL infostyle+8(FP), SI + MOVL $(0x2000000+184), AX SYSCALL - INT $3 // not reached + INT $3 // not reached + +TEXT runtime·sigtramp(SB),NOSPLIT,$32 + MOVQ DI, 0(SP) // fn + MOVL SI, 8(SP) // infostyle + MOVL DX, 12(SP) // sig + MOVQ CX, 16(SP) // info + MOVQ R8, 24(SP) // ctx + MOVQ $runtime·sigtrampgo(SB), AX + CALL AX TEXT runtime·mmap(SB),NOSPLIT,$0 MOVQ addr+0(FP), DI // arg 1 addr -- 2.50.0