diff options
author | Ian Lance Taylor <iant@golang.org> | 2019-06-28 11:20:15 -0700 |
---|---|---|
committer | Ian Lance Taylor <iant@golang.org> | 2019-06-30 05:48:31 +0000 |
commit | c485e8b55918b3b37e6eab47036ab6f16fec226d (patch) | |
tree | d2c8dfa28092ff8c715c817a9e9574e076906669 /src/runtime/os_darwin.go | |
parent | 623d653db7cd2287305347196f7f4742b6b1fb38 (diff) | |
download | go-c485e8b55918b3b37e6eab47036ab6f16fec226d.tar.gz go-c485e8b55918b3b37e6eab47036ab6f16fec226d.zip |
runtime: use a pipe to wake up signal_recv on Darwin
The implementation of semaphores, and therefore notes, used on Darwin
is not async-signal-safe. The runtime has one case where a note needs
to be woken up from a signal handler: the call to notewakeup in sigsend.
That notewakeup call is only called on a single note, and it doesn't
need the full functionality of notes: nothing ever does a timed wait on it.
So change that one note to use a different implementation on Darwin,
based on a pipe. This lets the wakeup code use the write call, which is
async-signal-safe.
Fixes #31264
Change-Id: If705072d7a961dd908ea9d639c8d12b222c64806
Reviewed-on: https://go-review.googlesource.com/c/go/+/184169
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/runtime/os_darwin.go')
-rw-r--r-- | src/runtime/os_darwin.go | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 819aaaca70..1614b66c8a 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -75,6 +75,52 @@ func semawakeup(mp *m) { 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 |