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
16#include "libgo3.h"
17
18static void die(const char* msg) {
19	perror(msg);
20	exit(EXIT_FAILURE);
21}
22
23static volatile sig_atomic_t sigioSeen;
24
25static void ioHandler(int signo, siginfo_t* info, void* ctxt) {
26	sigioSeen = 1;
27}
28
29// Set up the SIGPIPE signal handler in a high priority constructor, so
30// that it is installed before the Go code starts.
31
32static void pipeHandler(int signo, siginfo_t* info, void* ctxt) {
33	const char *s = "unexpected SIGPIPE\n";
34	write(2, s, strlen(s));
35	exit(EXIT_FAILURE);
36}
37
38static void init(void) __attribute__ ((constructor (200)));
39
40static void init() {
41    struct sigaction sa;
42
43	memset(&sa, 0, sizeof sa);
44	sa.sa_sigaction = pipeHandler;
45	if (sigemptyset(&sa.sa_mask) < 0) {
46		die("sigemptyset");
47	}
48	sa.sa_flags = SA_SIGINFO;
49	if (sigaction(SIGPIPE, &sa, NULL) < 0) {
50		die("sigaction");
51	}
52}
53
54int main(int argc, char** argv) {
55	int verbose;
56	struct sigaction sa;
57	int i;
58	struct timespec ts;
59
60	verbose = argc > 2;
61	setvbuf(stdout, NULL, _IONBF, 0);
62
63	if (verbose) {
64		printf("raising SIGPIPE\n");
65	}
66
67	// Test that the Go runtime handles SIGPIPE, even if we installed
68	// a non-default SIGPIPE handler before the runtime initializes.
69	ProvokeSIGPIPE();
70
71	if (verbose) {
72		printf("calling sigaction\n");
73	}
74
75	memset(&sa, 0, sizeof sa);
76	sa.sa_sigaction = ioHandler;
77	if (sigemptyset(&sa.sa_mask) < 0) {
78		die("sigemptyset");
79	}
80	sa.sa_flags = SA_SIGINFO;
81	if (sigaction(SIGIO, &sa, NULL) < 0) {
82		die("sigaction");
83	}
84
85	// At this point there should not be a Go signal handler
86	// installed for SIGIO.
87
88	if (verbose) {
89		printf("raising SIGIO\n");
90	}
91
92	if (raise(SIGIO) < 0) {
93		die("raise");
94	}
95
96	if (verbose) {
97		printf("waiting for sigioSeen\n");
98	}
99
100	// Wait until the signal has been delivered.
101	i = 0;
102	while (!sigioSeen) {
103		ts.tv_sec = 0;
104		ts.tv_nsec = 1000000;
105		nanosleep(&ts, NULL);
106		i++;
107		if (i > 5000) {
108			fprintf(stderr, "looping too long waiting for signal\n");
109			exit(EXIT_FAILURE);
110		}
111	}
112
113	sigioSeen = 0;
114
115	// Tell the Go code to catch SIGIO.
116
117	if (verbose) {
118		printf("calling CatchSIGIO\n");
119	}
120
121	CatchSIGIO();
122
123	if (verbose) {
124		printf("raising SIGIO\n");
125	}
126
127	if (raise(SIGIO) < 0) {
128		die("raise");
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 ResetSIGIO\n");
149	}
150
151	ResetSIGIO();
152
153	if (verbose) {
154		printf("raising SIGIO\n");
155	}
156
157	if (raise(SIGIO) < 0) {
158		die("raise");
159	}
160
161	if (verbose) {
162		printf("calling SawSIGIO\n");
163	}
164
165	if (SawSIGIO()) {
166		fprintf(stderr, "Go handler saw SIGIO after Reset\n");
167		exit(EXIT_FAILURE);
168	}
169
170	if (verbose) {
171		printf("waiting for sigioSeen\n");
172	}
173
174	// Wait until the signal has been delivered.
175	i = 0;
176	while (!sigioSeen) {
177		ts.tv_sec = 0;
178		ts.tv_nsec = 1000000;
179		nanosleep(&ts, NULL);
180		i++;
181		if (i > 5000) {
182			fprintf(stderr, "looping too long waiting for signal\n");
183			exit(EXIT_FAILURE);
184		}
185	}
186
187	printf("PASS\n");
188	return 0;
189}
190