]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/cgo/internal/testcarchive/testdata/main4.c
runtime: remove crash_cgo_test CgoRaceSignal timeout
[gostls13.git] / src / cmd / cgo / internal / testcarchive / testdata / main4.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 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
24 static void die(const char* msg) {
25         perror(msg);
26         exit(EXIT_FAILURE);
27 }
28
29 static int ok = 1;
30
31 static 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
37 static void init(void) __attribute__ ((constructor (200)));
38
39 static 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.
55 static 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.
112 static 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
167 int 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 }