예제 #1
0
int parent_main(pid_t child_pid) {
  int kq;
  int status;
  sigset_t sigs;

  if (sigfillset(&sigs)                        == -1) { ERRMSG("sigfillset() failed");  goto kill_child; }
  if (sigprocmask(SIG_SETMASK, &sigs, NULL)    == -1) { ERRMSG("sigprocmask() failed"); goto kill_child; }
  if ((kq = kqueue())                          == -1) { ERRMSG("kqueue() failed"); goto kill_child; }
  if (poll_add(kq, STDIN_FILENO, EVFILT_READ)  == -1) { ERRMSG("poll_add() failed"); goto kill_child; }

  for (;;) {
    int i;
    enum HANDLE_RESULT handle_ret = IGNORE;
    struct kevent e[2];
    struct timespec timeout;
    timeout.tv_sec = 0;
    timeout.tv_nsec = 100 * 1000 * 1000; // 100ms

    int nfd = kevent(kq, NULL, 0, e, sizeof(e) / sizeof(struct kevent), &timeout);
    if (nfd == -1) { ERRMSG("kevent() failed"); goto kill_child; }
    if (nfd == 0) {
      int ret = waitpid(child_pid, &status, WNOHANG);
      if (ret == -1) { ERRMSG("waitpid() failed");  goto kill_child; }
      if (ret != 0)  { goto child_exited; }

      if (sigpending(&sigs) == -1) { ERRMSG("sigpending() failed"); goto kill_child; }
      handle_ret = handle_signal(&sigs, child_pid);
    }

    for (i = 0; i < nfd; i++) {
      int fd = e[i].ident;
      if (fd == STDIN_FILENO) {
        if (e[i].flags & EV_EOF) {
          handle_ret = handle_in_eof(fd, child_pid);
        }
      }
    }

    switch(handle_ret) {
    case KILL_CHILD:      goto kill_child;
    case WAIT_CHILD_EXIT: goto wait_child_exit;
    case IGNORE:          break;
    }
  }
  
 kill_child:
  if (kill(child_pid, SIGKILL) == -1) { ERR_EXIT("kill() failed"); }
  
 wait_child_exit:
  if (waitpid(child_pid, &status, 0) == -1) { ERR_EXIT("waitpid() failed"); }

 child_exited:
  if (WIFEXITED(status))   { return WEXITSTATUS(status); }
  if (WIFSIGNALED(status)) { return WTERMSIG(status) + 128; }
  return 1;
}
예제 #2
0
int parent_main(pid_t child_pid) {
  int epfd;
  int sigfd;
  int status;
  sigset_t sigs;

  if (sigfillset(&sigs)                           == -1) { ERRMSG("sigfillset() failed");  goto kill_child; }
  if (sigprocmask(SIG_SETMASK, &sigs, NULL)       == -1) { ERRMSG("sigprocmask() failed"); goto kill_child; }
  if ((sigfd = signalfd(-1, &sigs, SFD_NONBLOCK)) == -1) { ERRMSG("signalfd() failed");    goto kill_child; }

  if ((epfd = epoll_create(1))         == -1) { ERRMSG("epoll_create() failed"); goto kill_child; }
  if (epoll_add(epfd, sigfd, EPOLLIN)  == -1) { ERRMSG("epoll_add() failed"); goto kill_child; }
  if (epoll_add(epfd, STDIN_FILENO, 0) == -1) { ERRMSG("epoll_add() failed"); goto kill_child; }

  for (;;) {
    int i;
    enum HANDLE_RESULT handle_ret;
    struct epoll_event e[3];
    int nfd = epoll_wait(epfd, e, sizeof(e) / sizeof(struct epoll_event), 100);
    if (nfd == -1) { ERRMSG("epoll_wait() failed"); goto kill_child; }
    if (nfd == 0) {
      int ret = waitpid(child_pid, &status, WNOHANG);
      if (ret == -1) { ERRMSG("waitpid() failed");  goto kill_child; }
      if (ret != 0)  { goto child_exited; }
      continue;
    }

    for (i = 0; i < nfd; i++) {
      int fd = e[i].data.fd;
      if (fd == sigfd) { handle_ret = handle_signal(fd, child_pid); }
      else             { handle_ret = handle_in_eof(fd, child_pid); }

      switch(handle_ret) {
      case KILL_CHILD:      goto kill_child;
      case WAIT_CHILD_EXIT: goto wait_child_exit;
      }
    }
  }

 kill_child:
  if (kill(child_pid, SIGKILL) == -1) { ERR_EXIT("kill() failed"); }

 wait_child_exit:
  if (waitpid(child_pid, &status, 0) == -1) { ERR_EXIT("waitpid() failed"); }

 child_exited:
  if (WIFEXITED(status))   { return WEXITSTATUS(status); }
  if (WIFSIGNALED(status)) { return WTERMSIG(status) + 128; }
  return 1;
}