PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED
F_SETFD = C.F_SETFD
+ F_GETFL = C.F_GETFL
+ F_SETFL = C.F_SETFL
FD_CLOEXEC = C.FD_CLOEXEC
+
+ O_NONBLOCK = C.O_NONBLOCK
)
type StackT C.struct_sigaltstack
_PTHREAD_CREATE_DETACHED = 0x2
_F_SETFD = 0x2
+ _F_GETFL = 0x3
+ _F_SETFL = 0x4
_FD_CLOEXEC = 0x1
+
+ _O_NONBLOCK = 4
)
type stackt struct {
_PTHREAD_CREATE_DETACHED = 0x2
_F_SETFD = 0x2
+ _F_GETFL = 0x3
+ _F_SETFL = 0x4
_FD_CLOEXEC = 0x1
+
+ _O_NONBLOCK = 4
)
type stackt struct {
_PTHREAD_CREATE_DETACHED = 0x2
_F_SETFD = 0x2
+ _F_GETFL = 0x3
+ _F_SETFL = 0x4
_FD_CLOEXEC = 0x1
+
+ _O_NONBLOCK = 4
)
type stackt struct {
_PTHREAD_CREATE_DETACHED = 0x2
_F_SETFD = 0x2
+ _F_GETFL = 0x3
+ _F_SETFL = 0x4
_FD_CLOEXEC = 0x1
+
+ _O_NONBLOCK = 4
)
type stackt struct {
pthread_mutex_unlock(&mp.mutex)
}
+// The read and write file descriptors used by the sigNote functions.
+var sigNoteRead, sigNoteWrite int32
+
+// sigNoteSetup initializes an async-signal-safe note.
+//
+// The current implementation of notes on Darwin is not async-signal-safe,
+// because the functions pthread_mutex_lock, pthread_cond_signal, and
+// pthread_mutex_unlock, called by semawakeup, are not async-signal-safe.
+// There is only one case where we need to wake up a note from a signal
+// handler: the sigsend function. The signal handler code does not require
+// all the features of notes: it does not need to do a timed wait.
+// This is a separate implementation of notes, based on a pipe, that does
+// not support timed waits but is async-signal-safe.
+func sigNoteSetup(*note) {
+ if sigNoteRead != 0 || sigNoteWrite != 0 {
+ throw("duplicate sigNoteSetup")
+ }
+ var errno int32
+ sigNoteRead, sigNoteWrite, errno = pipe()
+ if errno != 0 {
+ throw("pipe failed")
+ }
+ closeonexec(sigNoteRead)
+ closeonexec(sigNoteWrite)
+
+ // Make the write end of the pipe non-blocking, so that if the pipe
+ // buffer is somehow full we will not block in the signal handler.
+ // Leave the read end of the pipe blocking so that we will block
+ // in sigNoteSleep.
+ setNonblock(sigNoteWrite)
+}
+
+// sigNoteWakeup wakes up a thread sleeping on a note created by sigNoteSetup.
+func sigNoteWakeup(*note) {
+ var b byte
+ write(uintptr(sigNoteWrite), unsafe.Pointer(&b), 1)
+}
+
+// sigNoteSleep waits for a note created by sigNoteSetup to be woken.
+func sigNoteSleep(*note) {
+ entersyscallblock()
+ var b byte
+ read(sigNoteRead, unsafe.Pointer(&b), 1)
+ exitsyscall()
+}
+
// BSD interface for threading.
func osinit() {
// pthread_create delayed until end of goenvs so that we
break Send
case sigReceiving:
if atomic.Cas(&sig.state, sigReceiving, sigIdle) {
+ if GOOS == "darwin" {
+ sigNoteWakeup(&sig.note)
+ break Send
+ }
notewakeup(&sig.note)
break Send
}
throw("signal_recv: inconsistent state")
case sigIdle:
if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
+ if GOOS == "darwin" {
+ sigNoteSleep(&sig.note)
+ break Receive
+ }
notetsleepg(&sig.note, -1)
noteclear(&sig.note)
break Receive
// to use for initialization. It does not pass
// signal information in m.
sig.inuse = true // enable reception of signals; cannot disable
+ if GOOS == "darwin" {
+ sigNoteSetup(&sig.note)
+ return
+ }
noteclear(&sig.note)
return
}
--- /dev/null
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The current implementation of notes on Darwin is not async-signal-safe,
+// so on Darwin the sigqueue code uses different functions to wake up the
+// signal_recv thread. This file holds the non-Darwin implementations of
+// those functions. These functions will never be called.
+
+// +build !darwin
+// +build !plan9
+
+package runtime
+
+func sigNoteSetup(*note) {
+ throw("sigNoteSetup")
+}
+
+func sigNoteSleep(*note) {
+ throw("sigNoteSleep")
+}
+
+func sigNoteWakeup(*note) {
+ throw("sigNoteWakeup")
+}
}
func read_trampoline()
+func pipe() (r, w int32, errno int32) {
+ var p [2]int32
+ errno = libcCall(unsafe.Pointer(funcPC(pipe_trampoline)), noescape(unsafe.Pointer(&p)))
+ return p[0], p[1], errno
+}
+func pipe_trampoline()
+
//go:nosplit
//go:cgo_unsafe_args
func closefd(fd int32) int32 {
fcntl(fd, _F_SETFD, _FD_CLOEXEC)
}
+//go:nosplit
+func setNonblock(fd int32) {
+ flags := fcntl(fd, _F_GETFL, 0)
+ fcntl(fd, _F_SETFL, flags|_O_NONBLOCK)
+}
+
// Tell the linker that the libc_* functions are to be found
// in a system library, with the libc_ prefix missing.
//go:cgo_import_dynamic libc_close close "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_read read "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_write write "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pipe pipe "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mmap mmap "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_munmap munmap "/usr/lib/libSystem.B.dylib"
POPL BP
RET
+TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX // arg 1 pipefd
+ MOVL AX, 0(SP)
+ CALL libc_pipe(SB)
+ TESTL AX, AX
+ JEQ 3(PC)
+ CALL libc_error(SB) // return negative errno value
+ NEGL AX
+ MOVL BP, SP
+ POPL BP
+ RET
+
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
POPQ BP
RET
+TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ CALL libc_pipe(SB) // pointer already in DI
+ TESTL AX, AX
+ JEQ 3(PC)
+ CALL libc_error(SB) // return negative errno value
+ NEGL AX
+ POPQ BP
+ RET
+
TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
BL libc_read(SB)
RET
+TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
+ BL libc_pipe(SB) // pointer already in R0
+ CMP $0, R0
+ BEQ 3(PC)
+ BL libc_error(SB) // return negative errno value
+ RSB $0, R0, R0
+ RET
+
TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
MOVW 0(R0), R0 // arg 0 code
BL libc_exit(SB)
BL libc_read(SB)
RET
+TEXT runtime·pipe_trampoline(SB),NOSPLIT,$0
+ BL libc_pipe(SB) // pointer already in R0
+ CMP $0, R0
+ BEQ 3(PC)
+ BL libc_error(SB) // return negative errno value
+ NEG R0, R0
+ RET
+
TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
MOVW 0(R0), R0
BL libc_exit(SB)