diff options
author | Evan Martin <martine@danga.com> | 2012-02-14 00:55:16 (GMT) |
---|---|---|
committer | Evan Martin <martine@danga.com> | 2012-02-14 00:55:16 (GMT) |
commit | 0eebd5fe1dec021a63110ecab8fa411f9980745f (patch) | |
tree | 470e397b33e8538d82ab2ce842cfd708450d872c /src/subprocess-win32.cc | |
parent | 51066421eef67847b244154119ca77a893bd6be8 (diff) | |
parent | 44f58aeca923d6e3001636f8c0d24a6d513d8ea2 (diff) | |
download | Ninja-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.cc | 63 |
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(); +} |