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 that a signal handler works in non-Go code when using
6 // os/signal.Notify.
7 // This is a lot like ../testcarchive/main3.c.
8
9 #include <signal.h>
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <time.h>
15 #include <sched.h>
16 #include <dlfcn.h>
17
18 static void die(const char* msg) {
19 perror(msg);
20 exit(EXIT_FAILURE);
21 }
22
23 static volatile sig_atomic_t sigioSeen;
24
25 static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
26 sigioSeen = 1;
27 }
28
29 int main(int argc, char** argv) {
30 int verbose;
31 struct sigaction sa;
32 void* handle;
33 void (*catchSIGIO)(void);
34 void (*resetSIGIO)(void);
35 void (*awaitSIGIO)();
36 bool (*sawSIGIO)();
37 int i;
38 struct timespec ts;
39
40 verbose = argc > 2;
41 setvbuf(stdout, NULL, _IONBF, 0);
42
43 if (verbose) {
44 fprintf(stderr, "calling sigaction\n");
45 }
46
47 memset(&sa, 0, sizeof sa);
48 sa.sa_sigaction = ioHandler;
49 if (sigemptyset(&sa.sa_mask) < 0) {
50 die("sigemptyset");
51 }
52 sa.sa_flags = SA_SIGINFO;
53 if (sigaction(SIGIO, &sa, NULL) < 0) {
54 die("sigaction");
55 }
56
57 if (verbose) {
58 fprintf(stderr, "calling dlopen\n");
59 }
60
61 handle = dlopen(argv[1], RTLD_NOW | RTLD_GLOBAL);
62 if (handle == NULL) {
63 fprintf(stderr, "%s\n", dlerror());
64 exit(EXIT_FAILURE);
65 }
66
67 // At this point there should not be a Go signal handler
68 // installed for SIGIO.
69
70 if (verbose) {
71 fprintf(stderr, "raising SIGIO\n");
72 }
73
74 if (raise(SIGIO) < 0) {
75 die("raise");
76 }
77
78 if (verbose) {
79 fprintf(stderr, "waiting for sigioSeen\n");
80 }
81
82 // Wait until the signal has been delivered.
83 i = 0;
84 while (!sigioSeen) {
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 sigioSeen = 0;
96
97 // Tell the Go code to catch SIGIO.
98
99 if (verbose) {
100 fprintf(stderr, "calling dlsym\n");
101 }
102
103 catchSIGIO = (void(*)(void))dlsym(handle, "CatchSIGIO");
104 if (catchSIGIO == NULL) {
105 fprintf(stderr, "%s\n", dlerror());
106 exit(EXIT_FAILURE);
107 }
108
109 if (verbose) {
110 fprintf(stderr, "calling CatchSIGIO\n");
111 }
112
113 catchSIGIO();
114
115 if (verbose) {
116 fprintf(stderr, "raising SIGIO\n");
117 }
118
119 if (raise(SIGIO) < 0) {
120 die("raise");
121 }
122
123 if (verbose) {
124 fprintf(stderr, "calling dlsym\n");
125 }
126
127 // Check that the Go code saw SIGIO.
128 awaitSIGIO = (void (*)(void))dlsym(handle, "AwaitSIGIO");
129 if (awaitSIGIO == NULL) {
130 fprintf(stderr, "%s\n", dlerror());
131 exit(EXIT_FAILURE);
132 }
133
134 if (verbose) {
135 fprintf(stderr, "calling AwaitSIGIO\n");
136 }
137
138 awaitSIGIO();
139
140 if (sigioSeen != 0) {
141 fprintf(stderr, "C handler saw SIGIO when only Go handler should have\n");
142 exit(EXIT_FAILURE);
143 }
144
145 // Tell the Go code to stop catching SIGIO.
146
147 if (verbose) {
148 fprintf(stderr, "calling dlsym\n");
149 }
150
151 resetSIGIO = (void (*)(void))dlsym(handle, "ResetSIGIO");
152 if (resetSIGIO == NULL) {
153 fprintf(stderr, "%s\n", dlerror());
154 exit(EXIT_FAILURE);
155 }
156
157 if (verbose) {
158 fprintf(stderr, "calling ResetSIGIO\n");
159 }
160
161 resetSIGIO();
162
163 sawSIGIO = (bool (*)(void))dlsym(handle, "SawSIGIO");
164 if (sawSIGIO == NULL) {
165 fprintf(stderr, "%s\n", dlerror());
166 exit(EXIT_FAILURE);
167 }
168
169 if (verbose) {
170 fprintf(stderr, "raising SIGIO\n");
171 }
172
173 if (raise(SIGIO) < 0) {
174 die("raise");
175 }
176
177 if (verbose) {
178 fprintf(stderr, "calling SawSIGIO\n");
179 }
180
181 if (sawSIGIO()) {
182 fprintf(stderr, "Go handler saw SIGIO after Reset\n");
183 exit(EXIT_FAILURE);
184 }
185
186 if (verbose) {
187 fprintf(stderr, "waiting for sigioSeen\n");
188 }
189
190 // Wait until the signal has been delivered.
191 i = 0;
192 while (!sigioSeen) {
193 ts.tv_sec = 0;
194 ts.tv_nsec = 1000000;
195 nanosleep(&ts, NULL);
196 i++;
197 if (i > 5000) {
198 fprintf(stderr, "looping too long waiting for signal\n");
199 exit(EXIT_FAILURE);
200 }
201 }
202
203 printf("PASS\n");
204 return 0;
205 }
206
View as plain text