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