Ninja
subprocess-win32.cc
Go to the documentation of this file.
00001 // Copyright 2011 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "subprocess.h"
00016 
00017 #include <stdio.h>
00018 #include <windows.h>
00019 
00020 #include <algorithm>
00021 
00022 #include "util.h"
00023 
00024 namespace {
00025 
00026 void Win32Fatal(const char* function) {
00027   DWORD err = GetLastError();
00028 
00029   char* msg_buf;
00030   FormatMessageA(
00031         FORMAT_MESSAGE_ALLOCATE_BUFFER |
00032         FORMAT_MESSAGE_FROM_SYSTEM |
00033         FORMAT_MESSAGE_IGNORE_INSERTS,
00034         NULL,
00035         err,
00036         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00037         (char*)&msg_buf,
00038         0,
00039         NULL);
00040   Fatal("%s: %s", function, msg_buf);
00041   LocalFree(msg_buf);
00042 }
00043 
00044 }  // anonymous namespace
00045 
00046 Subprocess::Subprocess() : child_(NULL) , overlapped_() {
00047 }
00048 
00049 Subprocess::~Subprocess() {
00050   // Reap child if forgotten.
00051   if (child_)
00052     Finish();
00053 }
00054 
00055 HANDLE Subprocess::SetupPipe(HANDLE ioport) {
00056   char pipe_name[100];
00057   snprintf(pipe_name, sizeof(pipe_name),
00058            "\\\\.\\pipe\\ninja_pid%u_sp%p", GetProcessId(GetCurrentProcess()), this);
00059 
00060   pipe_ = ::CreateNamedPipeA(pipe_name,
00061                              PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
00062                              PIPE_TYPE_BYTE,
00063                              PIPE_UNLIMITED_INSTANCES,
00064                              0, 0, INFINITE, NULL);
00065   if (pipe_ == INVALID_HANDLE_VALUE)
00066     Win32Fatal("CreateNamedPipe");
00067 
00068   if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
00069     Win32Fatal("CreateIoCompletionPort");
00070 
00071   memset(&overlapped_, 0, sizeof(overlapped_));
00072   if (!ConnectNamedPipe(pipe_, &overlapped_) &&
00073       GetLastError() != ERROR_IO_PENDING) {
00074     Win32Fatal("ConnectNamedPipe");
00075   }
00076 
00077   // Get the write end of the pipe as a handle inheritable across processes.
00078   HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
00079                                           NULL, OPEN_EXISTING, 0, NULL);
00080   HANDLE output_write_child;
00081   if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
00082                        GetCurrentProcess(), &output_write_child,
00083                        0, TRUE, DUPLICATE_SAME_ACCESS)) {
00084     Win32Fatal("DuplicateHandle");
00085   }
00086   CloseHandle(output_write_handle);
00087 
00088   return output_write_child;
00089 }
00090 
00091 bool Subprocess::Start(SubprocessSet* set, const string& command) {
00092   HANDLE child_pipe = SetupPipe(set->ioport_);
00093 
00094   STARTUPINFOA startup_info = {};
00095   startup_info.cb = sizeof(STARTUPINFO);
00096   startup_info.dwFlags = STARTF_USESTDHANDLES;
00097   startup_info.hStdOutput = child_pipe;
00098   // TODO: what does this hook up stdin to?
00099   startup_info.hStdInput  = NULL;
00100   // TODO: is it ok to reuse pipe like this?
00101   startup_info.hStdError  = child_pipe;
00102 
00103   PROCESS_INFORMATION process_info;
00104 
00105   // Do not prepend 'cmd /c' on Windows, this breaks command
00106   // lines greater than 8,191 chars.
00107   if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
00108                       /* inherit handles */ TRUE, 0,
00109                       NULL, NULL,
00110                       &startup_info, &process_info)) {
00111     Win32Fatal("CreateProcess");
00112   }
00113 
00114   // Close pipe channel only used by the child.
00115   if (child_pipe)
00116     CloseHandle(child_pipe);
00117 
00118   CloseHandle(process_info.hThread);
00119   child_ = process_info.hProcess;
00120 
00121   return true;
00122 }
00123 
00124 void Subprocess::OnPipeReady() {
00125   DWORD bytes;
00126   if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
00127     if (GetLastError() == ERROR_BROKEN_PIPE) {
00128       CloseHandle(pipe_);
00129       pipe_ = NULL;
00130       return;
00131     }
00132     Win32Fatal("GetOverlappedResult");
00133   }
00134 
00135   if (bytes)
00136     buf_.append(overlapped_buf_, bytes);
00137 
00138   memset(&overlapped_, 0, sizeof(overlapped_));
00139   if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
00140                   &bytes, &overlapped_)) {
00141     if (GetLastError() == ERROR_BROKEN_PIPE) {
00142       CloseHandle(pipe_);
00143       pipe_ = NULL;
00144       return;
00145     }
00146     if (GetLastError() != ERROR_IO_PENDING)
00147       Win32Fatal("ReadFile");
00148   }
00149 
00150   // Even if we read any bytes in the readfile call, we'll enter this
00151   // function again later and get them at that point.
00152 }
00153 
00154 bool Subprocess::Finish() {
00155   // TODO: add error handling for all of these.
00156   WaitForSingleObject(child_, INFINITE);
00157 
00158   DWORD exit_code = 0;
00159   GetExitCodeProcess(child_, &exit_code);
00160 
00161   CloseHandle(child_);
00162   child_ = NULL;
00163 
00164   return exit_code == 0;
00165 }
00166 
00167 bool Subprocess::Done() const {
00168   return pipe_ == NULL;
00169 }
00170 
00171 const string& Subprocess::GetOutput() const {
00172   return buf_;
00173 }
00174 
00175 SubprocessSet::SubprocessSet() {
00176   ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
00177   if (!ioport_)
00178     Win32Fatal("CreateIoCompletionPort");
00179 }
00180 
00181 SubprocessSet::~SubprocessSet() {
00182   CloseHandle(ioport_);
00183 }
00184 
00185 void SubprocessSet::Add(Subprocess* subprocess) {
00186   running_.push_back(subprocess);
00187 }
00188 
00189 void SubprocessSet::DoWork() {
00190   DWORD bytes_read;
00191   Subprocess* subproc;
00192   OVERLAPPED* overlapped;
00193 
00194   if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
00195                                  &overlapped, INFINITE)) {
00196     if (GetLastError() != ERROR_BROKEN_PIPE)
00197       Win32Fatal("GetQueuedCompletionStatus");
00198   }
00199 
00200   subproc->OnPipeReady();
00201 
00202   if (subproc->Done()) {
00203     vector<Subprocess*>::iterator end =
00204         std::remove(running_.begin(), running_.end(), subproc);
00205     if (running_.end() != end) {
00206       finished_.push(subproc);
00207       running_.resize(end - running_.begin());
00208     }
00209   }
00210 }
00211 
00212 Subprocess* SubprocessSet::NextFinished() {
00213   if (finished_.empty())
00214     return NULL;
00215   Subprocess* subproc = finished_.front();
00216   finished_.pop();
00217   return subproc;
00218 }