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 os/signal.Notify and os/signal.Reset.
6 // This is a lot like misc/cgo/testcshared/main5.c.
7
8 #include <signal.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <sched.h>
14 #include <unistd.h>
15 #include <pthread.h>
16
17 #include "libgo3.h"
18
19 static void die(const char* msg) {
20 perror(msg);
21 exit(EXIT_FAILURE);
22 }
23
24 static volatile sig_atomic_t sigioSeen;
25
26 static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
27 sigioSeen = 1;
28 }
29
30 // Set up the SIGPIPE signal handler in a high priority constructor, so
31 // that it is installed before the Go code starts.
32
33 static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
34 const char *s = "unexpected SIGPIPE\n";
35 write(2, s, strlen(s));
36 exit(EXIT_FAILURE);
37 }
38
39 static void init(void) __attribute__ ((constructor (200)));
40
41 static void init() {
42 struct sigaction sa;
43
44 memset(&sa, 0, sizeof sa);
45 sa.sa_sigaction = pipeHandler;
46 if (sigemptyset(&sa.sa_mask) < 0) {
47 die("sigemptyset");
48 }
49 sa.sa_flags = SA_SIGINFO;
50 if (sigaction(SIGPIPE, &sa, NULL) < 0) {
51 die("sigaction");
52 }
53 }
54
55 static void *provokeSIGPIPE(void *arg) {
56 ProvokeSIGPIPE();
57 return NULL;
58 }
59
60 int main(int argc, char** argv) {
61 int verbose;
62 struct sigaction sa;
63 int i;
64 struct timespec ts;
65 int res;
66 pthread_t tid;
67
68 verbose = argc > 2;
69 setvbuf(stdout, NULL, _IONBF, 0);
70
71 if (verbose) {
72 printf("raising SIGPIPE\n");
73 }
74
75 // Test that the Go runtime handles SIGPIPE, even if we installed
76 // a non-default SIGPIPE handler before the runtime initializes.
77 ProvokeSIGPIPE();
78
79 // Test that SIGPIPE on a non-main thread is also handled by Go.
80 res = pthread_create(&tid, NULL, provokeSIGPIPE, NULL);
81 if (res != 0) {
82 fprintf(stderr, "pthread_create: %s\n", strerror(res));
83 exit(EXIT_FAILURE);
84 }
85
86 res = pthread_join(tid, NULL);
87 if (res != 0) {
88 fprintf(stderr, "pthread_join: %s\n", strerror(res));
89 exit(EXIT_FAILURE);
90 }
91
92 if (verbose) {
93 printf("calling sigaction\n");
94 }
95
96 memset(&sa, 0, sizeof sa);
97 sa.sa_sigaction = ioHandler;
98 if (sigemptyset(&sa.sa_mask) < 0) {
99 die("sigemptyset");
100 }
101 sa.sa_flags = SA_SIGINFO;
102 if (sigaction(SIGIO, &sa, NULL) < 0) {
103 die("sigaction");
104 }
105
106 // At this point there should not be a Go signal handler
107 // installed for SIGIO.
108
109 if (verbose) {
110 printf("raising SIGIO\n");
111 }
112
113 if (raise(SIGIO) < 0) {
114 die("raise");
115 }
116
117 if (verbose) {
118 printf("waiting for sigioSeen\n");
119 }
120
121 // Wait until the signal has been delivered.
122 i = 0;
123 while (!sigioSeen) {
124 ts.tv_sec = 0;
125 ts.tv_nsec = 1000000;
126 nanosleep(&ts, NULL);
127 i++;
128 if (i > 5000) {
129 fprintf(stderr, "looping too long waiting for signal\n");
130 exit(EXIT_FAILURE);
131 }
132 }
133
134 sigioSeen = 0;
135
136 // Tell the Go code to catch SIGIO.
137
138 if (verbose) {
139 printf("calling CatchSIGIO\n");
140 }
141
142 CatchSIGIO();
143
144 if (verbose) {
145 printf("raising SIGIO\n");
146 }
147
148 if (raise(SIGIO) < 0) {
149 die("raise");
150 }
151
152 if (verbose) {
153 printf("calling SawSIGIO\n");
154 }
155
156 if (!SawSIGIO()) {
157 fprintf(stderr, "Go handler did not see SIGIO\n");
158 exit(EXIT_FAILURE);
159 }
160
161 if (sigioSeen != 0) {
162 fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
163 exit(EXIT_FAILURE);
164 }
165
166 // Tell the Go code to stop catching SIGIO.
167
168 if (verbose) {
169 printf("calling ResetSIGIO\n");
170 }
171
172 ResetSIGIO();
173
174 if (verbose) {
175 printf("raising SIGIO\n");
176 }
177
178 if (raise(SIGIO) < 0) {
179 die("raise");
180 }
181
182 if (verbose) {
183 printf("calling SawSIGIO\n");
184 }
185
186 if (SawSIGIO()) {
187 fprintf(stderr, "Go handler saw SIGIO after Reset\n");
188 exit(EXIT_FAILURE);
189 }
190
191 if (verbose) {
192 printf("waiting for sigioSeen\n");
193 }
194
195 // Wait until the signal has been delivered.
196 i = 0;
197 while (!sigioSeen) {
198 ts.tv_sec = 0;
199 ts.tv_nsec = 1000000;
200 nanosleep(&ts, NULL);
201 i++;
202 if (i > 5000) {
203 fprintf(stderr, "looping too long waiting for signal\n");
204 exit(EXIT_FAILURE);
205 }
206 }
207
208 printf("PASS\n");
209 return 0;
210 }
211
View as plain text