| 127 | |
| 128 | |
| 129 | Subprocess::ChildHook Subprocess::ChildHook::SUPERVISOR() |
| 130 | { |
| 131 | return Subprocess::ChildHook([]() -> Try<Nothing> { |
| 132 | #ifdef __linux__ |
| 133 | // Send SIGTERM to the current process if the parent exits. |
| 134 | // NOTE:: This function should always succeed because we are passing |
| 135 | // in a valid signal. |
| 136 | prctl(PR_SET_PDEATHSIG, SIGTERM); |
| 137 | |
| 138 | // Put the current process into a separate process group so that |
| 139 | // we can kill it and all its children easily. |
| 140 | if (setpgid(0, 0) != 0) { |
| 141 | return Error("Could not start supervisor process."); |
| 142 | } |
| 143 | |
| 144 | // Install a SIGTERM handler which will kill the current process |
| 145 | // group. Since we already setup the death signal above, the |
| 146 | // signal handler will be triggered when the parent exits. |
| 147 | if (os::signals::install(SIGTERM, &signalHandler) != 0) { |
| 148 | return Error("Could not start supervisor process."); |
| 149 | } |
| 150 | |
| 151 | pid_t pid = fork(); |
| 152 | if (pid == -1) { |
| 153 | return Error("Could not start supervisor process."); |
| 154 | } else if (pid == 0) { |
| 155 | // Child. This is the process that is going to exec the |
| 156 | // process if zero is returned. |
| 157 | |
| 158 | // We setup death signal for the process as well in case |
| 159 | // someone, though unlikely, accidentally kill the parent of |
| 160 | // this process (the bookkeeping process). |
| 161 | prctl(PR_SET_PDEATHSIG, SIGKILL); |
| 162 | |
| 163 | // NOTE: We don't need to clear the signal handler explicitly |
| 164 | // because the subsequent 'exec' will clear them. |
| 165 | return Nothing(); |
| 166 | } else { |
| 167 | // Parent. This is the bookkeeping process which will wait for |
| 168 | // the child process to finish. |
| 169 | |
| 170 | // Close the files to prevent interference on the communication |
| 171 | // between the parent and the child process. |
| 172 | ::close(STDIN_FILENO); |
| 173 | ::close(STDOUT_FILENO); |
| 174 | ::close(STDERR_FILENO); |
| 175 | |
| 176 | // Block until the child process finishes. |
| 177 | int status = 0; |
| 178 | while (waitpid(pid, &status, 0) == -1) { |
| 179 | if (errno != EINTR) { |
| 180 | _exit(EXIT_FAILURE); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | // Forward the exit status if the child process exits normally. |
| 185 | if (WIFEXITED(status)) { |
| 186 | _exit(WEXITSTATUS(status)); |