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) }
func Test5337(t *testing.T) { test5337(t) }
func Test5548(t *testing.T) { test5548(t) }
func Test5603(t *testing.T) { test5603(t) }
func Test3250(t *testing.T) { test3250(t) }
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)
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)
{
......
......@@ -235,30 +235,6 @@ runtime·setprof(bool 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);
typedef struct sigaction {
......
......@@ -284,30 +284,6 @@ runtime·setprof(bool 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
#define sa_handler k_sa_handler
#endif
......
......@@ -275,30 +275,6 @@ runtime·setprof(bool 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);
typedef struct sigaction {
......
......@@ -257,30 +257,6 @@ runtime·setprof(bool 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);
typedef struct sigaction {
......
......@@ -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.
#pragma textflag 7
void
runtime·badsignal(void)
runtime·badsignal2(void)
{
runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
runtime·exits(badsignal);
......
......@@ -28,6 +28,7 @@ package runtime
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
#include "cgocall.h"
static struct {
Note;
......@@ -155,3 +156,11 @@ func signal_disable(s uint32) {
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));
}
......@@ -238,11 +238,12 @@ TEXT runtime·sigtramp(SB),7,$40
// 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 @@ TEXT runtime·sigtramp(SB),7,$40
MOVL 20(SP), DI
MOVL DI, g(CX)
sigtramp_ret:
// call sigreturn
MOVL context+16(FP), CX
MOVL style+4(FP), BX
......
......@@ -192,13 +192,17 @@ TEXT runtime·sigaction(SB),7,$0
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 @@ TEXT runtime·sigtramp(SB),7,$64
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 @@ TEXT runtime·sigtramp(SB),7,$64
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
......
......@@ -183,11 +183,12 @@ TEXT runtime·sigtramp(SB),7,$44
// 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 @@ TEXT runtime·sigtramp(SB),7,$44
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
......
......@@ -155,13 +155,14 @@ TEXT runtime·sigaction(SB),7,$-8
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 @@ TEXT runtime·sigtramp(SB),7,$64
MOVQ SI, 8(SP)
MOVQ DX, 16(SP)
MOVQ R10, 24(SP)
CALL runtime·sighandler(SB)
// restore g
......
......@@ -158,9 +158,10 @@ TEXT runtime·sigtramp(SB),7,$24
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
......
......@@ -168,10 +168,11 @@ TEXT runtime·sigtramp(SB),7,$44
// 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
......
......@@ -186,9 +186,10 @@ TEXT runtime·sigtramp(SB),7,$64
// 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
......
......@@ -292,9 +292,10 @@ TEXT runtime·sigtramp(SB),7,$24
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
......
......@@ -196,10 +196,11 @@ TEXT runtime·sigtramp(SB),7,$44
// 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
......
......@@ -215,9 +215,10 @@ TEXT runtime·sigtramp(SB),7,$64
// 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
......
......@@ -207,9 +207,10 @@ TEXT runtime·sigtramp(SB),7,$24
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
......
......@@ -170,11 +170,12 @@ TEXT runtime·sigtramp(SB),7,$44
// 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 @@ TEXT runtime·sigtramp(SB),7,$44
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
......
......@@ -204,9 +204,10 @@ TEXT runtime·sigtramp(SB),7,$64
// 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
......
......@@ -127,7 +127,7 @@ TEXT runtime·sigtramp(SB),7,$0
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
......
......@@ -159,7 +159,7 @@ TEXT runtime·sigtramp(SB),7,$0
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
......
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