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
diff --git a/src/main/tools/BUILD b/src/main/tools/BUILD
index 5ed4ac9..72aff63 100644
--- a/src/main/tools/BUILD
+++ b/src/main/tools/BUILD
@@ -19,9 +19,6 @@
         "//src:windows_msvc": ["process-wrapper-windows.cc"],
         "//conditions:default": [
             "process-wrapper.cc",
-            "process-wrapper.h",
-            "process-wrapper-legacy.cc",
-            "process-wrapper-legacy.h",
         ],
     }),
     linkopts = ["-lm"],
diff --git a/src/main/tools/process-wrapper-legacy.cc b/src/main/tools/process-wrapper-legacy.cc
deleted file mode 100644
index 2ebc593..0000000
--- a/src/main/tools/process-wrapper-legacy.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2017 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/main/tools/process-wrapper-legacy.h"
-
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <vector>
-
-#include "src/main/tools/logging.h"
-#include "src/main/tools/process-tools.h"
-#include "src/main/tools/process-wrapper.h"
-
-pid_t LegacyProcessWrapper::child_pid = 0;
-volatile sig_atomic_t LegacyProcessWrapper::last_signal = 0;
-
-void LegacyProcessWrapper::RunCommand() {
-  SpawnChild();
-  WaitForChild();
-}
-
-void LegacyProcessWrapper::SpawnChild() {
-  child_pid = fork();
-  if (child_pid < 0) {
-    DIE("fork");
-  } else if (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(opt.args[0], opt.args.data()) < 0) {
-      DIE("execvp(%s, ...)", opt.args[0]);
-    }
-  }
-}
-
-void LegacyProcessWrapper::WaitForChild() {
-  // 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 (opt.timeout_secs > 0) {
-    SetTimeout(opt.timeout_secs);
-  }
-
-  int status = WaitChild(child_pid);
-
-  // The child is done for, but may have grandchildren that we still have to
-  // kill.
-  kill(-child_pid, SIGKILL);
-
-  if (last_signal > 0) {
-    // Don't trust the exit code if we got a timeout or signal.
-    InstallDefaultSignalHandler(last_signal);
-    raise(last_signal);
-  } else if (WIFEXITED(status)) {
-    exit(WEXITSTATUS(status));
-  } else {
-    int sig = WTERMSIG(status);
-    InstallDefaultSignalHandler(sig);
-    raise(sig);
-  }
-}
-
-// Called when timeout or signal occurs.
-void LegacyProcessWrapper::OnSignal(int sig) {
-  last_signal = sig;
-
-  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(child_pid, true, opt.kill_delay_secs);
-  } else {
-    // Signals should kill the process quickly, as it's typically blocking the
-    // return of the prompt after a user hits "Ctrl-C".
-    KillEverything(child_pid, false, opt.kill_delay_secs);
-  }
-}
diff --git a/src/main/tools/process-wrapper-legacy.h b/src/main/tools/process-wrapper-legacy.h
deleted file mode 100644
index 5cea547..0000000
--- a/src/main/tools/process-wrapper-legacy.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2017 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_MAIN_TOOLS_PROCESS_WRAPPER_LEGACY_H_
-#define SRC_MAIN_TOOLS_PROCESS_WRAPPER_LEGACY_H_
-
-#include <signal.h>
-#include <vector>
-
-// The process-wrapper implementation that was used until and including Bazel
-// 0.4.5. Waits for the wrapped process to exit and then kills its process
-// group. Works on all POSIX operating systems (tested on Linux, macOS,
-// FreeBSD).
-//
-// Caveats:
-// - Killing just the process group of the spawned child means that daemons or
-//   other processes spawned by the child may not be killed if they change their
-//   process group.
-// - Does not wait for grandchildren to exit, thus processes spawned by the
-//   child that could not be killed will linger around in the background.
-// - Has a PID reuse race condition, because the kill() to the process group is
-//   sent after waitpid() was called on the main child.
-class LegacyProcessWrapper {
- public:
-  // Run the command specified in the `opt.args` array and kill it after
-  // `opt.timeout_secs` seconds.
-  static void RunCommand();
-
- private:
-  static void SpawnChild();
-  static void WaitForChild();
-  static void OnSignal(int sig);
-
-  static pid_t child_pid;
-  static volatile sig_atomic_t last_signal;
-};
-
-#endif
diff --git a/src/main/tools/process-wrapper.cc b/src/main/tools/process-wrapper.cc
index 09c1a88..c60de6e 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 @@
   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 @@
   Redirect(opt.stdout_path, STDOUT_FILENO);
   Redirect(opt.stderr_path, STDERR_FILENO);
 
-  LegacyProcessWrapper::RunCommand();
+  SpawnCommand(opt.args, opt.timeout_secs);
 
   return 0;
 }
diff --git a/src/main/tools/process-wrapper.h b/src/main/tools/process-wrapper.h
deleted file mode 100644
index 061eeac..0000000
--- a/src/main/tools/process-wrapper.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2017 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_MAIN_TOOLS_PROCESS_WRAPPER_H_
-#define SRC_MAIN_TOOLS_PROCESS_WRAPPER_H_
-
-#include <string>
-#include <vector>
-
-// Options parsing result.
-struct Options {
-  double timeout_secs;
-  double kill_delay_secs;
-  std::string stdout_path;
-  std::string stderr_path;
-  std::vector<char *> args;
-};
-
-extern struct Options opt;
-
-#endif