runtime: correctly handle signals received on foreign threads
Fixes #3250.

R=rsc
CC=golang-dev
https://golang.org/cl/10757044
diff --git a/src/pkg/runtime/os_darwin.c b/src/pkg/runtime/os_darwin.c
index b28e805..2a34f20 100644
--- a/src/pkg/runtime/os_darwin.c
+++ b/src/pkg/runtime/os_darwin.c
@@ -523,30 +523,6 @@
 		runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil);
 }
 
-#pragma dataflag 16 // no pointers
-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(int32 sig)
-{
-	int32 len;
-
-	if (sig == SIGPROF) {
-		return;  // Ignore SIGPROFs intended for a non-Go thread.
-	}
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	if (0 <= sig && sig < NSIG) {
-		// Can't call findnull() because it will split stack.
-		for(len = 0; runtime·sigtab[sig].name[len]; len++)
-			;
-		runtime·write(2, runtime·sigtab[sig].name, len);
-	}
-	runtime·write(2, "\n", 1);
-	runtime·exit(1);
-}
-
 void
 runtime·setsig(int32 i, GoSighandler *fn, bool restart)
 {
diff --git a/src/pkg/runtime/os_freebsd.c b/src/pkg/runtime/os_freebsd.c
index efe82ca..c513c0a 100644
--- a/src/pkg/runtime/os_freebsd.c
+++ b/src/pkg/runtime/os_freebsd.c
@@ -235,30 +235,6 @@
 	USED(on);
 }
 
-#pragma dataflag 16 // no pointers
-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(int32 sig)
-{
-	int32 len;
-
-	if (sig == SIGPROF) {
-		return;  // Ignore SIGPROFs intended for a non-Go thread.
-	}
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	if (0 <= sig && sig < NSIG) {
-		// Can't call findnull() because it will split stack.
-		for(len = 0; runtime·sigtab[sig].name[len]; len++)
-			;
-		runtime·write(2, runtime·sigtab[sig].name, len);
-	}
-	runtime·write(2, "\n", 1);
-	runtime·exit(1);
-}
-
 extern void runtime·sigtramp(void);
 
 typedef struct sigaction {
diff --git a/src/pkg/runtime/os_linux.c b/src/pkg/runtime/os_linux.c
index 2ae33af..b27239d 100644
--- a/src/pkg/runtime/os_linux.c
+++ b/src/pkg/runtime/os_linux.c
@@ -284,30 +284,6 @@
 	USED(on);
 }
 
-#pragma dataflag 16  // no pointers
-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(int32 sig)
-{
-	int32 len;
-
-	if (sig == SIGPROF) {
-		return;  // Ignore SIGPROFs intended for a non-Go thread.
-	}
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	if (0 <= sig && sig < NSIG) {
-		// Can't call findnull() because it will split stack.
-		for(len = 0; runtime·sigtab[sig].name[len]; len++)
-			;
-		runtime·write(2, runtime·sigtab[sig].name, len);
-	}
-	runtime·write(2, "\n", 1);
-	runtime·exit(1);
-}
-
 #ifdef GOARCH_386
 #define sa_handler k_sa_handler
 #endif
diff --git a/src/pkg/runtime/os_netbsd.c b/src/pkg/runtime/os_netbsd.c
index 56ff188..f53855c 100644
--- a/src/pkg/runtime/os_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -275,30 +275,6 @@
 	USED(on);
 }
 
-#pragma dataflag 16 // no pointers
-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(int32 sig)
-{
-	int32 len;
-
-	if (sig == SIGPROF) {
-		return;  // Ignore SIGPROFs intended for a non-Go thread.
-	}
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	if (0 <= sig && sig < NSIG) {
-		// Can't call findnull() because it will split stack.
-		for(len = 0; runtime·sigtab[sig].name[len]; len++)
-			;
-		runtime·write(2, runtime·sigtab[sig].name, len);
-	}
-	runtime·write(2, "\n", 1);
-	runtime·exit(1);
-}
-
 extern void runtime·sigtramp(void);
 
 typedef struct sigaction {
diff --git a/src/pkg/runtime/os_openbsd.c b/src/pkg/runtime/os_openbsd.c
index 8c62886..4c196e8 100644
--- a/src/pkg/runtime/os_openbsd.c
+++ b/src/pkg/runtime/os_openbsd.c
@@ -257,30 +257,6 @@
 	USED(on);
 }
 
-#pragma dataflag 16 // no pointers
-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(int32 sig)
-{
-	int32 len;
-
-	if (sig == SIGPROF) {
-		return;  // Ignore SIGPROFs intended for a non-Go thread.
-	}
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	if (0 <= sig && sig < NSIG) {
-		// Can't call findnull() because it will split stack.
-		for(len = 0; runtime·sigtab[sig].name[len]; len++)
-			;
-		runtime·write(2, runtime·sigtab[sig].name, len);
-	}
-	runtime·write(2, "\n", 1);
-	runtime·exit(1);
-}
-
 extern void runtime·sigtramp(void);
 
 typedef struct sigaction {
diff --git a/src/pkg/runtime/os_plan9.c b/src/pkg/runtime/os_plan9.c
index 0991f81..d64c463 100644
--- a/src/pkg/runtime/os_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -336,7 +336,7 @@
 // This runs on a foreign stack, without an m or a g.  No stack split.
 #pragma textflag 7
 void
-runtime·badsignal(void)
+runtime·badsignal2(void)
 {
 	runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
 	runtime·exits(badsignal);
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
index 7e08368..9bfab3b 100644
--- a/src/pkg/runtime/sigqueue.goc
+++ b/src/pkg/runtime/sigqueue.goc
@@ -28,6 +28,7 @@
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
 #include "os_GOOS.h"
+#include "cgocall.h"
 
 static struct {
 	Note;
@@ -155,3 +156,11 @@
 	sig.wanted[s/32] &= ~(1U<<(s&31));
 	runtime·sigdisable(s);
 }
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag 7
+void
+runtime·badsignal(uintptr sig)
+{
+	runtime·cgocallback((void (*)(void))runtime·sigsend, &sig, sizeof(sig));
+}
diff --git a/src/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index 59bb9d8..a1a7aaf 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -238,11 +238,12 @@
 	// check that m exists
 	MOVL	m(CX), BP
 	CMPL	BP, $0
-	JNE	5(PC)
+	JNE	6(PC)
 	MOVL	sig+8(FP), BX
 	MOVL	BX, 0(SP)
-	CALL	runtime·badsignal(SB)
-	RET
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	g(CX), DI
@@ -269,6 +270,7 @@
 	MOVL	20(SP), DI
 	MOVL	DI, g(CX)
 
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+16(FP), CX
 	MOVL	style+4(FP), BX
diff --git a/src/pkg/runtime/sys_darwin_amd64.s b/src/pkg/runtime/sys_darwin_amd64.s
index b324a04..a11cc33 100644
--- a/src/pkg/runtime/sys_darwin_amd64.s
+++ b/src/pkg/runtime/sys_darwin_amd64.s
@@ -192,13 +192,17 @@
 TEXT runtime·sigtramp(SB),7,$64
 	get_tls(BX)
 
+	MOVQ	R8, 32(SP)	// save ucontext
+	MOVQ	SI, 40(SP)	// save infostyle
+
 	// check that m exists
 	MOVQ	m(BX), BP
 	CMPQ	BP, $0
-	JNE	4(PC)
+	JNE	5(PC)
 	MOVL	DX, 0(SP)
-	CALL	runtime·badsignal(SB)
-	RET
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVQ	g(BX), R10
@@ -213,8 +217,6 @@
 	MOVQ	R8, 16(SP)
 	MOVQ	R10, 24(SP)
 
-	MOVQ	R8, 32(SP)	// save ucontext
-	MOVQ	SI, 40(SP)	// save infostyle
 	CALL	DI
 
 	// restore g
@@ -222,6 +224,7 @@
 	MOVQ	48(SP), R10
 	MOVQ	R10, g(BX)
 
+sigtramp_ret:
 	// call sigreturn
 	MOVL	$(0x2000000+184), AX	// sigreturn(ucontext, infostyle)
 	MOVQ	32(SP), DI	// saved ucontext
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index bbfb3e3..2a57cb4 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -183,11 +183,12 @@
 	// check that m exists
 	MOVL	m(CX), BX
 	CMPL	BX, $0
-	JNE	5(PC)
+	JNE	6(PC)
 	MOVL	signo+0(FP), BX
 	MOVL	BX, 0(SP)
-	CALL	runtime·badsignal(SB)
-	RET
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	g(CX), DI
@@ -212,7 +213,8 @@
 	get_tls(CX)
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
-	
+
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)	// syscall gap
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 9638acb..50d91c3 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -155,13 +155,14 @@
 
 TEXT runtime·sigtramp(SB),7,$64
 	get_tls(BX)
-	
+
 	// check that m exists
 	MOVQ	m(BX), BP
 	CMPQ	BP, $0
-	JNE	4(PC)
+	JNE	5(PC)
 	MOVQ	DI, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
@@ -176,7 +177,7 @@
 	MOVQ	SI, 8(SP)
 	MOVQ	DX, 16(SP)
 	MOVQ	R10, 24(SP)
-	
+
 	CALL	runtime·sighandler(SB)
 
 	// restore g
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 7aba498..8260940 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -158,9 +158,10 @@
 	BL.NE	(R0)
 
 	CMP $0, m
-	BNE 3(PC)
+	BNE 4(PC)
 	// signal number is already prepared in 4(R13)
-	BL runtime·badsignal(SB)
+	MOVW $runtime·badsignal(SB), R11
+	BL (R11)
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index 76ebe3d..7d677ac 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -168,10 +168,11 @@
 	// check that m exists
 	MOVL	m(CX), BX
 	CMPL	BX, $0
-	JNE	5(PC)
+	JNE	6(PC)
 	MOVL	sig+0(FP), BX
 	MOVL	BX, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index 2d802ab..649f205 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -186,9 +186,10 @@
 	// check that m exists
 	MOVQ	m(BX), BP
 	CMPQ	BP, $0
-	JNE	4(PC)
+	JNE	5(PC)
 	MOVQ	DI, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 6826bea..4927332 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -292,9 +292,10 @@
 	BL.NE	(R0)
 
 	CMP 	$0, m
-	BNE 	3(PC)
+	BNE 	4(PC)
 	// signal number is already prepared in 4(R13)
-	BL  	runtime·badsignal(SB)
+	MOVW  	$runtime·badsignal(SB), R11
+	BL	(R11)
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s
index 992eba7..19b3a52 100644
--- a/src/pkg/runtime/sys_netbsd_386.s
+++ b/src/pkg/runtime/sys_netbsd_386.s
@@ -196,10 +196,11 @@
 	// check that m exists
 	MOVL	m(CX), BX
 	CMPL	BX, $0
-	JNE	5(PC)
+	JNE	6(PC)
 	MOVL	signo+0(FP), BX
 	MOVL	BX, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s
index 574d8a9..10b06c8 100644
--- a/src/pkg/runtime/sys_netbsd_amd64.s
+++ b/src/pkg/runtime/sys_netbsd_amd64.s
@@ -215,9 +215,10 @@
 	// check that m exists
 	MOVQ	m(BX), BP
 	CMPQ	BP, $0
-	JNE	4(PC)
+	JNE	5(PC)
 	MOVQ	DI, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_netbsd_arm.s b/src/pkg/runtime/sys_netbsd_arm.s
index 0109ad8..d39b648 100644
--- a/src/pkg/runtime/sys_netbsd_arm.s
+++ b/src/pkg/runtime/sys_netbsd_arm.s
@@ -207,9 +207,10 @@
 	BL.NE	(R0)
 
 	CMP $0, m
-	BNE 3(PC)
+	BNE 4(PC)
 	// signal number is already prepared in 4(R13)
-	BL runtime·badsignal(SB)
+	MOVW $runtime·badsignal(SB), R11
+	BL (R11)
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index f154464..3ca4511 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -170,11 +170,12 @@
 	// check that m exists
 	MOVL	m(CX), BX
 	CMPL	BX, $0
-	JNE	5(PC)
+	JNE	6(PC)
 	MOVL	signo+0(FP), BX
 	MOVL	BX, 0(SP)
-	CALL	runtime·badsignal(SB)
-	RET
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	g(CX), DI
@@ -199,7 +200,8 @@
 	get_tls(CX)
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
-	
+
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)		// syscall gap
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 04c5719..3cbf0d9 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -204,9 +204,10 @@
 	// check that m exists
 	MOVQ	m(BX), BP
 	CMPQ	BP, $0
-	JNE	4(PC)
+	JNE	5(PC)
 	MOVQ	DI, 0(SP)
-	CALL	runtime·badsignal(SB)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
 	RET
 
 	// save g
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index 1f860a9..e8fd836 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -127,7 +127,7 @@
 	MOVL	m(AX), BX
 	CMPL	BX, $0
 	JNE	3(PC)
-	CALL	runtime·badsignal(SB) // will exit
+	CALL	runtime·badsignal2(SB) // will exit
 	RET
 
 	// save args
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index c0c896e..140c5e4 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -159,7 +159,7 @@
 	MOVQ	m(AX), BX
 	CMPQ	BX, $0
 	JNE	3(PC)
-	CALL	runtime·badsignal(SB) // will exit
+	CALL	runtime·badsignal2(SB) // will exit
 	RET
 
 	// save args