]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: correctly handle signals received on foreign threads
authorShenghou Ma <minux.ma@gmail.com>
Thu, 11 Jul 2013 20:39:39 +0000 (04:39 +0800)
committerShenghou Ma <minux.ma@gmail.com>
Thu, 11 Jul 2013 20:39:39 +0000 (04:39 +0800)
Fixes #3250.

R=rsc
CC=golang-dev
https://golang.org/cl/10757044

25 files changed:
misc/cgo/test/cgo_test.go
misc/cgo/test/issue3250.go [new file with mode: 0644]
misc/cgo/test/issue3250w.go [new file with mode: 0644]
src/pkg/runtime/os_darwin.c
src/pkg/runtime/os_freebsd.c
src/pkg/runtime/os_linux.c
src/pkg/runtime/os_netbsd.c
src/pkg/runtime/os_openbsd.c
src/pkg/runtime/os_plan9.c
src/pkg/runtime/sigqueue.goc
src/pkg/runtime/sys_darwin_386.s
src/pkg/runtime/sys_darwin_amd64.s
src/pkg/runtime/sys_freebsd_386.s
src/pkg/runtime/sys_freebsd_amd64.s
src/pkg/runtime/sys_freebsd_arm.s
src/pkg/runtime/sys_linux_386.s
src/pkg/runtime/sys_linux_amd64.s
src/pkg/runtime/sys_linux_arm.s
src/pkg/runtime/sys_netbsd_386.s
src/pkg/runtime/sys_netbsd_amd64.s
src/pkg/runtime/sys_netbsd_arm.s
src/pkg/runtime/sys_openbsd_386.s
src/pkg/runtime/sys_openbsd_amd64.s
src/pkg/runtime/sys_plan9_386.s
src/pkg/runtime/sys_plan9_amd64.s

index f0b31c589d15473a9cf8d0f9328b5dbf47ab37f5..92c5da4627aa2c9df603e131afd78bd21d17b09e 100644 (file)
@@ -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) }
diff --git a/misc/cgo/test/issue3250.go b/misc/cgo/test/issue3250.go
new file mode 100644 (file)
index 0000000..89a455c
--- /dev/null
@@ -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)
+       }
+}
diff --git a/misc/cgo/test/issue3250w.go b/misc/cgo/test/issue3250w.go
new file mode 100644 (file)
index 0000000..e3cb161
--- /dev/null
@@ -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) {}
index b28e805a825a9fbc5d9726ce7b6e44bb5e35fd5b..2a34f20a5d8b54f31777907de577e909a93d997c 100644 (file)
@@ -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)
 {
index efe82ca0721e110be1dc8f097f80383d5199b478..c513c0a1f870508af4d3ca5750e393008cfb0258 100644 (file)
@@ -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 {
index 2ae33af2d91be4d0f40c7a7b4d43deca8a930f43..b27239d46fe089170d4a728db6bb3eaddac2a483 100644 (file)
@@ -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
index 56ff188a630bad0ce0ffea27ff3086c67e02a709..f53855c25553c5806ca1e49fce7e22c9dacaddaf 100644 (file)
@@ -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 {
index 8c62886e9b33d6555eafef15e6700319f887fd31..4c196e80b0d27b7b85acc5ec1fc2e97508162f02 100644 (file)
@@ -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 {
index 0991f81753cf921b125ee62d109ed4f19363697a..d64c463994a7172bc4f8fe19b7f402c15387c907 100644 (file)
@@ -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);
index 7e083685d057c597dba0e71931ae35059a4f54b2..9bfab3bfae0b04cb0c780407c753e56386d913c9 100644 (file)
@@ -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));
+}
index 59bb9d80d8b86fce55a6454f64c9ca33ad7ac4b2..a1a7aaf8bcae02b60e9b89bbaed8bae48dd0824a 100644 (file)
@@ -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
index b324a04240f4ad8b3fc1661b9f0d5bb59fc575df..a11cc33f3862066c6b98505c773a8d4eb2d9de31 100644 (file)
@@ -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
index bbfb3e37a2f333c1a6bf3f8005d7afacc2572363..2a57cb4be0562f3d20097535b09ee2aae9565fa8 100644 (file)
@@ -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
index 9638acb6956e57d3a98bf735f2d66361dfb34180..50d91c32871ce2a0035fbaa157337cec46ecb3b8 100644 (file)
@@ -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
index 7aba498fcd64e32620439ee29fc764523dc28cd9..8260940c7493e7f2e3d3e336843c36a14ec28de1 100644 (file)
@@ -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
index 76ebe3dcf700d551cce35659bcf43d4bbf601a2c..7d677acf8b0ffd8626b504ecf536c1c1d6d2057d 100644 (file)
@@ -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
index 2d802abb6122533ecd4c43599df0fc278b388750..649f205195acc14e10709860374faf2b1bfac41e 100644 (file)
@@ -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
index 6826bea96196ac5d019dfbc42f995b3af55f0c01..4927332ba557d97370b4ed38e5da2a0135eebb01 100644 (file)
@@ -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
index 992eba77dad3137eac0f662e88742b2e29c0084b..19b3a526ad1904503e3c5991cfe023f2d9fc7fd9 100644 (file)
@@ -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
index 574d8a91b5d0d212d0a02c7d64cbbff1eefc5e40..10b06c8d2123c30c2cfa20b4fcdc9a4e0e6cb8d4 100644 (file)
@@ -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
index 0109ad8ca9bbed696b756655f698ec34e5d09ef7..d39b6481eb0bbcfdfab381e4b89373deb4c1f1ee 100644 (file)
@@ -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
index f154464dc6cc608d6f1e7758ce207532ed1e5543..3ca4511806f30527e37f5a7df413f091f1898475 100644 (file)
@@ -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
index 04c5719aaa6342ea47e4eba8be61a5cb2b764afb..3cbf0d9343f420660c33e9ca4474038a1fc4b775 100644 (file)
@@ -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
index 1f860a96190bd6503891fdc9fcee3b9da4ba112e..e8fd836169916d2173e7a3156184213982db2b2b 100644 (file)
@@ -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
index c0c896ebc9a182a6de64bb8d3282deb68da7b418..140c5e42b3ce61b057cc91c36d0fa12c8760dcfa 100644 (file)
@@ -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