aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/thread_linux.c
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2012-09-04 14:40:49 -0400
committerAlan Donovan <adonovan@google.com>2012-09-04 14:40:49 -0400
commit532dee3842298ad242355fd210efbd658cc93196 (patch)
tree5207a9746d6d93e8deac4413d3b67aff4186efda /src/pkg/runtime/thread_linux.c
parentb2458ff75c75c9fafe1b5f4e0521d4949cd3754e (diff)
downloadgo-532dee3842298ad242355fd210efbd658cc93196.tar.xz
runtime: discard SIGPROF delivered to non-Go threads.
Signal handlers are global resources but many language environments (Go, C++ at Google, etc) assume they have sole ownership of a particular handler. Signal handlers in mixed-language applications must therefore be robust against unexpected delivery of certain signals, such as SIGPROF. The default Go signal handler runtime·sigtramp assumes that it will never be called on a non-Go thread, but this assumption is violated by when linking in C++ code that spawns threads. Specifically, the handler asserts the thread has an associated "m" (Go scheduler). This CL is a very simple workaround: discard SIGPROF delivered to non-Go threads. runtime.badsignal(int32) now receives the signal number; if it returns without panicking (e.g. sig==SIGPROF) the signal is discarded. I don't think there is any really satisfactory solution to the problem of signal-based profiling in a mixed-language application. It's not only the issue of handler clobbering, but also that a C++ SIGPROF handler called in a Go thread can't unwind the Go stack (and vice versa). The best we can hope for is not crashing. Note: - I've ported this to all POSIX platforms, except ARM-linux which already ignores unexpected signals on m-less threads. - I've avoided tail-calling runtime.badsignal because AFAICT the 6a/6l don't support it. - I've avoided hoisting 'push sig' (common to both function calls) because it makes the code harder to read. - Fixed an (apparently incorrect?) docstring. R=iant, rsc, minux.ma CC=golang-dev https://golang.org/cl/6498057
Diffstat (limited to 'src/pkg/runtime/thread_linux.c')
-rw-r--r--src/pkg/runtime/thread_linux.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/src/pkg/runtime/thread_linux.c b/src/pkg/runtime/thread_linux.c
index f66d2dd4d2..c428ba1b39 100644
--- a/src/pkg/runtime/thread_linux.c
+++ b/src/pkg/runtime/thread_linux.c
@@ -261,7 +261,11 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go.
// This runs on a foreign stack, without an m or a g. No stack split.
#pragma textflag 7
void
-runtime·badsignal(void)
+runtime·badsignal(int32 sig)
{
+ if (sig == SIGPROF) {
+ return; // Ignore SIGPROFs intended for a non-Go thread.
+ }
runtime·write(2, badsignal, sizeof badsignal - 1);
+ runtime·exit(1);
}