Run a function post-fork, with a timeout. Function can return int8_t only due to unix exit code limitations. Returns -ETIMEDOUT if timeout is reached.
| 28 | // int8_t only due to unix exit code limitations. Returns -ETIMEDOUT |
| 29 | // if timeout is reached. |
| 30 | static inline int fork_function( |
| 31 | int timeout, |
| 32 | std::ostream& errstr, |
| 33 | std::function<int8_t(void)> f) |
| 34 | { |
| 35 | // first fork the forker. |
| 36 | pid_t forker_pid = fork(); |
| 37 | if (forker_pid) { |
| 38 | // just wait |
| 39 | int status; |
| 40 | while (waitpid(forker_pid, &status, 0) == -1) { |
| 41 | ceph_assert(errno == EINTR); |
| 42 | } |
| 43 | if (WIFSIGNALED(status)) { |
| 44 | errstr << ": got signal: " << WTERMSIG(status) << "\n"; |
| 45 | return 128 + WTERMSIG(status); |
| 46 | } |
| 47 | if (WIFEXITED(status)) { |
| 48 | int8_t r = WEXITSTATUS(status); |
| 49 | errstr << ": exit status: " << (int)r << "\n"; |
| 50 | return r; |
| 51 | } |
| 52 | errstr << ": waitpid: unknown status returned\n"; |
| 53 | return -1; |
| 54 | } |
| 55 | |
| 56 | // we are forker (first child) |
| 57 | |
| 58 | // close all fds |
| 59 | #if defined(__linux__) && defined(SYS_close_range) |
| 60 | if (::syscall(SYS_close_range, STDERR_FILENO + 1, ~0U, 0)) |
| 61 | #endif |
| 62 | { |
| 63 | // fall back to manually closing |
| 64 | int maxfd = sysconf(_SC_OPEN_MAX); |
| 65 | if (maxfd == -1) |
| 66 | maxfd = 16384; |
| 67 | for (int fd = 0; fd <= maxfd; fd++) { |
| 68 | if (fd == STDIN_FILENO) |
| 69 | continue; |
| 70 | if (fd == STDOUT_FILENO) |
| 71 | continue; |
| 72 | if (fd == STDERR_FILENO) |
| 73 | continue; |
| 74 | ::close(fd); |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | sigset_t mask, oldmask; |
| 79 | int pid; |
| 80 | |
| 81 | // Restore default action for SIGTERM in case the parent process decided |
| 82 | // to ignore it. |
| 83 | if (signal(SIGTERM, SIG_DFL) == SIG_ERR) { |
| 84 | std::cerr << ": signal failed: " << cpp_strerror(errno) << "\n"; |
| 85 | goto fail_exit; |
| 86 | } |
| 87 | // Because SIGCHLD is ignored by default, setup dummy handler for it, |