1 | /* Copyright libuv project 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 | /* These tests are Unix only. */ |
23 | #ifndef _WIN32 |
24 | |
25 | #include <unistd.h> |
26 | #include <sys/wait.h> |
27 | #include <sys/socket.h> |
28 | #include <string.h> |
29 | |
30 | #include "uv.h" |
31 | #include "task.h" |
32 | |
33 | static int timer_cb_called; |
34 | static int socket_cb_called; |
35 | |
36 | static void timer_cb(uv_timer_t* timer) { |
37 | timer_cb_called++; |
38 | uv_close((uv_handle_t*) timer, NULL); |
39 | } |
40 | |
41 | |
42 | static int socket_cb_read_fd; |
43 | static int socket_cb_read_size; |
44 | static char socket_cb_read_buf[1024]; |
45 | |
46 | |
47 | static void socket_cb(uv_poll_t* poll, int status, int events) { |
48 | ssize_t cnt; |
49 | socket_cb_called++; |
50 | ASSERT(0 == status); |
51 | printf("Socket cb got events %d\n" , events); |
52 | ASSERT(UV_READABLE == (events & UV_READABLE)); |
53 | if (socket_cb_read_fd) { |
54 | cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size); |
55 | ASSERT(cnt == socket_cb_read_size); |
56 | } |
57 | uv_close((uv_handle_t*) poll, NULL); |
58 | } |
59 | |
60 | |
61 | static void run_timer_loop_once(void) { |
62 | uv_loop_t* loop; |
63 | uv_timer_t timer_handle; |
64 | |
65 | loop = uv_default_loop(); |
66 | |
67 | timer_cb_called = 0; /* Reset for the child. */ |
68 | |
69 | ASSERT(0 == uv_timer_init(loop, &timer_handle)); |
70 | ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0)); |
71 | ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); |
72 | ASSERT(1 == timer_cb_called); |
73 | } |
74 | |
75 | |
76 | static void assert_wait_child(pid_t child_pid) { |
77 | pid_t waited_pid; |
78 | int child_stat; |
79 | |
80 | waited_pid = waitpid(child_pid, &child_stat, 0); |
81 | printf("Waited pid is %d with status %d\n" , waited_pid, child_stat); |
82 | if (waited_pid == -1) { |
83 | perror("Failed to wait" ); |
84 | } |
85 | ASSERT(child_pid == waited_pid); |
86 | ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */ |
87 | ASSERT(!WIFSIGNALED(child_stat)); |
88 | ASSERT(0 == WEXITSTATUS(child_stat)); |
89 | } |
90 | |
91 | |
92 | TEST_IMPL(fork_timer) { |
93 | /* Timers continue to work after we fork. */ |
94 | |
95 | /* |
96 | * Establish the loop before we fork to make sure that it |
97 | * has state to get reset after the fork. |
98 | */ |
99 | pid_t child_pid; |
100 | |
101 | run_timer_loop_once(); |
102 | child_pid = fork(); |
103 | ASSERT(child_pid != -1); |
104 | |
105 | if (child_pid != 0) { |
106 | /* parent */ |
107 | assert_wait_child(child_pid); |
108 | } else { |
109 | /* child */ |
110 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
111 | run_timer_loop_once(); |
112 | } |
113 | |
114 | MAKE_VALGRIND_HAPPY(); |
115 | return 0; |
116 | } |
117 | |
118 | |
119 | TEST_IMPL(fork_socketpair) { |
120 | /* A socket opened in the parent and accept'd in the |
121 | child works after a fork. */ |
122 | pid_t child_pid; |
123 | int socket_fds[2]; |
124 | uv_poll_t poll_handle; |
125 | |
126 | /* Prime the loop. */ |
127 | run_timer_loop_once(); |
128 | |
129 | ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); |
130 | |
131 | /* Create the server watcher in the parent, use it in the child. */ |
132 | ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); |
133 | |
134 | child_pid = fork(); |
135 | ASSERT(child_pid != -1); |
136 | |
137 | if (child_pid != 0) { |
138 | /* parent */ |
139 | ASSERT(3 == send(socket_fds[1], "hi\n" , 3, 0)); |
140 | assert_wait_child(child_pid); |
141 | } else { |
142 | /* child */ |
143 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
144 | ASSERT(0 == socket_cb_called); |
145 | ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); |
146 | printf("Going to run the loop in the child\n" ); |
147 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); |
148 | ASSERT(1 == socket_cb_called); |
149 | } |
150 | |
151 | MAKE_VALGRIND_HAPPY(); |
152 | return 0; |
153 | } |
154 | |
155 | |
156 | TEST_IMPL(fork_socketpair_started) { |
157 | /* A socket opened in the parent and accept'd in the |
158 | child works after a fork, even if the watcher was already |
159 | started, and then stopped in the parent. */ |
160 | pid_t child_pid; |
161 | int socket_fds[2]; |
162 | int sync_pipe[2]; |
163 | char sync_buf[1]; |
164 | uv_poll_t poll_handle; |
165 | |
166 | ASSERT(0 == pipe(sync_pipe)); |
167 | |
168 | /* Prime the loop. */ |
169 | run_timer_loop_once(); |
170 | |
171 | ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds)); |
172 | |
173 | /* Create and start the server watcher in the parent, use it in the child. */ |
174 | ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0])); |
175 | ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb)); |
176 | |
177 | /* Run the loop AFTER the poll watcher is registered to make sure it |
178 | gets passed to the kernel. Use NOWAIT and expect a non-zero |
179 | return to prove the poll watcher is active. |
180 | */ |
181 | ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); |
182 | |
183 | child_pid = fork(); |
184 | ASSERT(child_pid != -1); |
185 | |
186 | if (child_pid != 0) { |
187 | /* parent */ |
188 | ASSERT(0 == uv_poll_stop(&poll_handle)); |
189 | uv_close((uv_handle_t*)&poll_handle, NULL); |
190 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); |
191 | ASSERT(0 == socket_cb_called); |
192 | ASSERT(1 == write(sync_pipe[1], "1" , 1)); /* alert child */ |
193 | ASSERT(3 == send(socket_fds[1], "hi\n" , 3, 0)); |
194 | |
195 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); |
196 | ASSERT(0 == socket_cb_called); |
197 | |
198 | assert_wait_child(child_pid); |
199 | } else { |
200 | /* child */ |
201 | printf("Child is %d\n" , getpid()); |
202 | ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */ |
203 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
204 | ASSERT(0 == socket_cb_called); |
205 | |
206 | printf("Going to run the loop in the child\n" ); |
207 | socket_cb_read_fd = socket_fds[0]; |
208 | socket_cb_read_size = 3; |
209 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); |
210 | ASSERT(1 == socket_cb_called); |
211 | printf("Buf %s\n" , socket_cb_read_buf); |
212 | ASSERT(0 == strcmp("hi\n" , socket_cb_read_buf)); |
213 | } |
214 | |
215 | MAKE_VALGRIND_HAPPY(); |
216 | return 0; |
217 | } |
218 | |
219 | |
220 | static int fork_signal_cb_called; |
221 | |
222 | void fork_signal_to_child_cb(uv_signal_t* handle, int signum) |
223 | { |
224 | fork_signal_cb_called = signum; |
225 | uv_close((uv_handle_t*)handle, NULL); |
226 | } |
227 | |
228 | |
229 | TEST_IMPL(fork_signal_to_child) { |
230 | /* A signal handler installed before forking |
231 | is run only in the child when the child is signalled. */ |
232 | uv_signal_t signal_handle; |
233 | pid_t child_pid; |
234 | int sync_pipe[2]; |
235 | char sync_buf[1]; |
236 | |
237 | fork_signal_cb_called = 0; /* reset */ |
238 | |
239 | ASSERT(0 == pipe(sync_pipe)); |
240 | |
241 | /* Prime the loop. */ |
242 | run_timer_loop_once(); |
243 | |
244 | ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); |
245 | ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); |
246 | |
247 | child_pid = fork(); |
248 | ASSERT(child_pid != -1); |
249 | |
250 | if (child_pid != 0) { |
251 | /* parent */ |
252 | ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ |
253 | ASSERT(0 == kill(child_pid, SIGUSR1)); |
254 | /* Run the loop, make sure we don't get the signal. */ |
255 | printf("Running loop in parent\n" ); |
256 | uv_unref((uv_handle_t*)&signal_handle); |
257 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT)); |
258 | ASSERT(0 == fork_signal_cb_called); |
259 | printf("Waiting for child in parent\n" ); |
260 | assert_wait_child(child_pid); |
261 | } else { |
262 | /* child */ |
263 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
264 | ASSERT(1 == write(sync_pipe[1], "1" , 1)); /* alert parent */ |
265 | /* Get the signal. */ |
266 | ASSERT(0 != uv_loop_alive(uv_default_loop())); |
267 | printf("Running loop in child\n" ); |
268 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); |
269 | ASSERT(SIGUSR1 == fork_signal_cb_called); |
270 | } |
271 | |
272 | MAKE_VALGRIND_HAPPY(); |
273 | return 0; |
274 | } |
275 | |
276 | |
277 | TEST_IMPL(fork_signal_to_child_closed) { |
278 | /* A signal handler installed before forking |
279 | doesn't get received anywhere when the child is signalled, |
280 | but isnt running the loop. */ |
281 | uv_signal_t signal_handle; |
282 | pid_t child_pid; |
283 | int sync_pipe[2]; |
284 | int sync_pipe2[2]; |
285 | char sync_buf[1]; |
286 | int r; |
287 | |
288 | fork_signal_cb_called = 0; /* reset */ |
289 | |
290 | ASSERT(0 == pipe(sync_pipe)); |
291 | ASSERT(0 == pipe(sync_pipe2)); |
292 | |
293 | /* Prime the loop. */ |
294 | run_timer_loop_once(); |
295 | |
296 | ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle)); |
297 | ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1)); |
298 | |
299 | child_pid = fork(); |
300 | ASSERT(child_pid != -1); |
301 | |
302 | if (child_pid != 0) { |
303 | /* parent */ |
304 | printf("Wating on child in parent\n" ); |
305 | ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */ |
306 | printf("Parent killing child\n" ); |
307 | ASSERT(0 == kill(child_pid, SIGUSR1)); |
308 | /* Run the loop, make sure we don't get the signal. */ |
309 | printf("Running loop in parent\n" ); |
310 | uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit; |
311 | we *shouldn't* get any signals */ |
312 | run_timer_loop_once(); /* but while we share a pipe, we do, so |
313 | have something active. */ |
314 | ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); |
315 | printf("Signal in parent %d\n" , fork_signal_cb_called); |
316 | ASSERT(0 == fork_signal_cb_called); |
317 | ASSERT(1 == write(sync_pipe2[1], "1" , 1)); /* alert child */ |
318 | printf("Waiting for child in parent\n" ); |
319 | assert_wait_child(child_pid); |
320 | } else { |
321 | /* Child. Our signal handler should still be installed. */ |
322 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
323 | printf("Checking loop in child\n" ); |
324 | ASSERT(0 != uv_loop_alive(uv_default_loop())); |
325 | printf("Alerting parent in child\n" ); |
326 | ASSERT(1 == write(sync_pipe[1], "1" , 1)); /* alert parent */ |
327 | /* Don't run the loop. Wait for the parent to call us */ |
328 | printf("Waiting on parent in child\n" ); |
329 | /* Wait for parent. read may fail if the parent tripped an ASSERT |
330 | and exited, so this ASSERT is generous. |
331 | */ |
332 | r = read(sync_pipe2[0], sync_buf, 1); |
333 | ASSERT(-1 <= r && r <= 1); |
334 | ASSERT(0 == fork_signal_cb_called); |
335 | printf("Exiting child \n" ); |
336 | /* Note that we're deliberately not running the loop |
337 | * in the child, and also not closing the loop's handles, |
338 | * so the child default loop can't be cleanly closed. |
339 | * We need to explicitly exit to avoid an automatic failure |
340 | * in that case. |
341 | */ |
342 | exit(0); |
343 | } |
344 | |
345 | MAKE_VALGRIND_HAPPY(); |
346 | return 0; |
347 | } |
348 | |
349 | |
350 | static void create_file(const char* name) { |
351 | int r; |
352 | uv_file file; |
353 | uv_fs_t req; |
354 | |
355 | r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL); |
356 | ASSERT(r >= 0); |
357 | file = r; |
358 | uv_fs_req_cleanup(&req); |
359 | r = uv_fs_close(NULL, &req, file, NULL); |
360 | ASSERT(r == 0); |
361 | uv_fs_req_cleanup(&req); |
362 | } |
363 | |
364 | |
365 | static void touch_file(const char* name) { |
366 | int r; |
367 | uv_file file; |
368 | uv_fs_t req; |
369 | uv_buf_t buf; |
370 | |
371 | r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL); |
372 | ASSERT(r >= 0); |
373 | file = r; |
374 | uv_fs_req_cleanup(&req); |
375 | |
376 | buf = uv_buf_init("foo" , 4); |
377 | r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL); |
378 | ASSERT(r >= 0); |
379 | uv_fs_req_cleanup(&req); |
380 | |
381 | r = uv_fs_close(NULL, &req, file, NULL); |
382 | ASSERT(r == 0); |
383 | uv_fs_req_cleanup(&req); |
384 | } |
385 | |
386 | |
387 | static int timer_cb_touch_called; |
388 | |
389 | static void timer_cb_touch(uv_timer_t* timer) { |
390 | uv_close((uv_handle_t*)timer, NULL); |
391 | touch_file("watch_file" ); |
392 | timer_cb_touch_called++; |
393 | } |
394 | |
395 | |
396 | static int fs_event_cb_called; |
397 | |
398 | static void fs_event_cb_file_current_dir(uv_fs_event_t* handle, |
399 | const char* filename, |
400 | int events, |
401 | int status) { |
402 | ASSERT(fs_event_cb_called == 0); |
403 | ++fs_event_cb_called; |
404 | ASSERT(status == 0); |
405 | #if defined(__APPLE__) || defined(__linux__) |
406 | ASSERT(strcmp(filename, "watch_file" ) == 0); |
407 | #else |
408 | ASSERT(filename == NULL || strcmp(filename, "watch_file" ) == 0); |
409 | #endif |
410 | uv_close((uv_handle_t*)handle, NULL); |
411 | } |
412 | |
413 | |
414 | static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) { |
415 | uv_timer_t timer; |
416 | uv_fs_event_t fs_event; |
417 | int r; |
418 | |
419 | /* Setup */ |
420 | remove("watch_file" ); |
421 | create_file("watch_file" ); |
422 | |
423 | r = uv_fs_event_init(loop, &fs_event); |
424 | ASSERT(r == 0); |
425 | /* watching a dir is the only way to get fsevents involved on apple |
426 | platforms */ |
427 | r = uv_fs_event_start(&fs_event, |
428 | fs_event_cb_file_current_dir, |
429 | file_or_dir == 1 ? "." : "watch_file" , |
430 | 0); |
431 | ASSERT(r == 0); |
432 | |
433 | r = uv_timer_init(loop, &timer); |
434 | ASSERT(r == 0); |
435 | |
436 | r = uv_timer_start(&timer, timer_cb_touch, 100, 0); |
437 | ASSERT(r == 0); |
438 | |
439 | ASSERT(timer_cb_touch_called == 0); |
440 | ASSERT(fs_event_cb_called == 0); |
441 | |
442 | uv_run(loop, UV_RUN_DEFAULT); |
443 | |
444 | ASSERT(timer_cb_touch_called == 1); |
445 | ASSERT(fs_event_cb_called == 1); |
446 | |
447 | /* Cleanup */ |
448 | remove("watch_file" ); |
449 | fs_event_cb_called = 0; |
450 | timer_cb_touch_called = 0; |
451 | uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */ |
452 | } |
453 | |
454 | |
455 | #define FS_TEST_FILE 0 |
456 | #define FS_TEST_DIR 1 |
457 | |
458 | static int _do_fork_fs_events_child(int file_or_dir) { |
459 | /* basic fsevents work in the child after a fork */ |
460 | pid_t child_pid; |
461 | uv_loop_t loop; |
462 | |
463 | /* Watch in the parent, prime the loop and/or threads. */ |
464 | assert_watch_file_current_dir(uv_default_loop(), file_or_dir); |
465 | child_pid = fork(); |
466 | ASSERT(child_pid != -1); |
467 | |
468 | if (child_pid != 0) { |
469 | /* parent */ |
470 | assert_wait_child(child_pid); |
471 | } else { |
472 | /* child */ |
473 | /* Ee can watch in a new loop, but dirs only work |
474 | if we're on linux. */ |
475 | #if defined(__APPLE__) |
476 | file_or_dir = FS_TEST_FILE; |
477 | #endif |
478 | printf("Running child\n" ); |
479 | uv_loop_init(&loop); |
480 | printf("Child first watch\n" ); |
481 | assert_watch_file_current_dir(&loop, file_or_dir); |
482 | ASSERT(0 == uv_loop_close(&loop)); |
483 | printf("Child second watch default loop\n" ); |
484 | /* Ee can watch in the default loop. */ |
485 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
486 | /* On some platforms (OS X), if we don't update the time now, |
487 | * the timer cb fires before the event loop enters uv__io_poll, |
488 | * instead of after, meaning we don't see the change! This may be |
489 | * a general race. |
490 | */ |
491 | uv_update_time(uv_default_loop()); |
492 | assert_watch_file_current_dir(uv_default_loop(), file_or_dir); |
493 | |
494 | /* We can close the parent loop successfully too. This is |
495 | especially important on Apple platforms where if we're not |
496 | careful trying to touch the CFRunLoop, even just to shut it |
497 | down, that we allocated in the FS_TEST_DIR case would crash. */ |
498 | ASSERT(0 == uv_loop_close(uv_default_loop())); |
499 | |
500 | printf("Exiting child \n" ); |
501 | } |
502 | |
503 | MAKE_VALGRIND_HAPPY(); |
504 | return 0; |
505 | |
506 | } |
507 | |
508 | |
509 | TEST_IMPL(fork_fs_events_child) { |
510 | #if defined(NO_FS_EVENTS) |
511 | RETURN_SKIP(NO_FS_EVENTS); |
512 | #endif |
513 | return _do_fork_fs_events_child(FS_TEST_FILE); |
514 | } |
515 | |
516 | |
517 | TEST_IMPL(fork_fs_events_child_dir) { |
518 | #if defined(NO_FS_EVENTS) |
519 | RETURN_SKIP(NO_FS_EVENTS); |
520 | #endif |
521 | #if defined(__APPLE__) || defined (__linux__) |
522 | return _do_fork_fs_events_child(FS_TEST_DIR); |
523 | #else |
524 | /* You can't spin up a cfrunloop thread on an apple platform |
525 | and then fork. See |
526 | http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale |
527 | */ |
528 | return 0; |
529 | #endif |
530 | } |
531 | |
532 | |
533 | TEST_IMPL(fork_fs_events_file_parent_child) { |
534 | #if defined(NO_FS_EVENTS) |
535 | RETURN_SKIP(NO_FS_EVENTS); |
536 | #endif |
537 | #if defined(__sun) || defined(_AIX) || defined(__MVS__) |
538 | /* It's not possible to implement this without additional |
539 | * bookkeeping on SunOS. For AIX it is possible, but has to be |
540 | * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420 |
541 | * TODO: On z/OS, we need to open another message queue and subscribe to the |
542 | * same events as the parent. |
543 | */ |
544 | return 0; |
545 | #else |
546 | /* Establishing a started fs events watcher in the parent should |
547 | still work in the child. */ |
548 | uv_timer_t timer; |
549 | uv_fs_event_t fs_event; |
550 | int r; |
551 | pid_t child_pid; |
552 | uv_loop_t* loop; |
553 | |
554 | loop = uv_default_loop(); |
555 | |
556 | /* Setup */ |
557 | remove("watch_file" ); |
558 | create_file("watch_file" ); |
559 | |
560 | r = uv_fs_event_init(loop, &fs_event); |
561 | ASSERT(r == 0); |
562 | r = uv_fs_event_start(&fs_event, |
563 | fs_event_cb_file_current_dir, |
564 | "watch_file" , |
565 | 0); |
566 | ASSERT(r == 0); |
567 | |
568 | r = uv_timer_init(loop, &timer); |
569 | ASSERT(r == 0); |
570 | |
571 | child_pid = fork(); |
572 | ASSERT(child_pid != -1); |
573 | if (child_pid != 0) { |
574 | /* parent */ |
575 | assert_wait_child(child_pid); |
576 | } else { |
577 | /* child */ |
578 | printf("Running child\n" ); |
579 | ASSERT(0 == uv_loop_fork(loop)); |
580 | |
581 | r = uv_timer_start(&timer, timer_cb_touch, 100, 0); |
582 | ASSERT(r == 0); |
583 | |
584 | ASSERT(timer_cb_touch_called == 0); |
585 | ASSERT(fs_event_cb_called == 0); |
586 | printf("Running loop in child \n" ); |
587 | uv_run(loop, UV_RUN_DEFAULT); |
588 | |
589 | ASSERT(timer_cb_touch_called == 1); |
590 | ASSERT(fs_event_cb_called == 1); |
591 | |
592 | /* Cleanup */ |
593 | remove("watch_file" ); |
594 | fs_event_cb_called = 0; |
595 | timer_cb_touch_called = 0; |
596 | uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */ |
597 | } |
598 | |
599 | |
600 | MAKE_VALGRIND_HAPPY(); |
601 | return 0; |
602 | #endif |
603 | } |
604 | |
605 | |
606 | static int work_cb_count; |
607 | static int after_work_cb_count; |
608 | |
609 | |
610 | static void work_cb(uv_work_t* req) { |
611 | work_cb_count++; |
612 | } |
613 | |
614 | |
615 | static void after_work_cb(uv_work_t* req, int status) { |
616 | ASSERT(status == 0); |
617 | after_work_cb_count++; |
618 | } |
619 | |
620 | |
621 | static void assert_run_work(uv_loop_t* const loop) { |
622 | uv_work_t work_req; |
623 | int r; |
624 | |
625 | ASSERT(work_cb_count == 0); |
626 | ASSERT(after_work_cb_count == 0); |
627 | printf("Queue in %d\n" , getpid()); |
628 | r = uv_queue_work(loop, &work_req, work_cb, after_work_cb); |
629 | ASSERT(r == 0); |
630 | printf("Running in %d\n" , getpid()); |
631 | uv_run(loop, UV_RUN_DEFAULT); |
632 | |
633 | ASSERT(work_cb_count == 1); |
634 | ASSERT(after_work_cb_count == 1); |
635 | |
636 | /* cleanup */ |
637 | work_cb_count = 0; |
638 | after_work_cb_count = 0; |
639 | } |
640 | |
641 | |
642 | #ifndef __MVS__ |
643 | TEST_IMPL(fork_threadpool_queue_work_simple) { |
644 | /* The threadpool works in a child process. */ |
645 | |
646 | pid_t child_pid; |
647 | uv_loop_t loop; |
648 | |
649 | /* Prime the pool and default loop. */ |
650 | assert_run_work(uv_default_loop()); |
651 | |
652 | child_pid = fork(); |
653 | ASSERT(child_pid != -1); |
654 | |
655 | if (child_pid != 0) { |
656 | /* Parent. We can still run work. */ |
657 | assert_run_work(uv_default_loop()); |
658 | assert_wait_child(child_pid); |
659 | } else { |
660 | /* Child. We can work in a new loop. */ |
661 | printf("Running child in %d\n" , getpid()); |
662 | uv_loop_init(&loop); |
663 | printf("Child first watch\n" ); |
664 | assert_run_work(&loop); |
665 | uv_loop_close(&loop); |
666 | printf("Child second watch default loop\n" ); |
667 | /* We can work in the default loop. */ |
668 | ASSERT(0 == uv_loop_fork(uv_default_loop())); |
669 | assert_run_work(uv_default_loop()); |
670 | printf("Exiting child \n" ); |
671 | } |
672 | |
673 | |
674 | MAKE_VALGRIND_HAPPY(); |
675 | return 0; |
676 | } |
677 | #endif /* !__MVS__ */ |
678 | |
679 | #else |
680 | |
681 | typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */ |
682 | |
683 | #endif /* !_WIN32 */ |
684 | |