From 1cdabf0c8b1297a1b82fda975f9313f69b77b262 Mon Sep 17 00:00:00 2001 From: Matthew Dempsky Date: Wed, 11 May 2022 12:44:06 -0700 Subject: [PATCH] runtime: avoid staticinit dependency with sigsetAllExiting Currently, package runtime runs `osinit` before dynamic initialization of package-scope variables; but on GOOS=linux, `osinit` involves mutating `sigsetAllExiting`. This currently works because cmd/compile and gccgo have non-spec-conforming optimizations that statically initialize `sigsetAllExiting`, but disabling that optimization causes `sigsetAllExiting` to be dynamically initialized instead. This in turn causes the mutations in `osinit` to get lost. This CL moves the initialization of `sigsetAllExiting` from `osinit` into its initialization expression, and then removes the special case for continuing to perform the static-initialization optimization for package runtime. Updates #51913. Change-Id: I3be31454277c103372c9701d227dc774b2311dad Reviewed-on: https://go-review.googlesource.com/c/go/+/405549 Auto-Submit: Matthew Dempsky Reviewed-by: Michael Knyszek Reviewed-by: Heschi Kreinick LUCI-TryBot-Result: Go LUCI --- src/runtime/os_linux.go | 18 ------------------ src/runtime/signal_unix.go | 32 ++++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 51fedba2b8..26b5ecd1f0 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -346,24 +346,6 @@ func getHugePageSize() uintptr { func osinit() { ncpu = getproccount() physHugePageSize = getHugePageSize() - if iscgo { - // #42494 glibc and musl reserve some signals for - // internal use and require they not be blocked by - // the rest of a normal C runtime. When the go runtime - // blocks...unblocks signals, temporarily, the blocked - // interval of time is generally very short. As such, - // these expectations of *libc code are mostly met by - // the combined go+cgo system of threads. However, - // when go causes a thread to exit, via a return from - // mstart(), the combined runtime can deadlock if - // these signals are blocked. Thus, don't block these - // signals when exiting threads. - // - glibc: SIGCANCEL (32), SIGSETXID (33) - // - musl: SIGTIMER (32), SIGCANCEL (33), SIGSYNCCALL (34) - sigdelset(&sigsetAllExiting, 32) - sigdelset(&sigsetAllExiting, 33) - sigdelset(&sigsetAllExiting, 34) - } osArchInit() } diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go index 87cb662e41..9a3f18bc14 100644 --- a/src/runtime/signal_unix.go +++ b/src/runtime/signal_unix.go @@ -1177,10 +1177,34 @@ func msigrestore(sigmask sigset) { } // 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 +// exiting. +var sigsetAllExiting = func() sigset { + res := sigset_all + + // Apply GOOS-specific overrides here, rather than in osinit, + // because osinit may be called before sigsetAllExiting is + // initialized (#51913). + if GOOS == "linux" && iscgo { + // #42494 glibc and musl reserve some signals for + // internal use and require they not be blocked by + // the rest of a normal C runtime. When the go runtime + // blocks...unblocks signals, temporarily, the blocked + // interval of time is generally very short. As such, + // these expectations of *libc code are mostly met by + // the combined go+cgo system of threads. However, + // when go causes a thread to exit, via a return from + // mstart(), the combined runtime can deadlock if + // these signals are blocked. Thus, don't block these + // signals when exiting threads. + // - glibc: SIGCANCEL (32), SIGSETXID (33) + // - musl: SIGTIMER (32), SIGCANCEL (33), SIGSYNCCALL (34) + sigdelset(&res, 32) + sigdelset(&res, 33) + sigdelset(&res, 34) + } + + return res +}() // sigblock blocks signals in the current thread's signal mask. // This is used to block signals while setting up and tearing down g -- 2.50.0