aboutsummaryrefslogtreecommitdiff
path: root/misc/cgo/testcshared
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2015-12-18 15:29:51 -0800
committerIan Lance Taylor <iant@golang.org>2016-01-05 00:25:50 +0000
commita7d2b4d7cef3bf3107c6cf9725cd1c6151cf18d4 (patch)
treeadc9e286d8416963832e5e408ef223df03a63186 /misc/cgo/testcshared
parent6c8a141a6d53285acc876aacfa0a9c4edb563b6c (diff)
downloadgo-a7d2b4d7cef3bf3107c6cf9725cd1c6151cf18d4.tar.xz
runtime: disable a signal by restoring the original disposition
Fixes #13034. Fixes #13042. Update #9896. Change-Id: I189f381090223dd07086848aac2d69d2c00d80c4 Reviewed-on: https://go-review.googlesource.com/18062 Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'misc/cgo/testcshared')
-rw-r--r--misc/cgo/testcshared/main5.c197
-rw-r--r--misc/cgo/testcshared/src/libgo5/libgo5.go44
-rwxr-xr-xmisc/cgo/testcshared/test.bash20
3 files changed, 259 insertions, 2 deletions
diff --git a/misc/cgo/testcshared/main5.c b/misc/cgo/testcshared/main5.c
new file mode 100644
index 0000000000..50ddb47c6b
--- /dev/null
+++ b/misc/cgo/testcshared/main5.c
@@ -0,0 +1,197 @@
+// Copyright 2015 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.
+
+// Test that a signal handler works in non-Go code when using
+// os/signal.Notify.
+// This is a lot like misc/cgo/testcarchive/main3.c.
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sched.h>
+#include <dlfcn.h>
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static volatile sig_atomic_t sigioSeen;
+
+static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
+ sigioSeen = 1;
+}
+
+int main(int argc, char** argv) {
+ int verbose;
+ struct sigaction sa;
+ void* handle;
+ void (*fn1)(void);
+ int (*sawSIGIO)(void);
+ int i;
+
+ verbose = argc > 2;
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (verbose) {
+ printf("calling sigaction\n");
+ }
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = ioHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO;
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+
+ if (verbose) {
+ printf("calling dlopen\n");
+ }
+
+ handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
+ if (handle == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ // At this point there should not be a Go signal handler
+ // installed for SIGIO.
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("waiting for sigioSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigioSeen) {
+ if (sched_yield() < 0) {
+ perror("sched_yield");
+ }
+ i++;
+ if (i > 10000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ sigioSeen = 0;
+
+ // Tell the Go code to catch SIGIO.
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ fn1 = (void(*)(void))dlsym(handle, "CatchSIGIO");
+ if (fn1 == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling CatchSIGIO\n");
+ }
+
+ fn1();
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ // Check that the Go code saw SIGIO.
+ sawSIGIO = (int (*)(void))dlsym(handle, "SawSIGIO");
+ if (sawSIGIO == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling SawSIGIO\n");
+ }
+
+ if (!sawSIGIO()) {
+ fprintf(stderr, "Go handler did not see SIGIO\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (sigioSeen != 0) {
+ fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
+ exit(EXIT_FAILURE);
+ }
+
+ // Tell the Go code to stop catching SIGIO.
+
+ if (verbose) {
+ printf("calling dlsym\n");
+ }
+
+ fn1 = (void(*)(void))dlsym(handle, "ResetSIGIO");
+ if (fn1 == NULL) {
+ fprintf(stderr, "%s\n", dlerror());
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("calling ResetSIGIO\n");
+ }
+
+ fn1();
+
+ if (verbose) {
+ printf("raising SIGIO\n");
+ }
+
+ if (raise(SIGIO) < 0) {
+ die("raise");
+ }
+
+ if (verbose) {
+ printf("calling SawSIGIO\n");
+ }
+
+ if (sawSIGIO()) {
+ fprintf(stderr, "Go handler saw SIGIO after Reset\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (verbose) {
+ printf("waiting for sigioSeen\n");
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (!sigioSeen) {
+ if (sched_yield() < 0) {
+ perror("sched_yield");
+ }
+ i++;
+ if (i > 10000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/misc/cgo/testcshared/src/libgo5/libgo5.go b/misc/cgo/testcshared/src/libgo5/libgo5.go
new file mode 100644
index 0000000000..94e5d21c14
--- /dev/null
+++ b/misc/cgo/testcshared/src/libgo5/libgo5.go
@@ -0,0 +1,44 @@
+// Copyright 2015 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.
+
+package main
+
+import "C"
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+ "time"
+)
+
+// The channel used to read SIGIO signals.
+var sigioChan chan os.Signal
+
+// CatchSIGIO starts catching SIGIO signals.
+//export CatchSIGIO
+func CatchSIGIO() {
+ sigioChan = make(chan os.Signal, 1)
+ signal.Notify(sigioChan, syscall.SIGIO)
+}
+
+// ResetSIGIO stops catching SIGIO signals.
+//export ResetSIGIO
+func ResetSIGIO() {
+ signal.Reset(syscall.SIGIO)
+}
+
+// SawSIGIO returns whether we saw a SIGIO within a brief pause.
+//export SawSIGIO
+func SawSIGIO() C.int {
+ select {
+ case <-sigioChan:
+ return 1
+ case <-time.After(100 * time.Millisecond):
+ return 0
+ }
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
index 162a62d80e..ac852a007a 100755
--- a/misc/cgo/testcshared/test.bash
+++ b/misc/cgo/testcshared/test.bash
@@ -33,8 +33,9 @@ fi
androidpath=/data/local/tmp/testcshared-$$
function cleanup() {
- rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo.h libgo4.h
- rm -f testp testp2 testp3 testp4
+ rm -f libgo.$libext libgo2.$libext libgo4.$libext libgo5.$libext
+ rm -f libgo.h libgo4.h libgo5.h
+ rm -f testp testp2 testp3 testp4 testp5
rm -rf pkg "${goroot}/${installdir}"
if [ "$goos" == "android" ]; then
@@ -161,6 +162,21 @@ if test "$output" != "PASS"; then
status=1
fi
+# test5: tests signal handlers with os/signal.Notify
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo5.$libext libgo5
+binpush libgo5.$libext
+$(go env CC) ${GOGCCFLAGS} -pthread -o testp5 main5.c -ldl
+binpush testp5
+output=$(run ./testp5 ./libgo5.$libext 2>&1)
+if test "$output" != "PASS"; then
+ echo "FAIL test5 got ${output}"
+ if test "$goos" != "android"; then
+ echo "re-running test5 in verbose mode"
+ ./testp5 ./libgo5.$libext verbose
+ fi
+ status=1
+fi
+
if test $status = 0; then
echo "ok"
fi