mirror of
https://github.com/golang/go
synced 2024-11-22 02:44:39 -07:00
runtime: correctly handle signals received on foreign threads
Fixes #3250. R=rsc CC=golang-dev https://golang.org/cl/10757044
This commit is contained in:
parent
2a983aa311
commit
2f1ead7095
@ -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) }
|
||||
|
94
misc/cgo/test/issue3250.go
Normal file
94
misc/cgo/test/issue3250.go
Normal file
@ -0,0 +1,94 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
11
misc/cgo/test/issue3250w.go
Normal file
11
misc/cgo/test/issue3250w.go
Normal file
@ -0,0 +1,11 @@
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user