...
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.
4
5// Test a C thread that calls sigaltstack and then calls Go code.
6
7#include <signal.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <time.h>
12#include <sched.h>
13#include <pthread.h>
14
15#include "libgo4.h"
16
17#ifdef _AIX
18// On AIX, CSIGSTKSZ is too small to handle Go sighandler.
19#define CSIGSTKSZ 0x4000
20#else
21#define CSIGSTKSZ SIGSTKSZ
22#endif
23
24static void die(const char* msg) {
25 perror(msg);
26 exit(EXIT_FAILURE);
27}
28
29static int ok = 1;
30
31static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
32}
33
34// Set up the SIGIO signal handler in a high priority constructor, so
35// that it is installed before the Go code starts.
36
37static void init(void) __attribute__ ((constructor (200)));
38
39static void init() {
40 struct sigaction sa;
41
42 memset(&sa, 0, sizeof sa);
43 sa.sa_sigaction = ioHandler;
44 if (sigemptyset(&sa.sa_mask) < 0) {
45 die("sigemptyset");
46 }
47 sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
48 if (sigaction(SIGIO, &sa, NULL) < 0) {
49 die("sigaction");
50 }
51}
52
53// Test raising SIGIO on a C thread with an alternate signal stack
54// when there is a Go signal handler for SIGIO.
55static void* thread1(void* arg __attribute__ ((unused))) {
56 stack_t ss;
57 int i;
58 stack_t nss;
59 struct timespec ts;
60
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) {
65 die("malloc");
66 }
67 ss.ss_flags = 0;
68 ss.ss_size = CSIGSTKSZ;
69 if (sigaltstack(&ss, NULL) < 0) {
70 die("sigaltstack");
71 }
72
73 // Send ourselves a SIGIO. This will be caught by the Go
74 // signal handler which should forward to the C signal
75 // handler.
76 i = pthread_kill(pthread_self(), SIGIO);
77 if (i != 0) {
78 fprintf(stderr, "pthread_kill: %s\n", strerror(i));
79 exit(EXIT_FAILURE);
80 }
81
82 // Wait until the signal has been delivered.
83 i = 0;
84 while (SIGIOCount() == 0) {
85 ts.tv_sec = 0;
86 ts.tv_nsec = 1000000;
87 nanosleep(&ts, NULL);
88 i++;
89 if (i > 5000) {
90 fprintf(stderr, "looping too long waiting for signal\n");
91 exit(EXIT_FAILURE);
92 }
93 }
94
95 // We should still be on the same signal stack.
96 if (sigaltstack(NULL, &nss) < 0) {
97 die("sigaltstack check");
98 }
99 if ((nss.ss_flags & SS_DISABLE) != 0) {
100 fprintf(stderr, "sigaltstack disabled on return from Go\n");
101 ok = 0;
102 } else if (nss.ss_sp != ss.ss_sp) {
103 fprintf(stderr, "sigaltstack changed on return from Go\n");
104 ok = 0;
105 }
106
107 return NULL;
108}
109
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.
112static void* thread2(void* arg __attribute__ ((unused))) {
113 stack_t ss;
114 int i;
115 int oldcount;
116 pthread_t tid;
117 struct timespec ts;
118 stack_t nss;
119
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) {
124 die("malloc");
125 }
126 ss.ss_flags = 0;
127 ss.ss_size = CSIGSTKSZ;
128 if (sigaltstack(&ss, NULL) < 0) {
129 die("sigaltstack");
130 }
131
132 oldcount = SIGIOCount();
133
134 // Call a Go function that will call a C function to send us a
135 // SIGIO.
136 tid = pthread_self();
137 GoRaiseSIGIO(&tid);
138
139 // Wait until the signal has been delivered.
140 i = 0;
141 while (SIGIOCount() == oldcount) {
142 ts.tv_sec = 0;
143 ts.tv_nsec = 1000000;
144 nanosleep(&ts, NULL);
145 i++;
146 if (i > 5000) {
147 fprintf(stderr, "looping too long waiting for signal\n");
148 exit(EXIT_FAILURE);
149 }
150 }
151
152 // We should still be on the same signal stack.
153 if (sigaltstack(NULL, &nss) < 0) {
154 die("sigaltstack check");
155 }
156 if ((nss.ss_flags & SS_DISABLE) != 0) {
157 fprintf(stderr, "sigaltstack disabled on return from Go\n");
158 ok = 0;
159 } else if (nss.ss_sp != ss.ss_sp) {
160 fprintf(stderr, "sigaltstack changed on return from Go\n");
161 ok = 0;
162 }
163
164 return NULL;
165}
166
167int main(int argc, char **argv) {
168 pthread_t tid;
169 int i;
170
171 // Tell the Go library to start looking for SIGIO.
172 GoCatchSIGIO();
173
174 i = pthread_create(&tid, NULL, thread1, NULL);
175 if (i != 0) {
176 fprintf(stderr, "pthread_create: %s\n", strerror(i));
177 exit(EXIT_FAILURE);
178 }
179
180 i = pthread_join(tid, NULL);
181 if (i != 0) {
182 fprintf(stderr, "pthread_join: %s\n", strerror(i));
183 exit(EXIT_FAILURE);
184 }
185
186 i = pthread_create(&tid, NULL, thread2, NULL);
187 if (i != 0) {
188 fprintf(stderr, "pthread_create: %s\n", strerror(i));
189 exit(EXIT_FAILURE);
190 }
191
192 i = pthread_join(tid, NULL);
193 if (i != 0) {
194 fprintf(stderr, "pthread_join: %s\n", strerror(i));
195 exit(EXIT_FAILURE);
196 }
197
198 if (!ok) {
199 exit(EXIT_FAILURE);
200 }
201
202 printf("PASS\n");
203 return 0;
204}
View as plain text