runtime: linux iscgo support for not blocking nptl signals

Under linux+cgo, OS threads are launched via pthread_create().
This abstraction, under linux, requires we avoid blocking
signals 32,33 and 34 indefinitely because they are needed to
reliably execute POSIX-semantics threading in glibc and/or musl.

When blocking signals the go runtime generally re-enables them
quickly. However, when a thread exits (under cgo, this is
via a return from mstart()), we avoid a deadlock in C-code by
not blocking these three signals.

Fixes #42494

Change-Id: I02dfb2480a1f97d11679e0c4b132b51bddbe4c14
Reviewed-on: https://go-review.googlesource.com/c/go/+/269799
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
Trust: Tobias Klauser <tobias.klauser@gmail.com>
This commit is contained in:
Andrew G. Morgan 2020-11-12 21:19:52 -08:00 committed by Ian Lance Taylor
parent 223331fc0c
commit b0b0d98283
7 changed files with 53 additions and 11 deletions

View file

@ -1042,15 +1042,26 @@ func msigrestore(sigmask sigset) {
sigprocmask(_SIG_SETMASK, &sigmask, nil)
}
// sigblock blocks all signals in the current thread's signal mask.
// sigsetAllExiting is used by sigblock(true) when a thread is
// exiting. sigset_all is defined in OS specific code, and per GOOS
// behavior may override this default for sigsetAllExiting: see
// osinit().
var sigsetAllExiting = sigset_all
// sigblock blocks signals in the current thread's signal mask.
// This is used to block signals while setting up and tearing down g
// when a non-Go thread calls a Go function.
// The OS-specific code is expected to define sigset_all.
// when a non-Go thread calls a Go function. When a thread is exiting
// we use the sigsetAllExiting value, otherwise the OS specific
// definition of sigset_all is used.
// This is nosplit and nowritebarrierrec because it is called by needm
// which may be called on a non-Go thread with no g available.
//go:nosplit
//go:nowritebarrierrec
func sigblock() {
func sigblock(exiting bool) {
if exiting {
sigprocmask(_SIG_SETMASK, &sigsetAllExiting, nil)
return
}
sigprocmask(_SIG_SETMASK, &sigset_all, nil)
}