summaryrefslogtreecommitdiffstats
path: root/src/subprocess-win32.cc
diff options
context:
space:
mode:
authorEvan Martin <martine@danga.com>2012-02-14 00:55:16 (GMT)
committerEvan Martin <martine@danga.com>2012-02-14 00:55:16 (GMT)
commit0eebd5fe1dec021a63110ecab8fa411f9980745f (patch)
tree470e397b33e8538d82ab2ce842cfd708450d872c /src/subprocess-win32.cc
parent51066421eef67847b244154119ca77a893bd6be8 (diff)
parent44f58aeca923d6e3001636f8c0d24a6d513d8ea2 (diff)
downloadNinja-0eebd5fe1dec021a63110ecab8fa411f9980745f.zip
Ninja-0eebd5fe1dec021a63110ecab8fa411f9980745f.tar.gz
Ninja-0eebd5fe1dec021a63110ecab8fa411f9980745f.tar.bz2
Merge pull request #176 from pcc/exit-cleanup
Implement cleanup-on-interrupt
Diffstat (limited to 'src/subprocess-win32.cc')
-rw-r--r--src/subprocess-win32.cc63
1 files changed, 55 insertions, 8 deletions
diff --git a/src/subprocess-win32.cc b/src/subprocess-win32.cc
index c0185e4..fef0bc8 100644
--- a/src/subprocess-win32.cc
+++ b/src/subprocess-win32.cc
@@ -32,6 +32,10 @@ Subprocess::Subprocess() : child_(NULL) , overlapped_(), is_reading_(false) {
}
Subprocess::~Subprocess() {
+ if (pipe_) {
+ if (!CloseHandle(pipe_))
+ Win32Fatal("CloseHandle");
+ }
// Reap child if forgotten.
if (child_)
Finish();
@@ -92,7 +96,7 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
// Do not prepend 'cmd /c' on Windows, this breaks command
// lines greater than 8,191 chars.
if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
- /* inherit handles */ TRUE, 0,
+ /* inherit handles */ TRUE, CREATE_NEW_PROCESS_GROUP,
NULL, NULL,
&startup_info, &process_info)) {
DWORD error = GetLastError();
@@ -150,10 +154,9 @@ void Subprocess::OnPipeReady() {
// function again later and get them at that point.
}
-bool Subprocess::Finish() {
- if (! child_) {
- return false;
- }
+ExitStatus Subprocess::Finish() {
+ if (!child_)
+ return ExitFailure;
// TODO: add error handling for all of these.
WaitForSingleObject(child_, INFINITE);
@@ -164,7 +167,9 @@ bool Subprocess::Finish() {
CloseHandle(child_);
child_ = NULL;
- return exit_code == 0;
+ return exit_code == 0 ? ExitSuccess :
+ exit_code == CONTROL_C_EXIT ? ExitInterrupted :
+ ExitFailure;
}
bool Subprocess::Done() const {
@@ -175,24 +180,47 @@ const string& Subprocess::GetOutput() const {
return buf_;
}
+HANDLE SubprocessSet::ioport_;
+
SubprocessSet::SubprocessSet() {
ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
if (!ioport_)
Win32Fatal("CreateIoCompletionPort");
+ if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
+ Win32Fatal("SetConsoleCtrlHandler");
}
SubprocessSet::~SubprocessSet() {
+ Clear();
+
+ SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
CloseHandle(ioport_);
}
-void SubprocessSet::Add(Subprocess* subprocess) {
+BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) {
+ if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
+ if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
+ Win32Fatal("PostQueuedCompletionStatus");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+Subprocess *SubprocessSet::Add(const string &command) {
+ Subprocess *subprocess = new Subprocess;
+ if (!subprocess->Start(this, command)) {
+ delete subprocess;
+ return 0;
+ }
if (subprocess->child_)
running_.push_back(subprocess);
else
finished_.push(subprocess);
+ return subprocess;
}
-void SubprocessSet::DoWork() {
+bool SubprocessSet::DoWork() {
DWORD bytes_read;
Subprocess* subproc;
OVERLAPPED* overlapped;
@@ -203,6 +231,10 @@ void SubprocessSet::DoWork() {
Win32Fatal("GetQueuedCompletionStatus");
}
+ if (!subproc) // A NULL subproc indicates that we were interrupted and is
+ // delivered by NotifyInterrupted above.
+ return true;
+
subproc->OnPipeReady();
if (subproc->Done()) {
@@ -213,6 +245,8 @@ void SubprocessSet::DoWork() {
running_.resize(end - running_.begin());
}
}
+
+ return false;
}
Subprocess* SubprocessSet::NextFinished() {
@@ -222,3 +256,16 @@ Subprocess* SubprocessSet::NextFinished() {
finished_.pop();
return subproc;
}
+
+void SubprocessSet::Clear() {
+ for (vector<Subprocess*>::iterator i = running_.begin();
+ i != running_.end(); ++i) {
+ if ((*i)->child_)
+ if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, GetProcessId((*i)->child_)))
+ Win32Fatal("GenerateConsoleCtrlEvent");
+ }
+ for (vector<Subprocess*>::iterator i = running_.begin();
+ i != running_.end(); ++i)
+ delete *i;
+ running_.clear();
+}