Commit c61a55d8 authored by Ian Lance Taylor's avatar Ian Lance Taylor

misc/cgo/testcarchive: more robust TestSignalForwardingExternal

Try to avoid a race condition in the test.  Passed 500 times on my
laptop.

Fixes #14956.

Change-Id: I5de2e1e3623832f0ab4f180149f7c57ce7cd23c0
Reviewed-on: https://go-review.googlesource.com/21171
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 080e2d43
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"testing" "testing"
"time"
"unicode" "unicode"
) )
...@@ -312,6 +313,17 @@ func TestSignalForwardingExternal(t *testing.T) { ...@@ -312,6 +313,17 @@ func TestSignalForwardingExternal(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
// We want to send the process a signal and see if it dies.
// Normally the signal goes to the C thread, the Go signal
// handler picks it up, sees that it is running in a C thread,
// and the program dies. Unfortunately, occasionally the
// signal is delivered to a Go thread, which winds up
// discarding it because it was sent by another program and
// there is no Go handler for it. To avoid this, run the
// program several times in the hopes that it will eventually
// fail.
const tries = 20
for i := 0; i < tries; i++ {
cmd = exec.Command(bin[0], append(bin[1:], "2")...) cmd = exec.Command(bin[0], append(bin[1:], "2")...)
stderr, err := cmd.StderrPipe() stderr, err := cmd.StderrPipe()
...@@ -336,20 +348,30 @@ func TestSignalForwardingExternal(t *testing.T) { ...@@ -336,20 +348,30 @@ func TestSignalForwardingExternal(t *testing.T) {
t.Fatalf("Did not receive OK signal") t.Fatalf("Did not receive OK signal")
} }
// Trigger an interrupt external to the process. // Give the program a chance to enter the sleep function.
time.Sleep(time.Millisecond)
cmd.Process.Signal(syscall.SIGSEGV) cmd.Process.Signal(syscall.SIGSEGV)
err = cmd.Wait() err = cmd.Wait()
if err == nil { if err == nil {
t.Error("test program succeeded unexpectedly") continue
} else if ee, ok := err.(*exec.ExitError); !ok { }
if ee, ok := err.(*exec.ExitError); !ok {
t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err) t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok { } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys()) t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
} else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV { } else if !ws.Signaled() || ws.Signal() != syscall.SIGSEGV {
t.Errorf("got %v; expected SIGSEGV", ee) t.Errorf("got %v; expected SIGSEGV", ee)
} else {
// We got the error we expected.
return
} }
}
t.Errorf("program succeeded unexpectedly %d times", tries)
} }
func TestOsSignal(t *testing.T) { func TestOsSignal(t *testing.T) {
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/select.h>
#include "libgo2.h" #include "libgo2.h"
...@@ -16,7 +19,7 @@ int main(int argc, char** argv) { ...@@ -16,7 +19,7 @@ int main(int argc, char** argv) {
int test; int test;
if (argc < 2) { if (argc < 2) {
printf("Missing argument"); printf("Missing argument\n");
return 1; return 1;
} }
...@@ -28,7 +31,7 @@ int main(int argc, char** argv) { ...@@ -28,7 +31,7 @@ int main(int argc, char** argv) {
printf("calling RunGoroutines\n"); printf("calling RunGoroutines\n");
} }
RunGoroutines(); Noop();
switch (test) { switch (test) {
case 1: { case 1: {
...@@ -41,6 +44,8 @@ int main(int argc, char** argv) { ...@@ -41,6 +44,8 @@ int main(int argc, char** argv) {
} }
case 2: { case 2: {
struct timeval tv;
if (verbose) { if (verbose) {
printf("attempting external signal test\n"); printf("attempting external signal test\n");
} }
...@@ -48,8 +53,18 @@ int main(int argc, char** argv) { ...@@ -48,8 +53,18 @@ int main(int argc, char** argv) {
fprintf(stderr, "OK\n"); fprintf(stderr, "OK\n");
fflush(stderr); fflush(stderr);
// The program should be interrupted before this sleep finishes. // The program should be interrupted before
sleep(60); // this sleep finishes. We use select rather
// than sleep because in older versions of
// glibc the sleep function does some signal
// fiddling to handle SIGCHLD. If this
// program is fiddling signals just when the
// test program sends the signal, the signal
// may be delivered to a Go thread which will
// break this test.
tv.tv_sec = 60;
tv.tv_usec = 0;
select(0, NULL, NULL, NULL, &tv);
break; break;
} }
......
...@@ -41,5 +41,10 @@ func TestSEGV() { ...@@ -41,5 +41,10 @@ func TestSEGV() {
os.Exit(1) os.Exit(1)
} }
// Noop ensures that the Go runtime is initialized.
//export Noop
func Noop() {
}
func main() { func main() {
} }
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