Blame test/test-fork.c

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