Merge pull request #133 from hughbe/ninjabuild-command-consolidate
Consolidate common code between NinjaBuildCommand.cpp and LaneBasedExecutionQueue.cpp
diff --git a/lib/Commands/NinjaBuildCommand.cpp b/lib/Commands/NinjaBuildCommand.cpp
index a3e972d..f1c77af 100644
--- a/lib/Commands/NinjaBuildCommand.cpp
+++ b/lib/Commands/NinjaBuildCommand.cpp
@@ -24,6 +24,7 @@
#include "llbuild/Core/MakefileDepsParser.h"
#include "llbuild/Ninja/ManifestLoader.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/Support/TimeValue.h"
#include "CommandLineStatusOutput.h"
@@ -501,19 +502,24 @@
sys::write(signalWatchingPipe[1], &byte, 1);
}
+ void sendSignalToProcesses(int signal) {
+ std::unique_lock<std::mutex> lock(spawnedProcessesMutex);
+
+ for (pid_t pid: spawnedProcesses) {
+ // We are killing the whole process group here, this depends on us
+ // spawning each process in its own group earlier.
+ ::kill(-pid, signal);
+ }
+ }
+
/// Cancel the build in response to an interrupt event.
void cancelBuildOnInterrupt() {
- std::lock_guard<std::mutex> guard(spawnedProcessesMutex);
+ sendSignalToProcesses(SIGINT);
emitNote("cancelling build.");
isCancelled = true;
wasCancelledBySigint = true;
- // Cancel the spawned processes.
- for (pid_t pid: spawnedProcesses) {
- ::kill(-pid, SIGINT);
- }
-
// FIXME: In our model, we still wait for everything to terminate, which
// means a process that refuses to respond to SIGINT will cause us to just
// hang here. We should probably detect and report that and be willing to do
@@ -1211,6 +1217,10 @@
posix_spawn_file_actions_t fileActions;
posix_spawn_file_actions_init(&fileActions);
+ // Open /dev/null as stdin.
+ posix_spawn_file_actions_addopen(
+ &fileActions, 0, "/dev/null", O_RDONLY, 0);
+
// Create a pipe to use to read the command output, if necessary.
int pipe[2]{ -1, -1 };
if (!isConsole) {
@@ -1219,16 +1229,7 @@
strerror(errno));
return false;
}
- }
- // Open /dev/null as stdin.
- posix_spawn_file_actions_addopen(
- &fileActions, 0, "/dev/null", O_RDONLY, 0);
-
- if (isConsole) {
- posix_spawn_file_actions_adddup2(&fileActions, 1, 1);
- posix_spawn_file_actions_adddup2(&fileActions, 2, 2);
- } else {
// Open the write end of the pipe as stdout and stderr.
posix_spawn_file_actions_adddup2(&fileActions, pipe[1], 1);
posix_spawn_file_actions_adddup2(&fileActions, pipe[1], 2);
@@ -1236,6 +1237,10 @@
// Close the read and write ends of the pipe.
posix_spawn_file_actions_addclose(&fileActions, pipe[0]);
posix_spawn_file_actions_addclose(&fileActions, pipe[1]);
+ } else {
+ // Otherwise, propagate the current stdout/stderr.
+ posix_spawn_file_actions_adddup2(&fileActions, 1, 1);
+ posix_spawn_file_actions_adddup2(&fileActions, 2, 2);
}
// Spawn the command.
@@ -1245,10 +1250,11 @@
args[2] = command->getCommandString().c_str();
args[3] = nullptr;
- // We need to hold the spawn processes lock when we spawn, to ensure that
- // we don't create a process in between when we are cancelled.
+ // Spawn the command.
pid_t pid;
{
+ // We need to hold the spawn processes lock when we spawn, to ensure that
+ // we don't create a process in between when we are cancelled.
std::lock_guard<std::mutex> guard(context.spawnedProcessesMutex);
if (posix_spawn(&pid, args[0], /*file_actions=*/&fileActions,
@@ -1267,7 +1273,7 @@
posix_spawnattr_destroy(&attributes);
// Read the command output, if buffering.
- std::vector<char> outputData;
+ SmallString<1024> outputData;
if (!isConsole) {
// Close the write end of the output pipe.
::close(pipe[1]);
@@ -1295,10 +1301,7 @@
// Wait for the command to complete.
int status, result = waitpid(pid, &status, 0);
while (result == -1 && errno == EINTR)
- result = waitpid(pid, &status, 0);
- if (result == -1) {
- context.emitError("unable to wait for process (%s)", strerror(errno));
- }
+ result = waitpid(pid, &status, 0);
// Update the set of spawned processes.
{
@@ -1306,6 +1309,10 @@
context.spawnedProcesses.erase(pid);
}
+ if (result == -1) {
+ context.emitError("unable to wait for process (%s)", strerror(errno));
+ }
+
// If the build has been interrupted, return without writing any output or
// command status (since they will also have been interrupted).
if (context.isCancelled && context.wasCancelledBySigint) {
@@ -1318,7 +1325,8 @@
if (status != 0) {
// If the process was killed by SIGINT, assume it is because we were
// interrupted.
- if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT)
+ bool cancelled = WIFSIGNALED(status) && (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGKILL);
+ if (cancelled)
return false;
// Otherwise, report the failure.