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