diff options
Diffstat (limited to 'src/main/tools/process-wrapper-legacy.cc')
-rw-r--r-- | src/main/tools/process-wrapper-legacy.cc | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/main/tools/process-wrapper-legacy.cc b/src/main/tools/process-wrapper-legacy.cc new file mode 100644 index 0000000000..2c6e6d224a --- /dev/null +++ b/src/main/tools/process-wrapper-legacy.cc @@ -0,0 +1,102 @@ +// 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 <sys/types.h> +#include <sys/wait.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); + } +} |