summaryrefslogtreecommitdiffstats
path: root/misc/cgo/testcarchive/testdata/main4.c
diff options
context:
space:
mode:
Diffstat (limited to 'misc/cgo/testcarchive/testdata/main4.c')
-rw-r--r--misc/cgo/testcarchive/testdata/main4.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/misc/cgo/testcarchive/testdata/main4.c b/misc/cgo/testcarchive/testdata/main4.c
new file mode 100644
index 0000000..04f7740
--- /dev/null
+++ b/misc/cgo/testcarchive/testdata/main4.c
@@ -0,0 +1,204 @@
+// 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 a C thread that calls sigaltstack and then calls Go code.
+
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sched.h>
+#include <pthread.h>
+
+#include "libgo4.h"
+
+#ifdef _AIX
+// On AIX, CSIGSTKSZ is too small to handle Go sighandler.
+#define CSIGSTKSZ 0x4000
+#else
+#define CSIGSTKSZ SIGSTKSZ
+#endif
+
+static void die(const char* msg) {
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+static int ok = 1;
+
+static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
+}
+
+// Set up the SIGIO signal handler in a high priority constructor, so
+// that it is installed before the Go code starts.
+
+static void init(void) __attribute__ ((constructor (200)));
+
+static void init() {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ sa.sa_sigaction = ioHandler;
+ if (sigemptyset(&sa.sa_mask) < 0) {
+ die("sigemptyset");
+ }
+ sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
+ if (sigaction(SIGIO, &sa, NULL) < 0) {
+ die("sigaction");
+ }
+}
+
+// Test raising SIGIO on a C thread with an alternate signal stack
+// when there is a Go signal handler for SIGIO.
+static void* thread1(void* arg __attribute__ ((unused))) {
+ stack_t ss;
+ int i;
+ stack_t nss;
+ struct timespec ts;
+
+ // Set up an alternate signal stack for this thread.
+ memset(&ss, 0, sizeof ss);
+ ss.ss_sp = malloc(CSIGSTKSZ);
+ if (ss.ss_sp == NULL) {
+ die("malloc");
+ }
+ ss.ss_flags = 0;
+ ss.ss_size = CSIGSTKSZ;
+ if (sigaltstack(&ss, NULL) < 0) {
+ die("sigaltstack");
+ }
+
+ // Send ourselves a SIGIO. This will be caught by the Go
+ // signal handler which should forward to the C signal
+ // handler.
+ i = pthread_kill(pthread_self(), SIGIO);
+ if (i != 0) {
+ fprintf(stderr, "pthread_kill: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (SIGIOCount() == 0) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // We should still be on the same signal stack.
+ if (sigaltstack(NULL, &nss) < 0) {
+ die("sigaltstack check");
+ }
+ if ((nss.ss_flags & SS_DISABLE) != 0) {
+ fprintf(stderr, "sigaltstack disabled on return from Go\n");
+ ok = 0;
+ } else if (nss.ss_sp != ss.ss_sp) {
+ fprintf(stderr, "sigaltstack changed on return from Go\n");
+ ok = 0;
+ }
+
+ return NULL;
+}
+
+// Test calling a Go function to raise SIGIO on a C thread with an
+// alternate signal stack when there is a Go signal handler for SIGIO.
+static void* thread2(void* arg __attribute__ ((unused))) {
+ stack_t ss;
+ int i;
+ int oldcount;
+ pthread_t tid;
+ struct timespec ts;
+ stack_t nss;
+
+ // Set up an alternate signal stack for this thread.
+ memset(&ss, 0, sizeof ss);
+ ss.ss_sp = malloc(CSIGSTKSZ);
+ if (ss.ss_sp == NULL) {
+ die("malloc");
+ }
+ ss.ss_flags = 0;
+ ss.ss_size = CSIGSTKSZ;
+ if (sigaltstack(&ss, NULL) < 0) {
+ die("sigaltstack");
+ }
+
+ oldcount = SIGIOCount();
+
+ // Call a Go function that will call a C function to send us a
+ // SIGIO.
+ tid = pthread_self();
+ GoRaiseSIGIO(&tid);
+
+ // Wait until the signal has been delivered.
+ i = 0;
+ while (SIGIOCount() == oldcount) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1000000;
+ nanosleep(&ts, NULL);
+ i++;
+ if (i > 5000) {
+ fprintf(stderr, "looping too long waiting for signal\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // We should still be on the same signal stack.
+ if (sigaltstack(NULL, &nss) < 0) {
+ die("sigaltstack check");
+ }
+ if ((nss.ss_flags & SS_DISABLE) != 0) {
+ fprintf(stderr, "sigaltstack disabled on return from Go\n");
+ ok = 0;
+ } else if (nss.ss_sp != ss.ss_sp) {
+ fprintf(stderr, "sigaltstack changed on return from Go\n");
+ ok = 0;
+ }
+
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ pthread_t tid;
+ int i;
+
+ // Tell the Go library to start looking for SIGIO.
+ GoCatchSIGIO();
+
+ i = pthread_create(&tid, NULL, thread1, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_join(tid, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_create(&tid, NULL, thread2, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_create: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ i = pthread_join(tid, NULL);
+ if (i != 0) {
+ fprintf(stderr, "pthread_join: %s\n", strerror(i));
+ exit(EXIT_FAILURE);
+ }
+
+ if (!ok) {
+ exit(EXIT_FAILURE);
+ }
+
+ printf("PASS\n");
+ return 0;
+}