aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/tools/process-wrapper.cc
diff options
context:
space:
mode:
authorGravatar elenairina <elenairina@google.com>2017-05-23 20:06:28 +0200
committerGravatar Irina Iancu <elenairina@google.com>2017-05-23 20:15:47 +0200
commit5608765ab737ebb8a98a04a6068143d53ae7065c (patch)
treedcfaf44eb0721369355e794de828f6a7d8451790 /src/main/tools/process-wrapper.cc
parent6206d1edd5ec7b067daa48ce0c2b3784d0002c26 (diff)
Automated g4 rollback of commit 7f520a8286c39c5145b6d816cd0be5a6b7b18250.
*** Reason for rollback *** This broke Bazel CI on freebsd: http://ci.bazel.io/view/Dashboard/job/Bazel/JAVA_VERSION=1.8,PLATFORM_NAME=freebsd-11/1516/console# *** Original change description *** Refactor process-wrapper code so the spawn/wait code is pluggable. In an upcoming change I'll reintroduce the new platform-specific implementations that can kill and wait for all descendant processes spawned by the wrapped process. This has no functional changes. PiperOrigin-RevId: 156884488
Diffstat (limited to 'src/main/tools/process-wrapper.cc')
-rw-r--r--src/main/tools/process-wrapper.cc94
1 files changed, 89 insertions, 5 deletions
diff --git a/src/main/tools/process-wrapper.cc b/src/main/tools/process-wrapper.cc
index 09c1a88038..c60de6e4e3 100644
--- a/src/main/tools/process-wrapper.cc
+++ b/src/main/tools/process-wrapper.cc
@@ -22,8 +22,6 @@
// die with raise(SIGTERM) even if the child process handles SIGTERM with
// exit(0).
-#include "src/main/tools/process-wrapper.h"
-
#include <err.h>
#include <errno.h>
#include <signal.h>
@@ -40,9 +38,21 @@
#include "src/main/tools/logging.h"
#include "src/main/tools/process-tools.h"
-#include "src/main/tools/process-wrapper-legacy.h"
-struct Options opt;
+static double global_kill_delay;
+static pid_t global_child_pid;
+static volatile sig_atomic_t global_signal;
+
+// Options parsing result.
+struct Options {
+ double timeout_secs;
+ double kill_delay_secs;
+ std::string stdout_path;
+ std::string stderr_path;
+ std::vector<char *> args;
+};
+
+static struct Options opt;
// Print out a usage error and exit with EXIT_FAILURE.
static void Usage(char *program_name) {
@@ -76,9 +86,83 @@ static void ParseCommandLine(std::vector<char *> args) {
opt.args.push_back(nullptr);
}
+// Called when timeout or signal occurs.
+void OnSignal(int sig) {
+ global_signal = sig;
+
+ // Nothing to do if we received a signal before spawning the child.
+ if (global_child_pid == -1) {
+ return;
+ }
+
+ if (sig == SIGALRM) {
+ // SIGALRM represents a timeout, so we should give the process a bit of
+ // time to die gracefully if it needs it.
+ KillEverything(global_child_pid, true, global_kill_delay);
+ } else {
+ // Signals should kill the process quickly, as it's typically blocking
+ // the return of the prompt after a user hits "Ctrl-C".
+ KillEverything(global_child_pid, false, global_kill_delay);
+ }
+}
+
+// Run the command specified by the argv array and kill it after timeout
+// seconds.
+static void SpawnCommand(const std::vector<char *> &args, double timeout_secs) {
+ global_child_pid = fork();
+ if (global_child_pid < 0) {
+ DIE("fork");
+ } else if (global_child_pid == 0) {
+ // In child.
+ if (setsid() < 0) {
+ DIE("setsid");
+ }
+ ClearSignalMask();
+
+ // Force umask to include read and execute for everyone, to make
+ // output permissions predictable.
+ umask(022);
+
+ // Does not return unless something went wrong.
+ if (execvp(args[0], args.data()) < 0) {
+ DIE("execvp(%s, ...)", args[0]);
+ }
+ } else {
+ // In parent.
+
+ // Set up a signal handler which kills all subprocesses when the given
+ // signal is triggered.
+ InstallSignalHandler(SIGALRM, OnSignal);
+ InstallSignalHandler(SIGTERM, OnSignal);
+ InstallSignalHandler(SIGINT, OnSignal);
+ if (timeout_secs > 0) {
+ SetTimeout(timeout_secs);
+ }
+
+ int status = WaitChild(global_child_pid);
+
+ // The child is done for, but may have grandchildren that we still have to
+ // kill.
+ kill(-global_child_pid, SIGKILL);
+
+ if (global_signal > 0) {
+ // Don't trust the exit code if we got a timeout or signal.
+ InstallDefaultSignalHandler(global_signal);
+ raise(global_signal);
+ } else if (WIFEXITED(status)) {
+ exit(WEXITSTATUS(status));
+ } else {
+ int sig = WTERMSIG(status);
+ InstallDefaultSignalHandler(sig);
+ raise(sig);
+ }
+ }
+}
+
int main(int argc, char *argv[]) {
std::vector<char *> args(argv, argv + argc);
ParseCommandLine(args);
+ global_kill_delay = opt.kill_delay_secs;
SwitchToEuid();
SwitchToEgid();
@@ -86,7 +170,7 @@ int main(int argc, char *argv[]) {
Redirect(opt.stdout_path, STDOUT_FILENO);
Redirect(opt.stderr_path, STDERR_FILENO);
- LegacyProcessWrapper::RunCommand();
+ SpawnCommand(opt.args, opt.timeout_secs);
return 0;
}