Commit 2f1ead70 authored by Shenghou Ma's avatar Shenghou Ma

runtime: correctly handle signals received on foreign threads

Fixes #3250.

R=rsc
CC=golang-dev
https://golang.org/cl/10757044
parent 2a983aa3
...@@ -42,5 +42,6 @@ func TestCflags(t *testing.T) { testCflags(t) } ...@@ -42,5 +42,6 @@ func TestCflags(t *testing.T) { testCflags(t) }
func Test5337(t *testing.T) { test5337(t) } func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) } func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) } func Test5603(t *testing.T) { test5603(t) }
func Test3250(t *testing.T) { test3250(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
package cgotest
/*
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
static void *thread(void *p) {
(void)p;
const int M = 100;
int i;
for (i = 0; i < M; i++) {
pthread_kill(pthread_self(), SIGCHLD);
usleep(rand() % 20 + 5);
}
return NULL;
}
void testSendSIG() {
const int N = 20;
int i;
pthread_t tid[N];
for (i = 0; i < N; i++) {
usleep(rand() % 200 + 100);
pthread_create(&tid[i], 0, thread, NULL);
}
for (i = 0; i < N; i++)
pthread_join(tid[i], 0);
}
*/
import "C"
import (
"os"
"os/signal"
"syscall"
"testing"
"time"
)
func test3250(t *testing.T) {
const (
thres = 5
sig = syscall.SIGCHLD
)
type result struct {
n int
sig os.Signal
}
var (
sigCh = make(chan os.Signal, 10)
waitStart = make(chan struct{})
waitDone = make(chan result)
)
signal.Notify(sigCh, sig)
go func() {
n := 0
alarm := time.After(time.Second * 3)
for {
select {
case <-waitStart:
waitStart = nil
case v := <-sigCh:
n++
if v != sig || n > thres {
waitDone <- result{n, v}
return
}
case <-alarm:
waitDone <- result{n, sig}
return
}
}
}()
waitStart <- struct{}{}
C.testSendSIG()
r := <-waitDone
if r.sig != sig {
t.Fatalf("received signal %v, but want %v", r.sig, sig)
}
t.Logf("got %d signals\n", r.n)
if r.n <= thres {
t.Fatalf("expected more than %d", thres)
}
}
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package cgotest
import "testing"
func test3250(t *testing.T) {}
...@@ -523,30 +523,6 @@ runtime·setprof(bool on) ...@@ -523,30 +523,6 @@ runtime·setprof(bool on)
runtime·sigprocmask(SIG_BLOCK, &sigset_prof, nil); 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 void
runtime·setsig(int32 i, GoSighandler *fn, bool restart) runtime·setsig(int32 i, GoSighandler *fn, bool restart)
{ {
......
...@@ -235,30 +235,6 @@ runtime·setprof(bool on) ...@@ -235,30 +235,6 @@ runtime·setprof(bool on)
USED(on); 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); extern void runtime·sigtramp(void);
typedef struct sigaction { typedef struct sigaction {
......
...@@ -284,30 +284,6 @@ runtime·setprof(bool on) ...@@ -284,30 +284,6 @@ runtime·setprof(bool on)
USED(on); 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 #ifdef GOARCH_386
#define sa_handler k_sa_handler #define sa_handler k_sa_handler
#endif #endif
......
...@@ -275,30 +275,6 @@ runtime·setprof(bool on) ...@@ -275,30 +275,6 @@ runtime·setprof(bool on)
USED(on); 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); extern void runtime·sigtramp(void);
typedef struct sigaction { typedef struct sigaction {
......
...@@ -257,30 +257,6 @@ runtime·setprof(bool on) ...@@ -257,30 +257,6 @@ runtime·setprof(bool on)
USED(on); 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); extern void runtime·sigtramp(void);
typedef struct sigaction { typedef struct sigaction {
......
...@@ -336,7 +336,7 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go. ...@@ -336,7 +336,7 @@ 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. // This runs on a foreign stack, without an m or a g. No stack split.
#pragma textflag 7 #pragma textflag 7
void void
runtime·badsignal(void) runtime·badsignal2(void)
{ {
runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL); runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
runtime·exits(badsignal); runtime·exits(badsignal);
......
...@@ -28,6 +28,7 @@ package runtime ...@@ -28,6 +28,7 @@ package runtime
#include "runtime.h" #include "runtime.h"
#include "defs_GOOS_GOARCH.h" #include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h" #include "os_GOOS.h"
#include "cgocall.h"
static struct { static struct {
Note; Note;
...@@ -155,3 +156,11 @@ func signal_disable(s uint32) { ...@@ -155,3 +156,11 @@ func signal_disable(s uint32) {
sig.wanted[s/32] &= ~(1U<<(s&31)); sig.wanted[s/32] &= ~(1U<<(s&31));
runtime·sigdisable(s); 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));
}
...@@ -238,11 +238,12 @@ TEXT runtime·sigtramp(SB),7,$40 ...@@ -238,11 +238,12 @@ TEXT runtime·sigtramp(SB),7,$40
// check that m exists // check that m exists
MOVL m(CX), BP MOVL m(CX), BP
CMPL BP, $0 CMPL BP, $0
JNE 5(PC) JNE 6(PC)
MOVL sig+8(FP), BX MOVL sig+8(FP), BX
MOVL BX, 0(SP) MOVL BX, 0(SP)
CALL runtime·badsignal(SB) MOVL $runtime·badsignal(SB), AX
RET CALL AX
JMP sigtramp_ret
// save g // save g
MOVL g(CX), DI MOVL g(CX), DI
...@@ -269,6 +270,7 @@ TEXT runtime·sigtramp(SB),7,$40 ...@@ -269,6 +270,7 @@ TEXT runtime·sigtramp(SB),7,$40
MOVL 20(SP), DI MOVL 20(SP), DI
MOVL DI, g(CX) MOVL DI, g(CX)
sigtramp_ret:
// call sigreturn // call sigreturn
MOVL context+16(FP), CX MOVL context+16(FP), CX
MOVL style+4(FP), BX MOVL style+4(FP), BX
......
...@@ -192,13 +192,17 @@ TEXT runtime·sigaction(SB),7,$0 ...@@ -192,13 +192,17 @@ TEXT runtime·sigaction(SB),7,$0
TEXT runtime·sigtramp(SB),7,$64 TEXT runtime·sigtramp(SB),7,$64
get_tls(BX) get_tls(BX)
MOVQ R8, 32(SP) // save ucontext
MOVQ SI, 40(SP) // save infostyle
// check that m exists // check that m exists
MOVQ m(BX), BP MOVQ m(BX), BP
CMPQ BP, $0 CMPQ BP, $0
JNE 4(PC) JNE 5(PC)
MOVL DX, 0(SP) MOVL DX, 0(SP)
CALL runtime·badsignal(SB) MOVQ $runtime·badsignal(SB), AX
RET CALL AX
JMP sigtramp_ret
// save g // save g
MOVQ g(BX), R10 MOVQ g(BX), R10
...@@ -213,8 +217,6 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -213,8 +217,6 @@ TEXT runtime·sigtramp(SB),7,$64
MOVQ R8, 16(SP) MOVQ R8, 16(SP)
MOVQ R10, 24(SP) MOVQ R10, 24(SP)
MOVQ R8, 32(SP) // save ucontext
MOVQ SI, 40(SP) // save infostyle
CALL DI CALL DI
// restore g // restore g
...@@ -222,6 +224,7 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -222,6 +224,7 @@ TEXT runtime·sigtramp(SB),7,$64
MOVQ 48(SP), R10 MOVQ 48(SP), R10
MOVQ R10, g(BX) MOVQ R10, g(BX)
sigtramp_ret:
// call sigreturn // call sigreturn
MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle) MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
MOVQ 32(SP), DI // saved ucontext MOVQ 32(SP), DI // saved ucontext
......
...@@ -183,11 +183,12 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -183,11 +183,12 @@ TEXT runtime·sigtramp(SB),7,$44
// check that m exists // check that m exists
MOVL m(CX), BX MOVL m(CX), BX
CMPL BX, $0 CMPL BX, $0
JNE 5(PC) JNE 6(PC)
MOVL signo+0(FP), BX MOVL signo+0(FP), BX
MOVL BX, 0(SP) MOVL BX, 0(SP)
CALL runtime·badsignal(SB) MOVL $runtime·badsignal(SB), AX
RET CALL AX
JMP sigtramp_ret
// save g // save g
MOVL g(CX), DI MOVL g(CX), DI
...@@ -213,6 +214,7 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -213,6 +214,7 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL 20(SP), BX MOVL 20(SP), BX
MOVL BX, g(CX) MOVL BX, g(CX)
sigtramp_ret:
// call sigreturn // call sigreturn
MOVL context+8(FP), AX MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap MOVL $0, 0(SP) // syscall gap
......
...@@ -159,9 +159,10 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -159,9 +159,10 @@ TEXT runtime·sigtramp(SB),7,$64
// check that m exists // check that m exists
MOVQ m(BX), BP MOVQ m(BX), BP
CMPQ BP, $0 CMPQ BP, $0
JNE 4(PC) JNE 5(PC)
MOVQ DI, 0(SP) MOVQ DI, 0(SP)
CALL runtime·badsignal(SB) MOVQ $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -158,9 +158,10 @@ TEXT runtime·sigtramp(SB),7,$24 ...@@ -158,9 +158,10 @@ TEXT runtime·sigtramp(SB),7,$24
BL.NE (R0) BL.NE (R0)
CMP $0, m CMP $0, m
BNE 3(PC) BNE 4(PC)
// signal number is already prepared in 4(R13) // signal number is already prepared in 4(R13)
BL runtime·badsignal(SB) MOVW $runtime·badsignal(SB), R11
BL (R11)
RET RET
// save g // save g
......
...@@ -168,10 +168,11 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -168,10 +168,11 @@ TEXT runtime·sigtramp(SB),7,$44
// check that m exists // check that m exists
MOVL m(CX), BX MOVL m(CX), BX
CMPL BX, $0 CMPL BX, $0
JNE 5(PC) JNE 6(PC)
MOVL sig+0(FP), BX MOVL sig+0(FP), BX
MOVL BX, 0(SP) MOVL BX, 0(SP)
CALL runtime·badsignal(SB) MOVL $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -186,9 +186,10 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -186,9 +186,10 @@ TEXT runtime·sigtramp(SB),7,$64
// check that m exists // check that m exists
MOVQ m(BX), BP MOVQ m(BX), BP
CMPQ BP, $0 CMPQ BP, $0
JNE 4(PC) JNE 5(PC)
MOVQ DI, 0(SP) MOVQ DI, 0(SP)
CALL runtime·badsignal(SB) MOVQ $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -292,9 +292,10 @@ TEXT runtime·sigtramp(SB),7,$24 ...@@ -292,9 +292,10 @@ TEXT runtime·sigtramp(SB),7,$24
BL.NE (R0) BL.NE (R0)
CMP $0, m CMP $0, m
BNE 3(PC) BNE 4(PC)
// signal number is already prepared in 4(R13) // signal number is already prepared in 4(R13)
BL runtime·badsignal(SB) MOVW $runtime·badsignal(SB), R11
BL (R11)
RET RET
// save g // save g
......
...@@ -196,10 +196,11 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -196,10 +196,11 @@ TEXT runtime·sigtramp(SB),7,$44
// check that m exists // check that m exists
MOVL m(CX), BX MOVL m(CX), BX
CMPL BX, $0 CMPL BX, $0
JNE 5(PC) JNE 6(PC)
MOVL signo+0(FP), BX MOVL signo+0(FP), BX
MOVL BX, 0(SP) MOVL BX, 0(SP)
CALL runtime·badsignal(SB) MOVL $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -215,9 +215,10 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -215,9 +215,10 @@ TEXT runtime·sigtramp(SB),7,$64
// check that m exists // check that m exists
MOVQ m(BX), BP MOVQ m(BX), BP
CMPQ BP, $0 CMPQ BP, $0
JNE 4(PC) JNE 5(PC)
MOVQ DI, 0(SP) MOVQ DI, 0(SP)
CALL runtime·badsignal(SB) MOVQ $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -207,9 +207,10 @@ TEXT runtime·sigtramp(SB),7,$24 ...@@ -207,9 +207,10 @@ TEXT runtime·sigtramp(SB),7,$24
BL.NE (R0) BL.NE (R0)
CMP $0, m CMP $0, m
BNE 3(PC) BNE 4(PC)
// signal number is already prepared in 4(R13) // signal number is already prepared in 4(R13)
BL runtime·badsignal(SB) MOVW $runtime·badsignal(SB), R11
BL (R11)
RET RET
// save g // save g
......
...@@ -170,11 +170,12 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -170,11 +170,12 @@ TEXT runtime·sigtramp(SB),7,$44
// check that m exists // check that m exists
MOVL m(CX), BX MOVL m(CX), BX
CMPL BX, $0 CMPL BX, $0
JNE 5(PC) JNE 6(PC)
MOVL signo+0(FP), BX MOVL signo+0(FP), BX
MOVL BX, 0(SP) MOVL BX, 0(SP)
CALL runtime·badsignal(SB) MOVL $runtime·badsignal(SB), AX
RET CALL AX
JMP sigtramp_ret
// save g // save g
MOVL g(CX), DI MOVL g(CX), DI
...@@ -200,6 +201,7 @@ TEXT runtime·sigtramp(SB),7,$44 ...@@ -200,6 +201,7 @@ TEXT runtime·sigtramp(SB),7,$44
MOVL 20(SP), BX MOVL 20(SP), BX
MOVL BX, g(CX) MOVL BX, g(CX)
sigtramp_ret:
// call sigreturn // call sigreturn
MOVL context+8(FP), AX MOVL context+8(FP), AX
MOVL $0, 0(SP) // syscall gap MOVL $0, 0(SP) // syscall gap
......
...@@ -204,9 +204,10 @@ TEXT runtime·sigtramp(SB),7,$64 ...@@ -204,9 +204,10 @@ TEXT runtime·sigtramp(SB),7,$64
// check that m exists // check that m exists
MOVQ m(BX), BP MOVQ m(BX), BP
CMPQ BP, $0 CMPQ BP, $0
JNE 4(PC) JNE 5(PC)
MOVQ DI, 0(SP) MOVQ DI, 0(SP)
CALL runtime·badsignal(SB) MOVQ $runtime·badsignal(SB), AX
CALL AX
RET RET
// save g // save g
......
...@@ -127,7 +127,7 @@ TEXT runtime·sigtramp(SB),7,$0 ...@@ -127,7 +127,7 @@ TEXT runtime·sigtramp(SB),7,$0
MOVL m(AX), BX MOVL m(AX), BX
CMPL BX, $0 CMPL BX, $0
JNE 3(PC) JNE 3(PC)
CALL runtime·badsignal(SB) // will exit CALL runtime·badsignal2(SB) // will exit
RET RET
// save args // save args
......
...@@ -159,7 +159,7 @@ TEXT runtime·sigtramp(SB),7,$0 ...@@ -159,7 +159,7 @@ TEXT runtime·sigtramp(SB),7,$0
MOVQ m(AX), BX MOVQ m(AX), BX
CMPQ BX, $0 CMPQ BX, $0
JNE 3(PC) JNE 3(PC)
CALL runtime·badsignal(SB) // will exit CALL runtime·badsignal2(SB) // will exit
RET RET
// save args // save args
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment