Home | History | Annotate | Line # | Download | only in test
      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 
     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 
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    378 static void fork_signal_cb(uv_signal_t* h, int s) {
    379   fork_signal_cb_called = s;
    380 }
    381 static void empty_close_cb(uv_handle_t* h){}
    382 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    688 static void work_cb(uv_work_t* req) {
    689   work_cb_count++;
    690 }
    691 
    692 
    693 static void after_work_cb(uv_work_t* req, int status) {
    694   ASSERT_OK(status);
    695   after_work_cb_count++;
    696 }
    697 
    698 
    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__
    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