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