1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Test a C thread that calls sigaltstack and then calls Go code.
18 // On AIX, CSIGSTKSZ is too small to handle Go sighandler.
19 #define CSIGSTKSZ 0x4000
21 #define CSIGSTKSZ SIGSTKSZ
24 static void die(const char* msg) {
31 static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
34 // Set up the SIGIO signal handler in a high priority constructor, so
35 // that it is installed before the Go code starts.
37 static void init(void) __attribute__ ((constructor (200)));
42 memset(&sa, 0, sizeof sa);
43 sa.sa_sigaction = ioHandler;
44 if (sigemptyset(&sa.sa_mask) < 0) {
47 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
48 if (sigaction(SIGIO, &sa, NULL) < 0) {
53 // Test raising SIGIO on a C thread with an alternate signal stack
54 // when there is a Go signal handler for SIGIO.
55 static void* thread1(void* arg __attribute__ ((unused))) {
61 // Set up an alternate signal stack for this thread.
62 memset(&ss, 0, sizeof ss);
63 ss.ss_sp = malloc(CSIGSTKSZ);
64 if (ss.ss_sp == NULL) {
68 ss.ss_size = CSIGSTKSZ;
69 if (sigaltstack(&ss, NULL) < 0) {
73 // Send ourselves a SIGIO. This will be caught by the Go
74 // signal handler which should forward to the C signal
76 i = pthread_kill(pthread_self(), SIGIO);
78 fprintf(stderr, "pthread_kill: %s\n", strerror(i));
82 // Wait until the signal has been delivered.
84 while (SIGIOCount() == 0) {
90 fprintf(stderr, "looping too long waiting for signal\n");
95 // We should still be on the same signal stack.
96 if (sigaltstack(NULL, &nss) < 0) {
97 die("sigaltstack check");
99 if ((nss.ss_flags & SS_DISABLE) != 0) {
100 fprintf(stderr, "sigaltstack disabled on return from Go\n");
102 } else if (nss.ss_sp != ss.ss_sp) {
103 fprintf(stderr, "sigaltstack changed on return from Go\n");
110 // Test calling a Go function to raise SIGIO on a C thread with an
111 // alternate signal stack when there is a Go signal handler for SIGIO.
112 static void* thread2(void* arg __attribute__ ((unused))) {
120 // Set up an alternate signal stack for this thread.
121 memset(&ss, 0, sizeof ss);
122 ss.ss_sp = malloc(CSIGSTKSZ);
123 if (ss.ss_sp == NULL) {
127 ss.ss_size = CSIGSTKSZ;
128 if (sigaltstack(&ss, NULL) < 0) {
132 oldcount = SIGIOCount();
134 // Call a Go function that will call a C function to send us a
136 tid = pthread_self();
139 // Wait until the signal has been delivered.
141 while (SIGIOCount() == oldcount) {
143 ts.tv_nsec = 1000000;
144 nanosleep(&ts, NULL);
147 fprintf(stderr, "looping too long waiting for signal\n");
152 // We should still be on the same signal stack.
153 if (sigaltstack(NULL, &nss) < 0) {
154 die("sigaltstack check");
156 if ((nss.ss_flags & SS_DISABLE) != 0) {
157 fprintf(stderr, "sigaltstack disabled on return from Go\n");
159 } else if (nss.ss_sp != ss.ss_sp) {
160 fprintf(stderr, "sigaltstack changed on return from Go\n");
167 int main(int argc, char **argv) {
171 // Tell the Go library to start looking for SIGIO.
174 i = pthread_create(&tid, NULL, thread1, NULL);
176 fprintf(stderr, "pthread_create: %s\n", strerror(i));
180 i = pthread_join(tid, NULL);
182 fprintf(stderr, "pthread_join: %s\n", strerror(i));
186 i = pthread_create(&tid, NULL, thread2, NULL);
188 fprintf(stderr, "pthread_create: %s\n", strerror(i));
192 i = pthread_join(tid, NULL);
194 fprintf(stderr, "pthread_join: %s\n", strerror(i));