1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. |
2 | * |
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | * of this software and associated documentation files (the "Software"), to |
5 | * deal in the Software without restriction, including without limitation the |
6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
7 | * sell copies of the Software, and to permit persons to whom the Software is |
8 | * furnished to do so, subject to the following conditions: |
9 | * |
10 | * The above copyright notice and this permission notice shall be included in |
11 | * all copies or substantial portions of the Software. |
12 | * |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
19 | * IN THE SOFTWARE. |
20 | */ |
21 | |
22 | |
23 | /* This test does not pretend to be cross-platform. */ |
24 | #ifndef _WIN32 |
25 | |
26 | #include "uv.h" |
27 | #include "task.h" |
28 | |
29 | #include <errno.h> |
30 | #include <signal.h> |
31 | #include <stdarg.h> |
32 | #include <stdio.h> |
33 | #include <stdlib.h> |
34 | #include <string.h> |
35 | #include <unistd.h> |
36 | |
37 | /* The value of NUM_SIGNAL_HANDLING_THREADS is not arbitrary; it needs to be a |
38 | * multiple of three for reasons that will become clear when you scroll down. |
39 | * We're basically creating three different thread groups. The total needs |
40 | * to be divisible by three in order for the numbers in the final check to |
41 | * match up. |
42 | */ |
43 | #define NUM_SIGNAL_HANDLING_THREADS 24 |
44 | #define NUM_LOOP_CREATING_THREADS 10 |
45 | |
46 | enum signal_action { |
47 | ONLY_SIGUSR1, |
48 | ONLY_SIGUSR2, |
49 | SIGUSR1_AND_SIGUSR2 |
50 | }; |
51 | |
52 | static uv_sem_t sem; |
53 | static uv_mutex_t counter_lock; |
54 | static volatile int stop = 0; |
55 | |
56 | static volatile int signal1_cb_counter = 0; |
57 | static volatile int signal2_cb_counter = 0; |
58 | static volatile int loop_creation_counter = 0; |
59 | |
60 | |
61 | static void increment_counter(volatile int* counter) { |
62 | uv_mutex_lock(&counter_lock); |
63 | ++(*counter); |
64 | uv_mutex_unlock(&counter_lock); |
65 | } |
66 | |
67 | |
68 | static void signal1_cb(uv_signal_t* handle, int signum) { |
69 | ASSERT(signum == SIGUSR1); |
70 | increment_counter(&signal1_cb_counter); |
71 | uv_signal_stop(handle); |
72 | } |
73 | |
74 | |
75 | static void signal2_cb(uv_signal_t* handle, int signum) { |
76 | ASSERT(signum == SIGUSR2); |
77 | increment_counter(&signal2_cb_counter); |
78 | uv_signal_stop(handle); |
79 | } |
80 | |
81 | |
82 | static void signal_handling_worker(void* context) { |
83 | enum signal_action action; |
84 | uv_signal_t signal1a; |
85 | uv_signal_t signal1b; |
86 | uv_signal_t signal2; |
87 | uv_loop_t loop; |
88 | int r; |
89 | |
90 | action = (enum signal_action) (uintptr_t) context; |
91 | |
92 | ASSERT(0 == uv_loop_init(&loop)); |
93 | |
94 | /* Setup the signal watchers and start them. */ |
95 | if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { |
96 | r = uv_signal_init(&loop, &signal1a); |
97 | ASSERT(r == 0); |
98 | r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); |
99 | ASSERT(r == 0); |
100 | r = uv_signal_init(&loop, &signal1b); |
101 | ASSERT(r == 0); |
102 | r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); |
103 | ASSERT(r == 0); |
104 | } |
105 | |
106 | if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { |
107 | r = uv_signal_init(&loop, &signal2); |
108 | ASSERT(r == 0); |
109 | r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); |
110 | ASSERT(r == 0); |
111 | } |
112 | |
113 | /* Signal watchers are now set up. */ |
114 | uv_sem_post(&sem); |
115 | |
116 | /* Wait for all signals. The signal callbacks stop the watcher, so uv_run |
117 | * will return when all signal watchers caught a signal. |
118 | */ |
119 | r = uv_run(&loop, UV_RUN_DEFAULT); |
120 | ASSERT(r == 0); |
121 | |
122 | /* Restart the signal watchers. */ |
123 | if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { |
124 | r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1); |
125 | ASSERT(r == 0); |
126 | r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1); |
127 | ASSERT(r == 0); |
128 | } |
129 | |
130 | if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { |
131 | r = uv_signal_start(&signal2, signal2_cb, SIGUSR2); |
132 | ASSERT(r == 0); |
133 | } |
134 | |
135 | /* Wait for signals once more. */ |
136 | uv_sem_post(&sem); |
137 | |
138 | r = uv_run(&loop, UV_RUN_DEFAULT); |
139 | ASSERT(r == 0); |
140 | |
141 | /* Close the watchers. */ |
142 | if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) { |
143 | uv_close((uv_handle_t*) &signal1a, NULL); |
144 | uv_close((uv_handle_t*) &signal1b, NULL); |
145 | } |
146 | |
147 | if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) { |
148 | uv_close((uv_handle_t*) &signal2, NULL); |
149 | } |
150 | |
151 | /* Wait for the signal watchers to close. */ |
152 | r = uv_run(&loop, UV_RUN_DEFAULT); |
153 | ASSERT(r == 0); |
154 | |
155 | uv_loop_close(&loop); |
156 | } |
157 | |
158 | |
159 | static void signal_unexpected_cb(uv_signal_t* handle, int signum) { |
160 | ASSERT(0 && "signal_unexpected_cb should never be called" ); |
161 | } |
162 | |
163 | |
164 | static void loop_creating_worker(void* context) { |
165 | (void) context; |
166 | |
167 | do { |
168 | uv_loop_t *loop; |
169 | uv_signal_t signal; |
170 | int r; |
171 | |
172 | loop = malloc(sizeof(*loop)); |
173 | ASSERT(loop != NULL); |
174 | ASSERT(0 == uv_loop_init(loop)); |
175 | |
176 | r = uv_signal_init(loop, &signal); |
177 | ASSERT(r == 0); |
178 | |
179 | r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM); |
180 | ASSERT(r == 0); |
181 | |
182 | uv_close((uv_handle_t*) &signal, NULL); |
183 | |
184 | r = uv_run(loop, UV_RUN_DEFAULT); |
185 | ASSERT(r == 0); |
186 | |
187 | uv_loop_close(loop); |
188 | free(loop); |
189 | |
190 | increment_counter(&loop_creation_counter); |
191 | } while (!stop); |
192 | } |
193 | |
194 | |
195 | TEST_IMPL(signal_multiple_loops) { |
196 | #if defined(__CYGWIN__) || defined(__MSYS__) |
197 | /* FIXME: This test needs more investigation. Somehow the `read` in |
198 | uv__signal_lock fails spuriously with EACCES or even EAGAIN even |
199 | though it is supposed to be blocking. Also the test hangs during |
200 | thread setup occasionally. */ |
201 | RETURN_SKIP("FIXME: This test needs more investigation on Cygwin" ); |
202 | #endif |
203 | uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS]; |
204 | uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS]; |
205 | enum signal_action action; |
206 | sigset_t sigset; |
207 | int i; |
208 | int r; |
209 | |
210 | r = uv_sem_init(&sem, 0); |
211 | ASSERT(r == 0); |
212 | |
213 | r = uv_mutex_init(&counter_lock); |
214 | ASSERT(r == 0); |
215 | |
216 | /* Create a couple of threads that create a destroy loops continuously. */ |
217 | for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { |
218 | r = uv_thread_create(&loop_creating_threads[i], |
219 | loop_creating_worker, |
220 | NULL); |
221 | ASSERT(r == 0); |
222 | } |
223 | |
224 | /* Create a couple of threads that actually handle signals. */ |
225 | for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) { |
226 | switch (i % 3) { |
227 | case 0: action = ONLY_SIGUSR1; break; |
228 | case 1: action = ONLY_SIGUSR2; break; |
229 | case 2: action = SIGUSR1_AND_SIGUSR2; break; |
230 | } |
231 | |
232 | r = uv_thread_create(&signal_handling_threads[i], |
233 | signal_handling_worker, |
234 | (void*) (uintptr_t) action); |
235 | ASSERT(r == 0); |
236 | } |
237 | |
238 | /* Wait until all threads have started and set up their signal watchers. */ |
239 | for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) |
240 | uv_sem_wait(&sem); |
241 | |
242 | r = kill(getpid(), SIGUSR1); |
243 | ASSERT(r == 0); |
244 | r = kill(getpid(), SIGUSR2); |
245 | ASSERT(r == 0); |
246 | |
247 | /* Wait for all threads to handle these signals. */ |
248 | for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) |
249 | uv_sem_wait(&sem); |
250 | |
251 | /* Block all signals to this thread, so we are sure that from here the signal |
252 | * handler runs in another thread. This is more likely to catch thread and |
253 | * signal safety issues if there are any. |
254 | */ |
255 | sigfillset(&sigset); |
256 | pthread_sigmask(SIG_SETMASK, &sigset, NULL); |
257 | |
258 | r = kill(getpid(), SIGUSR1); |
259 | ASSERT(r == 0); |
260 | r = kill(getpid(), SIGUSR2); |
261 | ASSERT(r == 0); |
262 | |
263 | /* Wait for all signal handling threads to exit. */ |
264 | for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) { |
265 | r = uv_thread_join(&signal_handling_threads[i]); |
266 | ASSERT(r == 0); |
267 | } |
268 | |
269 | /* Tell all loop creating threads to stop. */ |
270 | stop = 1; |
271 | |
272 | /* Wait for all loop creating threads to exit. */ |
273 | for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) { |
274 | r = uv_thread_join(&loop_creating_threads[i]); |
275 | ASSERT(r == 0); |
276 | } |
277 | |
278 | uv_sem_destroy(&sem); |
279 | printf("signal1_cb calls: %d\n" , signal1_cb_counter); |
280 | printf("signal2_cb calls: %d\n" , signal2_cb_counter); |
281 | printf("loops created and destroyed: %d\n" , loop_creation_counter); |
282 | |
283 | /* The division by three reflects the fact that we spawn three different |
284 | * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each. |
285 | */ |
286 | ASSERT(signal1_cb_counter == 8 * (NUM_SIGNAL_HANDLING_THREADS / 3)); |
287 | ASSERT(signal2_cb_counter == 4 * (NUM_SIGNAL_HANDLING_THREADS / 3)); |
288 | |
289 | /* We don't know exactly how much loops will be created and destroyed, but at |
290 | * least there should be 1 for every loop creating thread. |
291 | */ |
292 | ASSERT(loop_creation_counter >= NUM_LOOP_CREATING_THREADS); |
293 | |
294 | MAKE_VALGRIND_HAPPY(); |
295 | return 0; |
296 | } |
297 | |
298 | #else |
299 | |
300 | typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ |
301 | |
302 | #endif /* !_WIN32 */ |
303 | |