diff options
| author | Ian Lance Taylor <iant@golang.org> | 2015-12-18 15:29:51 -0800 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2016-01-05 00:25:50 +0000 |
| commit | a7d2b4d7cef3bf3107c6cf9725cd1c6151cf18d4 (patch) | |
| tree | adc9e286d8416963832e5e408ef223df03a63186 /misc/cgo/testcshared | |
| parent | 6c8a141a6d53285acc876aacfa0a9c4edb563b6c (diff) | |
| download | go-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.c | 197 | ||||
| -rw-r--r-- | misc/cgo/testcshared/src/libgo5/libgo5.go | 44 | ||||
| -rwxr-xr-x | misc/cgo/testcshared/test.bash | 20 |
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 |
