Skip to content

Commit

Permalink
runtime: use libc's signal functions on Darwin
Browse files Browse the repository at this point in the history
sigaction, sigprocmask, sigaltstack, and raiseproc.

Fix bug in mstart_stub where we weren't saving callee-saved registers,
so if an m finished the pthread library calling mstart_stub would
sometimes fail.

Update #17490
Update #22805

Change-Id: Ie297ede0997910aa956834e49e85711b90cdfaa7
Reviewed-on: https://go-review.googlesource.com/116875
Run-TryBot: Ian Lance Taylor <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
randall77 committed Jun 12, 2018
1 parent adeb7e6 commit ec98933
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 118 deletions.
1 change: 1 addition & 0 deletions src/runtime/defs_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ type Sighandler C.union___sigaction_u

type Sigaction C.struct___sigaction // used in syscalls
type Usigaction C.struct_sigaction // used by sigaction second argument
type Sigset C.sigset_t
type Sigval C.union_sigval
type Siginfo C.siginfo_t
type Timeval C.struct_timeval
Expand Down
29 changes: 9 additions & 20 deletions src/runtime/os_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ func mpreinit(mp *m) {
func minit() {
// The alternate signal stack is buggy on arm and arm64.
// The signal handler handles it directly.
// The sigaltstack assembly function does nothing.
if GOARCH != "arm" && GOARCH != "arm64" {
minitSignalStack()
}
Expand Down Expand Up @@ -499,24 +498,9 @@ const (
_SS_DISABLE = 4
)

//go:noescape
func sigprocmask(how int32, new, old *sigset)

//go:noescape
func sigaction(mode uint32, new *sigactiont, old *usigactiont)

//go:noescape
func sigaltstack(new, old *stackt)

// darwin/arm64 uses registers instead of stack-based arguments.
// TODO: does this matter?
func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer)

//go:noescape
func setitimer(mode int32, new, old *itimerval)

func raiseproc(sig uint32)

//extern SigTabTT runtime·sigtab[];

type sigset uint32
Expand All @@ -526,14 +510,20 @@ var sigset_all = ^sigset(0)
//go:nosplit
//go:nowritebarrierrec
func setsig(i uint32, fn uintptr) {
var sa sigactiont
var sa usigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = ^uint32(0)
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
if fn == funcPC(sighandler) {
fn = funcPC(sigtramp)
}
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
sigaction(i, &sa, nil)
}

// sigtramp is the callback from libc when a signal is received.
// It is called with the C calling convention.
func sigtramp()

//go:nosplit
//go:nowritebarrierrec
func setsigstack(i uint32) {
Expand All @@ -543,9 +533,8 @@ func setsigstack(i uint32) {
if osa.sa_flags&_SA_ONSTACK != 0 {
return
}
var sa sigactiont
var sa usigactiont
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
sa.sa_mask = osa.sa_mask
sa.sa_flags = osa.sa_flags | _SA_ONSTACK
sigaction(i, &sa, nil)
Expand Down
40 changes: 40 additions & 0 deletions src/runtime/sys_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,41 @@ func walltime() (int64, int32) {
}
func walltime_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
asmcgocall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig))
}
func sigaction_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func sigprocmask(how uint32, new *sigset, old *sigset) {
asmcgocall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how))
}
func sigprocmask_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func sigaltstack(new *stackt, old *stackt) {
if new != nil && new.ss_flags&_SS_DISABLE != 0 && new.ss_size == 0 {
// Despite the fact that Darwin's sigaltstack man page says it ignores the size
// when SS_DISABLE is set, it doesn't. sigaltstack returns ENOMEM
// if we don't give it a reasonable size.
// ref: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140421/214296.html
new.ss_size = 32768
}
asmcgocall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new))
}
func sigaltstack_trampoline()

//go:nosplit
//go:cgo_unsafe_args
func raiseproc(sig uint32) {
asmcgocall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig))
}
func raiseproc_trampoline()

// Not used on Darwin, but must be defined.
func exitThread(wait *uint32) {
}
Expand Down Expand Up @@ -207,6 +242,11 @@ func exitThread(wait *uint32) {
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib"

// Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
Expand Down
151 changes: 102 additions & 49 deletions src/runtime/sys_darwin_386.s
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0
POPL BP
RET

TEXT runtime·raiseproc(SB),NOSPLIT,$16
MOVL $20, AX // getpid
INT $0x80
MOVL AX, 4(SP) // pid
MOVL sig+0(FP), AX
MOVL AX, 8(SP) // signal
MOVL $1, 12(SP) // posix
MOVL $37, AX // kill
INT $0x80
RET

TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
Expand Down Expand Up @@ -211,18 +200,73 @@ initialized:
POPL BP
RET

TEXT runtime·sigprocmask(SB),NOSPLIT,$0
MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
INT $0x80
JAE 2(PC)
TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $24, SP
MOVL 32(SP), CX
MOVL 0(CX), AX // arg 1 sig
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 new
MOVL AX, 4(SP)
MOVL 8(CX), AX // arg 3 old
MOVL AX, 8(SP)
CALL libc_sigaction(SB)
TESTL AX, AX
JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
MOVL BP, SP
POPL BP
RET

TEXT runtime·sigaction(SB),NOSPLIT,$0
MOVL $46, AX
INT $0x80
JAE 2(PC)
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $24, SP
MOVL 32(SP), CX
MOVL 0(CX), AX // arg 1 how
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 new
MOVL AX, 4(SP)
MOVL 8(CX), AX // arg 3 old
MOVL AX, 8(SP)
CALL libc_pthread_sigmask(SB)
TESTL AX, AX
JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
MOVL BP, SP
POPL BP
RET

TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
MOVL 16(SP), CX
MOVL 0(CX), AX // arg 1 new
MOVL AX, 0(SP)
MOVL 4(CX), AX // arg 2 old
MOVL AX, 4(SP)
CALL libc_sigaltstack(SB)
TESTL AX, AX
JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
MOVL BP, SP
POPL BP
RET

TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
SUBL $8, SP
CALL libc_getpid(SB)
MOVL AX, 0(SP) // arg 1 pid
MOVL 16(SP), CX
MOVL 0(CX), AX
MOVL AX, 4(SP) // arg 2 signal
CALL libc_kill(SB)
MOVL BP, SP
POPL BP
RET

TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
Expand All @@ -243,38 +287,32 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
RET

// Sigtramp's job is to call the actual signal handler.
// It is called with the following arguments on the stack:
// 0(SP) "return address" - ignored
// 4(SP) actual handler
// 8(SP) siginfo style
// 12(SP) signal number
// 16(SP) siginfo
// 20(SP) context
TEXT runtime·sigtramp(SB),NOSPLIT,$20
MOVL sig+8(FP), BX
MOVL BX, 0(SP)
MOVL info+12(FP), BX
MOVL BX, 4(SP)
MOVL ctx+16(FP), BX
MOVL BX, 8(SP)
// It is called with the C calling convention, and calls out
// to sigtrampgo with the Go calling convention.
TEXT runtime·sigtramp(SB),NOSPLIT,$0
SUBL $28, SP

// Save callee-save registers.
MOVL BP, 12(SP)
MOVL BX, 16(SP)
MOVL SI, 20(SP)
MOVL DI, 24(SP)

MOVL 32(SP), AX
MOVL AX, 0(SP) // arg 1 signal number
MOVL 36(SP), AX
MOVL AX, 4(SP) // arg 2 siginfo
MOVL 40(SP), AX
MOVL AX, 8(SP) // arg 3 ctxt
CALL runtime·sigtrampgo(SB)

// call sigreturn
MOVL ctx+16(FP), CX
MOVL infostyle+4(FP), BX
MOVL $0, 0(SP) // "caller PC" - ignored
MOVL CX, 4(SP)
MOVL BX, 8(SP)
MOVL $184, AX // sigreturn(ucontext, infostyle)
INT $0x80
MOVL $0xf1, 0xf1 // crash
RET
// Restore callee-save registers.
MOVL 12(SP), BP
MOVL 16(SP), BX
MOVL 20(SP), SI
MOVL 24(SP), DI

TEXT runtime·sigaltstack(SB),NOSPLIT,$0
MOVL $53, AX
INT $0x80
JAE 2(PC)
MOVL $0xf1, 0xf1 // crash
ADDL $28, SP
RET

TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
Expand Down Expand Up @@ -409,8 +447,15 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
// The value at SP+4 points to the m.
// We are already on m's g0 stack.

// Save callee-save registers.
SUBL $16, SP
MOVL BP, 0(SP)
MOVL BX, 4(SP)
MOVL SI, 8(SP)
MOVL DI, 12(SP)

MOVL SP, AX // hide argument read from vet (vet thinks this function is using the Go calling convention)
MOVL 4(AX), DI // m
MOVL 20(AX), DI // m
MOVL m_g0(DI), DX // g

// Initialize TLS entry.
Expand All @@ -422,10 +467,18 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0

CALL runtime·mstart(SB)

// Restore callee-save registers.
MOVL 0(SP), BP
MOVL 4(SP), BX
MOVL 8(SP), SI
MOVL 12(SP), DI

// Go is all done with this OS thread.
// Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX

ADDL $16, SP
RET

TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
Expand Down
Loading

0 comments on commit ec98933

Please sign in to comment.