]> Cypherpunks.ru repositories - gostls13.git/blob - misc/cgo/testcarchive/testdata/main2.c
da35673421b39a1b774f625fe654b949dd8d55df
[gostls13.git] / misc / cgo / testcarchive / testdata / main2.c
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 installing a signal handler before the Go code starts.
6 // This is a lot like misc/cgo/testcshared/main4.c.
7
8 #include <setjmp.h>
9 #include <signal.h>
10 #include <stdarg.h>
11 #include <stddef.h>
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18 #include <sched.h>
19 #include <time.h>
20 #include <errno.h>
21
22 #include "libgo2.h"
23
24 static void die(const char* msg) {
25         perror(msg);
26         exit(EXIT_FAILURE);
27 }
28
29 static volatile sig_atomic_t sigioSeen;
30 static volatile sig_atomic_t sigpipeSeen;
31
32 // Use up some stack space.
33 static void recur(int i, char *p) {
34         char a[1024];
35
36         *p = '\0';
37         if (i > 0) {
38                 recur(i - 1, a);
39         }
40 }
41
42 static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
43         sigpipeSeen = 1;
44 }
45
46 // Signal handler that uses up more stack space than a goroutine will have.
47 static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
48         char a[1024];
49
50         recur(4, a);
51         sigioSeen = 1;
52 }
53
54 static jmp_buf jmp;
55 static char* nullPointer;
56
57 // An arbitrary function which requires proper stack alignment; see
58 // http://golang.org/issue/17641.
59 static void callWithVarargs(void* dummy, ...) {
60         va_list args;
61         va_start(args, dummy);
62         va_end(args);
63 }
64
65 // Signal handler for SIGSEGV on a C thread.
66 static void segvHandler(int signo, siginfo_t* info, void* ctxt) {
67         sigset_t mask;
68         int i;
69
70         // Call an arbitrary function that requires the stack to be properly aligned.
71         callWithVarargs("dummy arg", 3.1415);
72
73         if (sigemptyset(&mask) < 0) {
74                 die("sigemptyset");
75         }
76         if (sigaddset(&mask, SIGSEGV) < 0) {
77                 die("sigaddset");
78         }
79         i = sigprocmask(SIG_UNBLOCK, &mask, NULL);
80         if (i != 0) {
81                 fprintf(stderr, "sigprocmask: %s\n", strerror(i));
82                 exit(EXIT_FAILURE);
83         }
84
85         // Don't try this at home.
86         longjmp(jmp, signo);
87
88         // We should never get here.
89         abort();
90 }
91
92 // Set up the signal handlers in a high priority constructor,
93 // so that they are installed before the Go code starts.
94
95 static void init(void) __attribute__ ((constructor (200)));
96
97 static void init() {
98         struct sigaction sa;
99
100         memset(&sa, 0, sizeof sa);
101         sa.sa_sigaction = ioHandler;
102         if (sigemptyset(&sa.sa_mask) < 0) {
103                 die("sigemptyset");
104         }
105         sa.sa_flags = SA_SIGINFO;
106         if (sigaction(SIGIO, &sa, NULL) < 0) {
107                 die("sigaction");
108         }
109
110         sa.sa_sigaction = segvHandler;
111         if (sigaction(SIGSEGV, &sa, NULL) < 0 || sigaction(SIGBUS, &sa, NULL) < 0) {
112                 die("sigaction");
113         }
114
115         sa.sa_sigaction = pipeHandler;
116         if (sigaction(SIGPIPE, &sa, NULL) < 0) {
117                 die("sigaction");
118         }
119 }
120
121 int main(int argc, char** argv) {
122         int verbose;
123         sigset_t mask;
124         int i;
125         struct timespec ts;
126         int darwin;
127
128         darwin = atoi(argv[1]);
129
130         verbose = argc > 2;
131
132         setvbuf(stdout, NULL, _IONBF, 0);
133
134         // Call setsid so that we can use kill(0, SIGIO) below.
135         // Don't check the return value so that this works both from
136         // a job control shell and from a shell script.
137         setsid();
138
139         if (verbose) {
140                 printf("calling RunGoroutines\n");
141         }
142
143         RunGoroutines();
144
145         // Block SIGIO in this thread to make it more likely that it
146         // will be delivered to a goroutine.
147
148         if (verbose) {
149                 printf("calling pthread_sigmask\n");
150         }
151
152         if (sigemptyset(&mask) < 0) {
153                 die("sigemptyset");
154         }
155         if (sigaddset(&mask, SIGIO) < 0) {
156                 die("sigaddset");
157         }
158         i = pthread_sigmask(SIG_BLOCK, &mask, NULL);
159         if (i != 0) {
160                 fprintf(stderr, "pthread_sigmask: %s\n", strerror(i));
161                 exit(EXIT_FAILURE);
162         }
163
164         if (verbose) {
165                 printf("calling kill\n");
166         }
167
168         if (kill(0, SIGIO) < 0) {
169                 die("kill");
170         }
171
172         if (verbose) {
173                 printf("waiting for sigioSeen\n");
174         }
175
176         // Wait until the signal has been delivered.
177         i = 0;
178         while (!sigioSeen) {
179                 ts.tv_sec = 0;
180                 ts.tv_nsec = 1000000;
181                 nanosleep(&ts, NULL);
182                 i++;
183                 if (i > 5000) {
184                         fprintf(stderr, "looping too long waiting for SIGIO\n");
185                         exit(EXIT_FAILURE);
186                 }
187         }
188
189         if (verbose) {
190                 printf("provoking SIGPIPE\n");
191         }
192
193         // SIGPIPE is never forwarded on Darwin, see golang.org/issue/33384.
194         if (!darwin) {
195                 GoRaiseSIGPIPE();
196
197                 if (verbose) {
198                         printf("waiting for sigpipeSeen\n");
199                 }
200
201                 // Wait until the signal has been delivered.
202                 i = 0;
203                 while (!sigpipeSeen) {
204                         ts.tv_sec = 0;
205                         ts.tv_nsec = 1000000;
206                         nanosleep(&ts, NULL);
207                         i++;
208                         if (i > 5000) {
209                                 fprintf(stderr, "looping too long waiting for SIGPIPE\n");
210                                 exit(EXIT_FAILURE);
211                         }
212                 }
213         }
214
215         if (verbose) {
216                 printf("calling setjmp\n");
217         }
218
219         // Test that a SIGSEGV on this thread is delivered to us.
220         if (setjmp(jmp) == 0) {
221                 if (verbose) {
222                         printf("triggering SIGSEGV\n");
223                 }
224
225                 *nullPointer = '\0';
226
227                 fprintf(stderr, "continued after address error\n");
228                 exit(EXIT_FAILURE);
229         }
230
231         if (verbose) {
232                 printf("calling TestSEGV\n");
233         }
234
235         TestSEGV();
236
237         printf("PASS\n");
238         return 0;
239 }