Blame test/test-fork.c

Packit b5b901
/* Copyright libuv project contributors. All rights reserved.
Packit b5b901
 *
Packit b5b901
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit b5b901
 * of this software and associated documentation files (the "Software"), to
Packit b5b901
 * deal in the Software without restriction, including without limitation the
Packit b5b901
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit b5b901
 * sell copies of the Software, and to permit persons to whom the Software is
Packit b5b901
 * furnished to do so, subject to the following conditions:
Packit b5b901
 *
Packit b5b901
 * The above copyright notice and this permission notice shall be included in
Packit b5b901
 * all copies or substantial portions of the Software.
Packit b5b901
 *
Packit b5b901
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit b5b901
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit b5b901
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit b5b901
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit b5b901
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit b5b901
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit b5b901
 * IN THE SOFTWARE.
Packit b5b901
 */
Packit b5b901
Packit b5b901
/* These tests are Unix only. */
Packit b5b901
#ifndef _WIN32
Packit b5b901
Packit b5b901
#include <unistd.h>
Packit b5b901
#include <sys/wait.h>
Packit b5b901
#include <sys/socket.h>
Packit b5b901
#include <string.h>
Packit b5b901
Packit b5b901
#include "uv.h"
Packit b5b901
#include "task.h"
Packit b5b901
Packit b5b901
static int timer_cb_called;
Packit b5b901
static int socket_cb_called;
Packit b5b901
Packit b5b901
static void timer_cb(uv_timer_t* timer) {
Packit b5b901
  timer_cb_called++;
Packit b5b901
  uv_close((uv_handle_t*) timer, NULL);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int socket_cb_read_fd;
Packit b5b901
static int socket_cb_read_size;
Packit b5b901
static char socket_cb_read_buf[1024];
Packit b5b901
Packit b5b901
Packit b5b901
static void socket_cb(uv_poll_t* poll, int status, int events) {
Packit b5b901
  ssize_t cnt;
Packit b5b901
  socket_cb_called++;
Packit b5b901
  ASSERT(0 == status);
Packit b5b901
  printf("Socket cb got events %d\n", events);
Packit b5b901
  ASSERT(UV_READABLE == (events & UV_READABLE));
Packit b5b901
  if (socket_cb_read_fd) {
Packit b5b901
    cnt = read(socket_cb_read_fd, socket_cb_read_buf, socket_cb_read_size);
Packit b5b901
    ASSERT(cnt == socket_cb_read_size);
Packit b5b901
  }
Packit b5b901
  uv_close((uv_handle_t*) poll, NULL);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void run_timer_loop_once(void) {
Packit b5b901
  uv_loop_t* loop;
Packit b5b901
  uv_timer_t timer_handle;
Packit b5b901
Packit b5b901
  loop = uv_default_loop();
Packit b5b901
Packit b5b901
  timer_cb_called = 0; /* Reset for the child. */
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_timer_init(loop, &timer_handle));
Packit b5b901
  ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 1, 0));
Packit b5b901
  ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
Packit b5b901
  ASSERT(1 == timer_cb_called);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void assert_wait_child(pid_t child_pid) {
Packit b5b901
  pid_t waited_pid;
Packit b5b901
  int child_stat;
Packit b5b901
Packit b5b901
  waited_pid = waitpid(child_pid, &child_stat, 0);
Packit b5b901
  printf("Waited pid is %d with status %d\n", waited_pid, child_stat);
Packit b5b901
  if (waited_pid == -1) {
Packit b5b901
    perror("Failed to wait");
Packit b5b901
  }
Packit b5b901
  ASSERT(child_pid == waited_pid);
Packit b5b901
  ASSERT(WIFEXITED(child_stat)); /* Clean exit, not a signal. */
Packit b5b901
  ASSERT(!WIFSIGNALED(child_stat));
Packit b5b901
  ASSERT(0 == WEXITSTATUS(child_stat));
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_timer) {
Packit b5b901
  /* Timers continue to work after we fork. */
Packit b5b901
Packit b5b901
  /*
Packit b5b901
   * Establish the loop before we fork to make sure that it
Packit b5b901
   * has state to get reset after the fork.
Packit b5b901
   */
Packit b5b901
  pid_t child_pid;
Packit b5b901
Packit b5b901
  run_timer_loop_once();
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    run_timer_loop_once();
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_socketpair) {
Packit b5b901
  /* A socket opened in the parent and accept'd in the
Packit b5b901
     child works after a fork. */
Packit b5b901
  pid_t child_pid;
Packit b5b901
  int socket_fds[2];
Packit b5b901
  uv_poll_t poll_handle;
Packit b5b901
Packit b5b901
  /* Prime the loop. */
Packit b5b901
  run_timer_loop_once();
Packit b5b901
Packit b5b901
  ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
Packit b5b901
Packit b5b901
  /* Create the server watcher in the parent, use it in the child. */
Packit b5b901
  ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    ASSERT(0 == socket_cb_called);
Packit b5b901
    ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
Packit b5b901
    printf("Going to run the loop in the child\n");
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
    ASSERT(1 == socket_cb_called);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_socketpair_started) {
Packit b5b901
  /* A socket opened in the parent and accept'd in the
Packit b5b901
     child works after a fork, even if the watcher was already
Packit b5b901
     started, and then stopped in the parent. */
Packit b5b901
  pid_t child_pid;
Packit b5b901
  int socket_fds[2];
Packit b5b901
  int sync_pipe[2];
Packit b5b901
  char sync_buf[1];
Packit b5b901
  uv_poll_t poll_handle;
Packit b5b901
Packit b5b901
  ASSERT(0 == pipe(sync_pipe));
Packit b5b901
Packit b5b901
  /* Prime the loop. */
Packit b5b901
  run_timer_loop_once();
Packit b5b901
Packit b5b901
  ASSERT(0 == socketpair(AF_UNIX, SOCK_STREAM, 0, socket_fds));
Packit b5b901
Packit b5b901
  /* Create and start the server watcher in the parent, use it in the child. */
Packit b5b901
  ASSERT(0 == uv_poll_init(uv_default_loop(), &poll_handle, socket_fds[0]));
Packit b5b901
  ASSERT(0 == uv_poll_start(&poll_handle, UV_READABLE, socket_cb));
Packit b5b901
Packit b5b901
  /* Run the loop AFTER the poll watcher is registered to make sure it
Packit b5b901
     gets passed to the kernel. Use NOWAIT and expect a non-zero
Packit b5b901
     return to prove the poll watcher is active.
Packit b5b901
  */
Packit b5b901
  ASSERT(1 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    ASSERT(0 == uv_poll_stop(&poll_handle));
Packit b5b901
    uv_close((uv_handle_t*)&poll_handle, NULL);
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
    ASSERT(0 == socket_cb_called);
Packit b5b901
    ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert child */
Packit b5b901
    ASSERT(3 == send(socket_fds[1], "hi\n", 3, 0));
Packit b5b901
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
    ASSERT(0 == socket_cb_called);
Packit b5b901
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    printf("Child is %d\n", getpid());
Packit b5b901
    ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for parent */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    ASSERT(0 == socket_cb_called);
Packit b5b901
Packit b5b901
    printf("Going to run the loop in the child\n");
Packit b5b901
    socket_cb_read_fd = socket_fds[0];
Packit b5b901
    socket_cb_read_size = 3;
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT));
Packit b5b901
    ASSERT(1 == socket_cb_called);
Packit b5b901
    printf("Buf %s\n", socket_cb_read_buf);
Packit b5b901
    ASSERT(0 == strcmp("hi\n", socket_cb_read_buf));
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int fork_signal_cb_called;
Packit b5b901
Packit b5b901
void fork_signal_to_child_cb(uv_signal_t* handle, int signum)
Packit b5b901
{
Packit b5b901
  fork_signal_cb_called = signum;
Packit b5b901
  uv_close((uv_handle_t*)handle, NULL);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_signal_to_child) {
Packit b5b901
  /* A signal handler installed before forking
Packit b5b901
     is run only in the child when the child is signalled. */
Packit b5b901
  uv_signal_t signal_handle;
Packit b5b901
  pid_t child_pid;
Packit b5b901
  int sync_pipe[2];
Packit b5b901
  char sync_buf[1];
Packit b5b901
Packit b5b901
  fork_signal_cb_called = 0;    /* reset */
Packit b5b901
Packit b5b901
  ASSERT(0 == pipe(sync_pipe));
Packit b5b901
Packit b5b901
  /* Prime the loop. */
Packit b5b901
  run_timer_loop_once();
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
Packit b5b901
  ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
Packit b5b901
    ASSERT(0 == kill(child_pid, SIGUSR1));
Packit b5b901
    /* Run the loop, make sure we don't get the signal. */
Packit b5b901
    printf("Running loop in parent\n");
Packit b5b901
    uv_unref((uv_handle_t*)&signal_handle);
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_NOWAIT));
Packit b5b901
    ASSERT(0 == fork_signal_cb_called);
Packit b5b901
    printf("Waiting for child in parent\n");
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
Packit b5b901
    /* Get the signal. */
Packit b5b901
    ASSERT(0 != uv_loop_alive(uv_default_loop()));
Packit b5b901
    printf("Running loop in child\n");
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
Packit b5b901
    ASSERT(SIGUSR1 == fork_signal_cb_called);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_signal_to_child_closed) {
Packit b5b901
  /* A signal handler installed before forking
Packit b5b901
     doesn't get received anywhere when the child is signalled,
Packit b5b901
     but isnt running the loop. */
Packit b5b901
  uv_signal_t signal_handle;
Packit b5b901
  pid_t child_pid;
Packit b5b901
  int sync_pipe[2];
Packit b5b901
  int sync_pipe2[2];
Packit b5b901
  char sync_buf[1];
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  fork_signal_cb_called = 0;    /* reset */
Packit b5b901
Packit b5b901
  ASSERT(0 == pipe(sync_pipe));
Packit b5b901
  ASSERT(0 == pipe(sync_pipe2));
Packit b5b901
Packit b5b901
  /* Prime the loop. */
Packit b5b901
  run_timer_loop_once();
Packit b5b901
Packit b5b901
  ASSERT(0 == uv_signal_init(uv_default_loop(), &signal_handle));
Packit b5b901
  ASSERT(0 == uv_signal_start(&signal_handle, fork_signal_to_child_cb, SIGUSR1));
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    printf("Wating on child in parent\n");
Packit b5b901
    ASSERT(1 == read(sync_pipe[0], sync_buf, 1)); /* wait for child */
Packit b5b901
    printf("Parent killing child\n");
Packit b5b901
    ASSERT(0 == kill(child_pid, SIGUSR1));
Packit b5b901
    /* Run the loop, make sure we don't get the signal. */
Packit b5b901
    printf("Running loop in parent\n");
Packit b5b901
    uv_unref((uv_handle_t*)&signal_handle); /* so the loop can exit;
Packit b5b901
                                               we *shouldn't* get any signals */
Packit b5b901
    run_timer_loop_once(); /* but while we share a pipe, we do, so
Packit b5b901
                              have something active. */
Packit b5b901
    ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE));
Packit b5b901
    printf("Signal in parent %d\n", fork_signal_cb_called);
Packit b5b901
    ASSERT(0 == fork_signal_cb_called);
Packit b5b901
    ASSERT(1 == write(sync_pipe2[1], "1", 1)); /* alert child */
Packit b5b901
    printf("Waiting for child in parent\n");
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* Child. Our signal handler should still be installed. */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    printf("Checking loop in child\n");
Packit b5b901
    ASSERT(0 != uv_loop_alive(uv_default_loop()));
Packit b5b901
    printf("Alerting parent in child\n");
Packit b5b901
    ASSERT(1 == write(sync_pipe[1], "1", 1)); /* alert parent */
Packit b5b901
    /* Don't run the loop. Wait for the parent to call us */
Packit b5b901
    printf("Waiting on parent in child\n");
Packit b5b901
    /* Wait for parent. read may fail if the parent tripped an ASSERT
Packit b5b901
       and exited, so this ASSERT is generous.
Packit b5b901
    */
Packit b5b901
    r = read(sync_pipe2[0], sync_buf, 1);
Packit b5b901
    ASSERT(-1 <= r && r <= 1);
Packit b5b901
    ASSERT(0 == fork_signal_cb_called);
Packit b5b901
    printf("Exiting child \n");
Packit b5b901
    /* Note that we're deliberately not running the loop
Packit b5b901
     * in the child, and also not closing the loop's handles,
Packit b5b901
     * so the child default loop can't be cleanly closed.
Packit b5b901
     * We need to explicitly exit to avoid an automatic failure
Packit b5b901
     * in that case.
Packit b5b901
     */
Packit b5b901
    exit(0);
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void create_file(const char* name) {
Packit b5b901
  int r;
Packit b5b901
  uv_file file;
Packit b5b901
  uv_fs_t req;
Packit b5b901
Packit b5b901
  r = uv_fs_open(NULL, &req, name, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR, NULL);
Packit b5b901
  ASSERT(r >= 0);
Packit b5b901
  file = r;
Packit b5b901
  uv_fs_req_cleanup(&req;;
Packit b5b901
  r = uv_fs_close(NULL, &req, file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&req;;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void touch_file(const char* name) {
Packit b5b901
  int r;
Packit b5b901
  uv_file file;
Packit b5b901
  uv_fs_t req;
Packit b5b901
  uv_buf_t buf;
Packit b5b901
Packit b5b901
  r = uv_fs_open(NULL, &req, name, O_RDWR, 0, NULL);
Packit b5b901
  ASSERT(r >= 0);
Packit b5b901
  file = r;
Packit b5b901
  uv_fs_req_cleanup(&req;;
Packit b5b901
Packit b5b901
  buf = uv_buf_init("foo", 4);
Packit b5b901
  r = uv_fs_write(NULL, &req, file, &buf, 1, -1, NULL);
Packit b5b901
  ASSERT(r >= 0);
Packit b5b901
  uv_fs_req_cleanup(&req;;
Packit b5b901
Packit b5b901
  r = uv_fs_close(NULL, &req, file, NULL);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  uv_fs_req_cleanup(&req;;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int timer_cb_touch_called;
Packit b5b901
Packit b5b901
static void timer_cb_touch(uv_timer_t* timer) {
Packit b5b901
  uv_close((uv_handle_t*)timer, NULL);
Packit b5b901
  touch_file("watch_file");
Packit b5b901
  timer_cb_touch_called++;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int fs_event_cb_called;
Packit b5b901
Packit b5b901
static void fs_event_cb_file_current_dir(uv_fs_event_t* handle,
Packit b5b901
                                         const char* filename,
Packit b5b901
                                         int events,
Packit b5b901
                                         int status) {
Packit b5b901
  ASSERT(fs_event_cb_called == 0);
Packit b5b901
  ++fs_event_cb_called;
Packit b5b901
  ASSERT(status == 0);
Packit b5b901
#if defined(__APPLE__) || defined(__linux__)
Packit b5b901
  ASSERT(strcmp(filename, "watch_file") == 0);
Packit b5b901
#else
Packit b5b901
  ASSERT(filename == NULL || strcmp(filename, "watch_file") == 0);
Packit b5b901
#endif
Packit b5b901
  uv_close((uv_handle_t*)handle, NULL);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void assert_watch_file_current_dir(uv_loop_t* const loop, int file_or_dir) {
Packit b5b901
  uv_timer_t timer;
Packit b5b901
  uv_fs_event_t fs_event;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  /* Setup */
Packit b5b901
  remove("watch_file");
Packit b5b901
  create_file("watch_file");
Packit b5b901
Packit b5b901
  r = uv_fs_event_init(loop, &fs_event);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  /* watching a dir is the only way to get fsevents involved on apple
Packit b5b901
     platforms */
Packit b5b901
  r = uv_fs_event_start(&fs_event,
Packit b5b901
                        fs_event_cb_file_current_dir,
Packit b5b901
                        file_or_dir == 1 ? "." : "watch_file",
Packit b5b901
                        0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_init(loop, &timer;;
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  ASSERT(timer_cb_touch_called == 0);
Packit b5b901
  ASSERT(fs_event_cb_called == 0);
Packit b5b901
Packit b5b901
  uv_run(loop, UV_RUN_DEFAULT);
Packit b5b901
Packit b5b901
  ASSERT(timer_cb_touch_called == 1);
Packit b5b901
  ASSERT(fs_event_cb_called == 1);
Packit b5b901
Packit b5b901
  /* Cleanup */
Packit b5b901
  remove("watch_file");
Packit b5b901
  fs_event_cb_called = 0;
Packit b5b901
  timer_cb_touch_called = 0;
Packit b5b901
  uv_run(loop, UV_RUN_DEFAULT); /* flush pending closes */
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#define FS_TEST_FILE 0
Packit b5b901
#define FS_TEST_DIR 1
Packit b5b901
Packit b5b901
static int _do_fork_fs_events_child(int file_or_dir) {
Packit b5b901
  /* basic fsevents work in the child after a fork */
Packit b5b901
  pid_t child_pid;
Packit b5b901
  uv_loop_t loop;
Packit b5b901
Packit b5b901
  /* Watch in the parent, prime the loop and/or threads. */
Packit b5b901
  assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    /* Ee can watch in a new loop, but dirs only work
Packit b5b901
       if we're on linux. */
Packit b5b901
#if defined(__APPLE__)
Packit b5b901
    file_or_dir = FS_TEST_FILE;
Packit b5b901
#endif
Packit b5b901
    printf("Running child\n");
Packit b5b901
    uv_loop_init(&loop);
Packit b5b901
    printf("Child first watch\n");
Packit b5b901
    assert_watch_file_current_dir(&loop, file_or_dir);
Packit b5b901
    ASSERT(0 == uv_loop_close(&loop);;
Packit b5b901
    printf("Child second watch default loop\n");
Packit b5b901
    /* Ee can watch in the default loop. */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    /* On some platforms (OS X), if we don't update the time now,
Packit b5b901
     * the timer cb fires before the event loop enters uv__io_poll,
Packit b5b901
     * instead of after, meaning we don't see the change! This may be
Packit b5b901
     * a general race.
Packit b5b901
     */
Packit b5b901
    uv_update_time(uv_default_loop());
Packit b5b901
    assert_watch_file_current_dir(uv_default_loop(), file_or_dir);
Packit b5b901
Packit b5b901
    /* We can close the parent loop successfully too. This is
Packit b5b901
       especially important on Apple platforms where if we're not
Packit b5b901
       careful trying to touch the CFRunLoop, even just to shut it
Packit b5b901
       down, that we allocated in the FS_TEST_DIR case would crash. */
Packit b5b901
    ASSERT(0 == uv_loop_close(uv_default_loop()));
Packit b5b901
Packit b5b901
    printf("Exiting child \n");
Packit b5b901
  }
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_fs_events_child) {
Packit b5b901
#if defined(NO_FS_EVENTS)
Packit b5b901
  RETURN_SKIP(NO_FS_EVENTS);
Packit b5b901
#endif
Packit b5b901
  return _do_fork_fs_events_child(FS_TEST_FILE);
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_fs_events_child_dir) {
Packit b5b901
#if defined(NO_FS_EVENTS)
Packit b5b901
  RETURN_SKIP(NO_FS_EVENTS);
Packit b5b901
#endif
Packit b5b901
#if defined(__APPLE__) || defined (__linux__)
Packit b5b901
  return _do_fork_fs_events_child(FS_TEST_DIR);
Packit b5b901
#else
Packit b5b901
  /* You can't spin up a cfrunloop thread on an apple platform
Packit b5b901
     and then fork. See
Packit b5b901
     http://objectivistc.tumblr.com/post/16187948939/you-must-exec-a-core-foundation-fork-safety-tale
Packit b5b901
  */
Packit b5b901
  return 0;
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
TEST_IMPL(fork_fs_events_file_parent_child) {
Packit b5b901
#if defined(NO_FS_EVENTS)
Packit b5b901
  RETURN_SKIP(NO_FS_EVENTS);
Packit b5b901
#endif
Packit b5b901
#if defined(__sun) || defined(_AIX) || defined(__MVS__)
Packit b5b901
  /* It's not possible to implement this without additional
Packit b5b901
   * bookkeeping on SunOS. For AIX it is possible, but has to be
Packit b5b901
   * written. See https://github.com/libuv/libuv/pull/846#issuecomment-287170420
Packit b5b901
   * TODO: On z/OS, we need to open another message queue and subscribe to the
Packit b5b901
   * same events as the parent.
Packit b5b901
   */
Packit b5b901
  return 0;
Packit b5b901
#else
Packit b5b901
  /* Establishing a started fs events watcher in the parent should
Packit b5b901
     still work in the child. */
Packit b5b901
  uv_timer_t timer;
Packit b5b901
  uv_fs_event_t fs_event;
Packit b5b901
  int r;
Packit b5b901
  pid_t child_pid;
Packit b5b901
  uv_loop_t* loop;
Packit b5b901
Packit b5b901
  loop = uv_default_loop();
Packit b5b901
Packit b5b901
  /* Setup */
Packit b5b901
  remove("watch_file");
Packit b5b901
  create_file("watch_file");
Packit b5b901
Packit b5b901
  r = uv_fs_event_init(loop, &fs_event);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  r = uv_fs_event_start(&fs_event,
Packit b5b901
                        fs_event_cb_file_current_dir,
Packit b5b901
                        "watch_file",
Packit b5b901
                        0);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  r = uv_timer_init(loop, &timer;;
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* parent */
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* child */
Packit b5b901
    printf("Running child\n");
Packit b5b901
    ASSERT(0 == uv_loop_fork(loop));
Packit b5b901
Packit b5b901
    r = uv_timer_start(&timer, timer_cb_touch, 100, 0);
Packit b5b901
    ASSERT(r == 0);
Packit b5b901
Packit b5b901
    ASSERT(timer_cb_touch_called == 0);
Packit b5b901
    ASSERT(fs_event_cb_called == 0);
Packit b5b901
    printf("Running loop in child \n");
Packit b5b901
    uv_run(loop, UV_RUN_DEFAULT);
Packit b5b901
Packit b5b901
    ASSERT(timer_cb_touch_called == 1);
Packit b5b901
    ASSERT(fs_event_cb_called == 1);
Packit b5b901
Packit b5b901
    /* Cleanup */
Packit b5b901
    remove("watch_file");
Packit b5b901
    fs_event_cb_called = 0;
Packit b5b901
    timer_cb_touch_called = 0;
Packit b5b901
    uv_run(loop, UV_RUN_DEFAULT); /* Flush pending closes. */
Packit b5b901
  }
Packit b5b901
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
#endif
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static int work_cb_count;
Packit b5b901
static int after_work_cb_count;
Packit b5b901
Packit b5b901
Packit b5b901
static void work_cb(uv_work_t* req) {
Packit b5b901
  work_cb_count++;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void after_work_cb(uv_work_t* req, int status) {
Packit b5b901
  ASSERT(status == 0);
Packit b5b901
  after_work_cb_count++;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
static void assert_run_work(uv_loop_t* const loop) {
Packit b5b901
  uv_work_t work_req;
Packit b5b901
  int r;
Packit b5b901
Packit b5b901
  ASSERT(work_cb_count == 0);
Packit b5b901
  ASSERT(after_work_cb_count == 0);
Packit b5b901
  printf("Queue in %d\n", getpid());
Packit b5b901
  r = uv_queue_work(loop, &work_req, work_cb, after_work_cb);
Packit b5b901
  ASSERT(r == 0);
Packit b5b901
  printf("Running in %d\n", getpid());
Packit b5b901
  uv_run(loop, UV_RUN_DEFAULT);
Packit b5b901
Packit b5b901
  ASSERT(work_cb_count == 1);
Packit b5b901
  ASSERT(after_work_cb_count == 1);
Packit b5b901
Packit b5b901
  /* cleanup  */
Packit b5b901
  work_cb_count = 0;
Packit b5b901
  after_work_cb_count = 0;
Packit b5b901
}
Packit b5b901
Packit b5b901
Packit b5b901
#ifndef __MVS__
Packit b5b901
TEST_IMPL(fork_threadpool_queue_work_simple) {
Packit b5b901
  /* The threadpool works in a child process. */
Packit b5b901
Packit b5b901
  pid_t child_pid;
Packit b5b901
  uv_loop_t loop;
Packit b5b901
Packit b5b901
  /* Prime the pool and default loop. */
Packit b5b901
  assert_run_work(uv_default_loop());
Packit b5b901
Packit b5b901
  child_pid = fork();
Packit b5b901
  ASSERT(child_pid != -1);
Packit b5b901
Packit b5b901
  if (child_pid != 0) {
Packit b5b901
    /* Parent. We can still run work. */
Packit b5b901
    assert_run_work(uv_default_loop());
Packit b5b901
    assert_wait_child(child_pid);
Packit b5b901
  } else {
Packit b5b901
    /* Child. We can work in a new loop. */
Packit b5b901
    printf("Running child in %d\n", getpid());
Packit b5b901
    uv_loop_init(&loop);
Packit b5b901
    printf("Child first watch\n");
Packit b5b901
    assert_run_work(&loop);
Packit b5b901
    uv_loop_close(&loop);
Packit b5b901
    printf("Child second watch default loop\n");
Packit b5b901
    /* We can work in the default loop. */
Packit b5b901
    ASSERT(0 == uv_loop_fork(uv_default_loop()));
Packit b5b901
    assert_run_work(uv_default_loop());
Packit b5b901
    printf("Exiting child \n");
Packit b5b901
  }
Packit b5b901
Packit b5b901
Packit b5b901
  MAKE_VALGRIND_HAPPY();
Packit b5b901
  return 0;
Packit b5b901
}
Packit b5b901
#endif /* !__MVS__ */
Packit b5b901
Packit Service e08953
#else
Packit Service e08953
Packit Service e08953
typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
Packit b5b901
Packit b5b901
#endif /* !_WIN32 */