Skip to content

Commit ec98933

Browse files
committed
runtime: use libc's signal functions on Darwin
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]>
1 parent adeb7e6 commit ec98933

File tree

5 files changed

+244
-118
lines changed

5 files changed

+244
-118
lines changed

src/runtime/defs_darwin.go

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ type Sighandler C.union___sigaction_u
158158

159159
type Sigaction C.struct___sigaction // used in syscalls
160160
type Usigaction C.struct_sigaction // used by sigaction second argument
161+
type Sigset C.sigset_t
161162
type Sigval C.union_sigval
162163
type Siginfo C.siginfo_t
163164
type Timeval C.struct_timeval

src/runtime/os_darwin.go

+9-20
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ func mpreinit(mp *m) {
206206
func minit() {
207207
// The alternate signal stack is buggy on arm and arm64.
208208
// The signal handler handles it directly.
209-
// The sigaltstack assembly function does nothing.
210209
if GOARCH != "arm" && GOARCH != "arm64" {
211210
minitSignalStack()
212211
}
@@ -499,24 +498,9 @@ const (
499498
_SS_DISABLE = 4
500499
)
501500

502-
//go:noescape
503-
func sigprocmask(how int32, new, old *sigset)
504-
505-
//go:noescape
506-
func sigaction(mode uint32, new *sigactiont, old *usigactiont)
507-
508-
//go:noescape
509-
func sigaltstack(new, old *stackt)
510-
511-
// darwin/arm64 uses registers instead of stack-based arguments.
512-
// TODO: does this matter?
513-
func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer)
514-
515501
//go:noescape
516502
func setitimer(mode int32, new, old *itimerval)
517503

518-
func raiseproc(sig uint32)
519-
520504
//extern SigTabTT runtime·sigtab[];
521505

522506
type sigset uint32
@@ -526,14 +510,20 @@ var sigset_all = ^sigset(0)
526510
//go:nosplit
527511
//go:nowritebarrierrec
528512
func setsig(i uint32, fn uintptr) {
529-
var sa sigactiont
513+
var sa usigactiont
530514
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
531515
sa.sa_mask = ^uint32(0)
532-
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
516+
if fn == funcPC(sighandler) {
517+
fn = funcPC(sigtramp)
518+
}
533519
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
534520
sigaction(i, &sa, nil)
535521
}
536522

523+
// sigtramp is the callback from libc when a signal is received.
524+
// It is called with the C calling convention.
525+
func sigtramp()
526+
537527
//go:nosplit
538528
//go:nowritebarrierrec
539529
func setsigstack(i uint32) {
@@ -543,9 +533,8 @@ func setsigstack(i uint32) {
543533
if osa.sa_flags&_SA_ONSTACK != 0 {
544534
return
545535
}
546-
var sa sigactiont
536+
var sa usigactiont
547537
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
548-
sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
549538
sa.sa_mask = osa.sa_mask
550539
sa.sa_flags = osa.sa_flags | _SA_ONSTACK
551540
sigaction(i, &sa, nil)

src/runtime/sys_darwin.go

+40
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,41 @@ func walltime() (int64, int32) {
179179
}
180180
func walltime_trampoline()
181181

182+
//go:nosplit
183+
//go:cgo_unsafe_args
184+
func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
185+
asmcgocall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig))
186+
}
187+
func sigaction_trampoline()
188+
189+
//go:nosplit
190+
//go:cgo_unsafe_args
191+
func sigprocmask(how uint32, new *sigset, old *sigset) {
192+
asmcgocall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how))
193+
}
194+
func sigprocmask_trampoline()
195+
196+
//go:nosplit
197+
//go:cgo_unsafe_args
198+
func sigaltstack(new *stackt, old *stackt) {
199+
if new != nil && new.ss_flags&_SS_DISABLE != 0 && new.ss_size == 0 {
200+
// Despite the fact that Darwin's sigaltstack man page says it ignores the size
201+
// when SS_DISABLE is set, it doesn't. sigaltstack returns ENOMEM
202+
// if we don't give it a reasonable size.
203+
// ref: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140421/214296.html
204+
new.ss_size = 32768
205+
}
206+
asmcgocall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new))
207+
}
208+
func sigaltstack_trampoline()
209+
210+
//go:nosplit
211+
//go:cgo_unsafe_args
212+
func raiseproc(sig uint32) {
213+
asmcgocall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig))
214+
}
215+
func raiseproc_trampoline()
216+
182217
// Not used on Darwin, but must be defined.
183218
func exitThread(wait *uint32) {
184219
}
@@ -207,6 +242,11 @@ func exitThread(wait *uint32) {
207242
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
208243
//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
209244
//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib"
245+
//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
246+
//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
247+
//go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
248+
//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib"
249+
//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib"
210250

211251
// Magic incantation to get libSystem actually dynamically linked.
212252
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210

src/runtime/sys_darwin_386.s

+102-49
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0
8484
POPL BP
8585
RET
8686

87-
TEXT runtime·raiseproc(SB),NOSPLIT,$16
88-
MOVL $20, AX // getpid
89-
INT $0x80
90-
MOVL AX, 4(SP) // pid
91-
MOVL sig+0(FP), AX
92-
MOVL AX, 8(SP) // signal
93-
MOVL $1, 12(SP) // posix
94-
MOVL $37, AX // kill
95-
INT $0x80
96-
RET
97-
9887
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
9988
PUSHL BP
10089
MOVL SP, BP
@@ -211,18 +200,73 @@ initialized:
211200
POPL BP
212201
RET
213202

214-
TEXT runtime·sigprocmask(SB),NOSPLIT,$0
215-
MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
216-
INT $0x80
217-
JAE 2(PC)
203+
TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
204+
PUSHL BP
205+
MOVL SP, BP
206+
SUBL $24, SP
207+
MOVL 32(SP), CX
208+
MOVL 0(CX), AX // arg 1 sig
209+
MOVL AX, 0(SP)
210+
MOVL 4(CX), AX // arg 2 new
211+
MOVL AX, 4(SP)
212+
MOVL 8(CX), AX // arg 3 old
213+
MOVL AX, 8(SP)
214+
CALL libc_sigaction(SB)
215+
TESTL AX, AX
216+
JEQ 2(PC)
218217
MOVL $0xf1, 0xf1 // crash
218+
MOVL BP, SP
219+
POPL BP
219220
RET
220221

221-
TEXT runtime·sigaction(SB),NOSPLIT,$0
222-
MOVL $46, AX
223-
INT $0x80
224-
JAE 2(PC)
222+
TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
223+
PUSHL BP
224+
MOVL SP, BP
225+
SUBL $24, SP
226+
MOVL 32(SP), CX
227+
MOVL 0(CX), AX // arg 1 how
228+
MOVL AX, 0(SP)
229+
MOVL 4(CX), AX // arg 2 new
230+
MOVL AX, 4(SP)
231+
MOVL 8(CX), AX // arg 3 old
232+
MOVL AX, 8(SP)
233+
CALL libc_pthread_sigmask(SB)
234+
TESTL AX, AX
235+
JEQ 2(PC)
236+
MOVL $0xf1, 0xf1 // crash
237+
MOVL BP, SP
238+
POPL BP
239+
RET
240+
241+
TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
242+
PUSHL BP
243+
MOVL SP, BP
244+
SUBL $8, SP
245+
MOVL 16(SP), CX
246+
MOVL 0(CX), AX // arg 1 new
247+
MOVL AX, 0(SP)
248+
MOVL 4(CX), AX // arg 2 old
249+
MOVL AX, 4(SP)
250+
CALL libc_sigaltstack(SB)
251+
TESTL AX, AX
252+
JEQ 2(PC)
225253
MOVL $0xf1, 0xf1 // crash
254+
MOVL BP, SP
255+
POPL BP
256+
RET
257+
258+
TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
259+
PUSHL BP
260+
MOVL SP, BP
261+
SUBL $8, SP
262+
CALL libc_getpid(SB)
263+
MOVL AX, 0(SP) // arg 1 pid
264+
MOVL 16(SP), CX
265+
MOVL 0(CX), AX
266+
MOVL AX, 4(SP) // arg 2 signal
267+
CALL libc_kill(SB)
268+
MOVL BP, SP
269+
POPL BP
226270
RET
227271

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

245289
// Sigtramp's job is to call the actual signal handler.
246-
// It is called with the following arguments on the stack:
247-
// 0(SP) "return address" - ignored
248-
// 4(SP) actual handler
249-
// 8(SP) siginfo style
250-
// 12(SP) signal number
251-
// 16(SP) siginfo
252-
// 20(SP) context
253-
TEXT runtime·sigtramp(SB),NOSPLIT,$20
254-
MOVL sig+8(FP), BX
255-
MOVL BX, 0(SP)
256-
MOVL info+12(FP), BX
257-
MOVL BX, 4(SP)
258-
MOVL ctx+16(FP), BX
259-
MOVL BX, 8(SP)
290+
// It is called with the C calling convention, and calls out
291+
// to sigtrampgo with the Go calling convention.
292+
TEXT runtime·sigtramp(SB),NOSPLIT,$0
293+
SUBL $28, SP
294+
295+
// Save callee-save registers.
296+
MOVL BP, 12(SP)
297+
MOVL BX, 16(SP)
298+
MOVL SI, 20(SP)
299+
MOVL DI, 24(SP)
300+
301+
MOVL 32(SP), AX
302+
MOVL AX, 0(SP) // arg 1 signal number
303+
MOVL 36(SP), AX
304+
MOVL AX, 4(SP) // arg 2 siginfo
305+
MOVL 40(SP), AX
306+
MOVL AX, 8(SP) // arg 3 ctxt
260307
CALL runtime·sigtrampgo(SB)
261308

262-
// call sigreturn
263-
MOVL ctx+16(FP), CX
264-
MOVL infostyle+4(FP), BX
265-
MOVL $0, 0(SP) // "caller PC" - ignored
266-
MOVL CX, 4(SP)
267-
MOVL BX, 8(SP)
268-
MOVL $184, AX // sigreturn(ucontext, infostyle)
269-
INT $0x80
270-
MOVL $0xf1, 0xf1 // crash
271-
RET
309+
// Restore callee-save registers.
310+
MOVL 12(SP), BP
311+
MOVL 16(SP), BX
312+
MOVL 20(SP), SI
313+
MOVL 24(SP), DI
272314

273-
TEXT runtime·sigaltstack(SB),NOSPLIT,$0
274-
MOVL $53, AX
275-
INT $0x80
276-
JAE 2(PC)
277-
MOVL $0xf1, 0xf1 // crash
315+
ADDL $28, SP
278316
RET
279317

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

450+
// Save callee-save registers.
451+
SUBL $16, SP
452+
MOVL BP, 0(SP)
453+
MOVL BX, 4(SP)
454+
MOVL SI, 8(SP)
455+
MOVL DI, 12(SP)
456+
412457
MOVL SP, AX // hide argument read from vet (vet thinks this function is using the Go calling convention)
413-
MOVL 4(AX), DI // m
458+
MOVL 20(AX), DI // m
414459
MOVL m_g0(DI), DX // g
415460

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

423468
CALL runtime·mstart(SB)
424469

470+
// Restore callee-save registers.
471+
MOVL 0(SP), BP
472+
MOVL 4(SP), BX
473+
MOVL 8(SP), SI
474+
MOVL 12(SP), DI
475+
425476
// Go is all done with this OS thread.
426477
// Tell pthread everything is ok (we never join with this thread, so
427478
// the value here doesn't really matter).
428479
XORL AX, AX
480+
481+
ADDL $16, SP
429482
RET
430483

431484
TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0

0 commit comments

Comments
 (0)