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; }
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; }