Skip to content

Commit 8714e39

Browse files
committed
runtime: M-targeted signals for BSDs
For these, we split up the existing runtime.raise assembly implementation into its constituent "get thread ID" and "signal thread" parts. This lets us implement signalM and reimplement raise in pure Go. (NetBSD conveniently already had lwp_self.) We also change minit to store the procid directly, rather than depending on newosproc to do so. This is because newosproc isn't called for the bootstrap M, but we need a procid for every M. This is also simpler overall. For golang#10958, golang#24543. Change-Id: Ie5f1fcada6a33046375066bcbe054d1f784d39c0 Reviewed-on: https://go-review.googlesource.com/c/go/+/201402 Run-TryBot: Austin Clements <austin@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
1 parent 334291d commit 8714e39

21 files changed

+160
-78
lines changed

src/runtime/defs_freebsd_386.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ type thrparam struct {
126126
spare [3]uintptr
127127
}
128128

129+
type thread int32 // long
130+
129131
type sigset struct {
130132
__bits [4]uint32
131133
}

src/runtime/defs_freebsd_amd64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ type thrparam struct {
127127
spare [3]uintptr
128128
}
129129

130+
type thread int64 // long
131+
130132
type sigset struct {
131133
__bits [4]uint32
132134
}

src/runtime/defs_freebsd_arm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ type thrparam struct {
126126
spare [3]uintptr
127127
}
128128

129+
type thread int32 // long
130+
129131
type sigset struct {
130132
__bits [4]uint32
131133
}

src/runtime/defs_freebsd_arm64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ type thrparam struct {
127127
spare [3]uintptr
128128
}
129129

130+
type thread int64 // long
131+
130132
type sigset struct {
131133
__bits [4]uint32
132134
}

src/runtime/os_dragonfly.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ func setitimer(mode int32, new, old *itimerval)
3838
//go:noescape
3939
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
4040

41-
func raise(sig uint32)
4241
func raiseproc(sig uint32)
4342

43+
func lwp_gettid() int32
44+
func lwp_kill(pid, tid int32, sig int)
45+
4446
//go:noescape
4547
func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
4648

@@ -151,7 +153,7 @@ func newosproc(mp *m) {
151153
start_func: funcPC(lwp_start),
152154
arg: unsafe.Pointer(mp),
153155
stack: uintptr(stk),
154-
tid1: unsafe.Pointer(&mp.procid),
156+
tid1: nil, // minit will record tid
155157
tid2: nil,
156158
}
157159

@@ -191,10 +193,7 @@ func mpreinit(mp *m) {
191193
// Called to initialize a new m (including the bootstrap m).
192194
// Called on the new thread, cannot allocate memory.
193195
func minit() {
194-
// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
195-
_g_ := getg()
196-
_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
197-
196+
getg().m.procid = uint64(lwp_gettid())
198197
minitSignals()
199198
}
200199

@@ -288,3 +287,17 @@ func sysauxv(auxv []uintptr) {
288287
}
289288
}
290289
}
290+
291+
// raise sends a signal to the calling thread.
292+
//
293+
// It must be nosplit because it is used by the signal handler before
294+
// it definitely has a Go stack.
295+
//
296+
//go:nosplit
297+
func raise(sig uint32) {
298+
lwp_kill(-1, lwp_gettid(), int(sig))
299+
}
300+
301+
func signalM(mp *m, sig int) {
302+
lwp_kill(-1, int32(mp.procid), sig)
303+
}

src/runtime/os_freebsd.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@ func setitimer(mode int32, new, old *itimerval)
2626
//go:noescape
2727
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
2828

29-
func raise(sig uint32)
3029
func raiseproc(sig uint32)
3130

31+
func thr_self() thread
32+
func thr_kill(tid thread, sig int)
33+
3234
//go:noescape
3335
func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_time) int32
3436

@@ -195,7 +197,7 @@ func newosproc(mp *m) {
195197
arg: unsafe.Pointer(mp),
196198
stack_base: mp.g0.stack.lo,
197199
stack_size: uintptr(stk) - mp.g0.stack.lo,
198-
child_tid: unsafe.Pointer(&mp.procid),
200+
child_tid: nil, // minit will record tid
199201
parent_tid: nil,
200202
tls_base: unsafe.Pointer(&mp.tls[0]),
201203
tls_size: unsafe.Sizeof(mp.tls),
@@ -231,7 +233,7 @@ func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
231233
arg: nil,
232234
stack_base: uintptr(stack), //+stacksize?
233235
stack_size: stacksize,
234-
child_tid: unsafe.Pointer(&m0.procid),
236+
child_tid: nil, // minit will record tid
235237
parent_tid: nil,
236238
tls_base: unsafe.Pointer(&m0.tls[0]),
237239
tls_size: unsafe.Sizeof(m0.tls),
@@ -290,12 +292,7 @@ func mpreinit(mp *m) {
290292
// Called to initialize a new m (including the bootstrap m).
291293
// Called on the new thread, cannot allocate memory.
292294
func minit() {
293-
// m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
294-
// Fix it up. (Only matters on big-endian, but be clean anyway.)
295-
if sys.PtrSize == 4 {
296-
_g_ := getg()
297-
_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
298-
}
295+
getg().m.procid = uint64(thr_self())
299296

300297
// On FreeBSD before about April 2017 there was a bug such
301298
// that calling execve from a thread other than the main
@@ -423,3 +420,17 @@ func sysSigaction(sig uint32, new, old *sigactiont) {
423420
// asmSigaction is implemented in assembly.
424421
//go:noescape
425422
func asmSigaction(sig uintptr, new, old *sigactiont) int32
423+
424+
// raise sends a signal to the calling thread.
425+
//
426+
// It must be nosplit because it is used by the signal handler before
427+
// it definitely has a Go stack.
428+
//
429+
//go:nosplit
430+
func raise(sig uint32) {
431+
thr_kill(thr_self(), int(sig))
432+
}
433+
434+
func signalM(mp *m, sig int) {
435+
thr_kill(thread(mp.procid), sig)
436+
}

src/runtime/os_netbsd.go

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, nds
4747

4848
func lwp_tramp()
4949

50-
func raise(sig uint32)
5150
func raiseproc(sig uint32)
5251

52+
func lwp_kill(tid int32, sig int)
53+
5354
//go:noescape
5455
func getcontext(ctxt unsafe.Pointer)
5556

@@ -361,3 +362,17 @@ func sysauxv(auxv []uintptr) {
361362
}
362363
}
363364
}
365+
366+
// raise sends signal to the calling thread.
367+
//
368+
// It must be nosplit because it is used by the signal handler before
369+
// it definitely has a Go stack.
370+
//
371+
//go:nosplit
372+
func raise(sig uint32) {
373+
lwp_kill(lwp_self(), int(sig))
374+
}
375+
376+
func signalM(mp *m, sig int) {
377+
lwp_kill(int32(mp.procid), sig)
378+
}

src/runtime/os_openbsd.go

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ func sigprocmask(how int32, new, old *sigset) {
4242
//go:noescape
4343
func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
4444

45-
func raise(sig uint32)
4645
func raiseproc(sig uint32)
4746

47+
func getthrid() int32
48+
func thrkill(tid int32, sig int)
49+
4850
//go:noescape
4951
func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
5052

@@ -190,7 +192,7 @@ func newosproc(mp *m) {
190192
// rather than at the top of it.
191193
param := tforkt{
192194
tf_tcb: unsafe.Pointer(&mp.tls[0]),
193-
tf_tid: (*int32)(unsafe.Pointer(&mp.procid)),
195+
tf_tid: nil, // minit will record tid
194196
tf_stack: uintptr(stk) - sys.PtrSize,
195197
}
196198

@@ -238,10 +240,7 @@ func mpreinit(mp *m) {
238240
// Called to initialize a new m (including the bootstrap m).
239241
// Called on the new thread, can not allocate memory.
240242
func minit() {
241-
// m.procid is a uint64, but tfork writes an int32. Fix it up.
242-
_g_ := getg()
243-
_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
244-
243+
getg().m.procid = uint64(getthrid())
245244
minitSignals()
246245
}
247246

@@ -337,3 +336,11 @@ func osStackRemap(s *mspan, flags int32) {
337336
throw("remapping stack memory failed")
338337
}
339338
}
339+
340+
func raise(sig uint32) {
341+
thrkill(getthrid(), int(sig))
342+
}
343+
344+
func signalM(mp *m, sig int) {
345+
thrkill(int32(mp.procid), sig)
346+
}

src/runtime/sys_dragonfly_amd64.s

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,16 @@ TEXT runtime·write1(SB),NOSPLIT,$-8
134134
MOVL AX, ret+24(FP)
135135
RET
136136

137-
TEXT runtime·raise(SB),NOSPLIT,$16
137+
TEXT runtime·lwp_gettid(SB),NOSPLIT,$0-4
138138
MOVL $496, AX // lwp_gettid
139139
SYSCALL
140-
MOVQ $-1, DI // arg 1 - pid
141-
MOVQ AX, SI // arg 2 - tid
142-
MOVL sig+0(FP), DX // arg 3 - signum
140+
MOVL AX, ret+0(FP)
141+
RET
142+
143+
TEXT runtime·lwp_kill(SB),NOSPLIT,$0-16
144+
MOVL pid+0(FP), DI // arg 1 - pid
145+
MOVL tid+4(FP), SI // arg 2 - tid
146+
MOVQ sig+8(FP), DX // arg 3 - signum
143147
MOVL $497, AX // lwp_kill
144148
SYSCALL
145149
RET

src/runtime/sys_freebsd_386.s

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,16 @@ TEXT runtime·write1(SB),NOSPLIT,$-4
131131
MOVL AX, ret+12(FP)
132132
RET
133133

134-
TEXT runtime·raise(SB),NOSPLIT,$16
135-
// thr_self(&8(SP))
136-
LEAL 8(SP), AX
134+
TEXT runtime·thr_self(SB),NOSPLIT,$8-4
135+
// thr_self(&0(FP))
136+
LEAL ret+0(FP), AX
137137
MOVL AX, 4(SP)
138138
MOVL $432, AX
139139
INT $0x80
140-
// thr_kill(self, SIGPIPE)
141-
MOVL 8(SP), AX
142-
MOVL AX, 4(SP)
143-
MOVL sig+0(FP), AX
144-
MOVL AX, 8(SP)
140+
RET
141+
142+
TEXT runtime·thr_kill(SB),NOSPLIT,$-4
143+
// thr_kill(tid, sig)
145144
MOVL $433, AX
146145
INT $0x80
147146
RET

0 commit comments

Comments
 (0)