Ninja
|
00001 // Copyright 2012 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 00019 #include <algorithm> 00020 00021 #include "util.h" 00022 00023 Subprocess::Subprocess() : child_(NULL) , overlapped_(), is_reading_(false) { 00024 } 00025 00026 Subprocess::~Subprocess() { 00027 if (pipe_) { 00028 if (!CloseHandle(pipe_)) 00029 Win32Fatal("CloseHandle"); 00030 } 00031 // Reap child if forgotten. 00032 if (child_) 00033 Finish(); 00034 } 00035 00036 HANDLE Subprocess::SetupPipe(HANDLE ioport) { 00037 char pipe_name[100]; 00038 snprintf(pipe_name, sizeof(pipe_name), 00039 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this); 00040 00041 pipe_ = ::CreateNamedPipeA(pipe_name, 00042 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 00043 PIPE_TYPE_BYTE, 00044 PIPE_UNLIMITED_INSTANCES, 00045 0, 0, INFINITE, NULL); 00046 if (pipe_ == INVALID_HANDLE_VALUE) 00047 Win32Fatal("CreateNamedPipe"); 00048 00049 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0)) 00050 Win32Fatal("CreateIoCompletionPort"); 00051 00052 memset(&overlapped_, 0, sizeof(overlapped_)); 00053 if (!ConnectNamedPipe(pipe_, &overlapped_) && 00054 GetLastError() != ERROR_IO_PENDING) { 00055 Win32Fatal("ConnectNamedPipe"); 00056 } 00057 00058 // Get the write end of the pipe as a handle inheritable across processes. 00059 HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0, 00060 NULL, OPEN_EXISTING, 0, NULL); 00061 HANDLE output_write_child; 00062 if (!DuplicateHandle(GetCurrentProcess(), output_write_handle, 00063 GetCurrentProcess(), &output_write_child, 00064 0, TRUE, DUPLICATE_SAME_ACCESS)) { 00065 Win32Fatal("DuplicateHandle"); 00066 } 00067 CloseHandle(output_write_handle); 00068 00069 return output_write_child; 00070 } 00071 00072 bool Subprocess::Start(SubprocessSet* set, const string& command) { 00073 HANDLE child_pipe = SetupPipe(set->ioport_); 00074 00075 SECURITY_ATTRIBUTES security_attributes; 00076 memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES)); 00077 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); 00078 security_attributes.bInheritHandle = TRUE; 00079 // Must be inheritable so subprocesses can dup to children. 00080 HANDLE nul = CreateFile("NUL", GENERIC_READ, 00081 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 00082 &security_attributes, OPEN_EXISTING, 0, NULL); 00083 if (nul == INVALID_HANDLE_VALUE) 00084 Fatal("couldn't open nul"); 00085 00086 STARTUPINFOA startup_info; 00087 memset(&startup_info, 0, sizeof(startup_info)); 00088 startup_info.cb = sizeof(STARTUPINFO); 00089 startup_info.dwFlags = STARTF_USESTDHANDLES; 00090 startup_info.hStdInput = nul; 00091 startup_info.hStdOutput = child_pipe; 00092 startup_info.hStdError = child_pipe; 00093 00094 PROCESS_INFORMATION process_info; 00095 memset(&process_info, 0, sizeof(process_info)); 00096 00097 // Do not prepend 'cmd /c' on Windows, this breaks command 00098 // lines greater than 8,191 chars. 00099 if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL, 00100 /* inherit handles */ TRUE, CREATE_NEW_PROCESS_GROUP, 00101 NULL, NULL, 00102 &startup_info, &process_info)) { 00103 DWORD error = GetLastError(); 00104 if (error == ERROR_FILE_NOT_FOUND) { 00105 // File (program) not found error is treated as a normal build 00106 // action failure. 00107 if (child_pipe) 00108 CloseHandle(child_pipe); 00109 CloseHandle(pipe_); 00110 CloseHandle(nul); 00111 pipe_ = NULL; 00112 // child_ is already NULL; 00113 buf_ = "CreateProcess failed: The system cannot find the file " 00114 "specified.\n"; 00115 return true; 00116 } else { 00117 Win32Fatal("CreateProcess"); // pass all other errors to Win32Fatal 00118 } 00119 } 00120 00121 // Close pipe channel only used by the child. 00122 if (child_pipe) 00123 CloseHandle(child_pipe); 00124 CloseHandle(nul); 00125 00126 CloseHandle(process_info.hThread); 00127 child_ = process_info.hProcess; 00128 00129 return true; 00130 } 00131 00132 void Subprocess::OnPipeReady() { 00133 DWORD bytes; 00134 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) { 00135 if (GetLastError() == ERROR_BROKEN_PIPE) { 00136 CloseHandle(pipe_); 00137 pipe_ = NULL; 00138 return; 00139 } 00140 Win32Fatal("GetOverlappedResult"); 00141 } 00142 00143 if (is_reading_ && bytes) 00144 buf_.append(overlapped_buf_, bytes); 00145 00146 memset(&overlapped_, 0, sizeof(overlapped_)); 00147 is_reading_ = true; 00148 if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_), 00149 &bytes, &overlapped_)) { 00150 if (GetLastError() == ERROR_BROKEN_PIPE) { 00151 CloseHandle(pipe_); 00152 pipe_ = NULL; 00153 return; 00154 } 00155 if (GetLastError() != ERROR_IO_PENDING) 00156 Win32Fatal("ReadFile"); 00157 } 00158 00159 // Even if we read any bytes in the readfile call, we'll enter this 00160 // function again later and get them at that point. 00161 } 00162 00163 ExitStatus Subprocess::Finish() { 00164 if (!child_) 00165 return ExitFailure; 00166 00167 // TODO: add error handling for all of these. 00168 WaitForSingleObject(child_, INFINITE); 00169 00170 DWORD exit_code = 0; 00171 GetExitCodeProcess(child_, &exit_code); 00172 00173 CloseHandle(child_); 00174 child_ = NULL; 00175 00176 return exit_code == 0 ? ExitSuccess : 00177 exit_code == CONTROL_C_EXIT ? ExitInterrupted : 00178 ExitFailure; 00179 } 00180 00181 bool Subprocess::Done() const { 00182 return pipe_ == NULL; 00183 } 00184 00185 const string& Subprocess::GetOutput() const { 00186 return buf_; 00187 } 00188 00189 HANDLE SubprocessSet::ioport_; 00190 00191 SubprocessSet::SubprocessSet() { 00192 ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); 00193 if (!ioport_) 00194 Win32Fatal("CreateIoCompletionPort"); 00195 if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE)) 00196 Win32Fatal("SetConsoleCtrlHandler"); 00197 } 00198 00199 SubprocessSet::~SubprocessSet() { 00200 Clear(); 00201 00202 SetConsoleCtrlHandler(NotifyInterrupted, FALSE); 00203 CloseHandle(ioport_); 00204 } 00205 00206 BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) { 00207 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { 00208 if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL)) 00209 Win32Fatal("PostQueuedCompletionStatus"); 00210 return TRUE; 00211 } 00212 00213 return FALSE; 00214 } 00215 00216 Subprocess *SubprocessSet::Add(const string& command) { 00217 Subprocess *subprocess = new Subprocess; 00218 if (!subprocess->Start(this, command)) { 00219 delete subprocess; 00220 return 0; 00221 } 00222 if (subprocess->child_) 00223 running_.push_back(subprocess); 00224 else 00225 finished_.push(subprocess); 00226 return subprocess; 00227 } 00228 00229 bool SubprocessSet::DoWork() { 00230 DWORD bytes_read; 00231 Subprocess* subproc; 00232 OVERLAPPED* overlapped; 00233 00234 if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc, 00235 &overlapped, INFINITE)) { 00236 if (GetLastError() != ERROR_BROKEN_PIPE) 00237 Win32Fatal("GetQueuedCompletionStatus"); 00238 } 00239 00240 if (!subproc) // A NULL subproc indicates that we were interrupted and is 00241 // delivered by NotifyInterrupted above. 00242 return true; 00243 00244 subproc->OnPipeReady(); 00245 00246 if (subproc->Done()) { 00247 vector<Subprocess*>::iterator end = 00248 std::remove(running_.begin(), running_.end(), subproc); 00249 if (running_.end() != end) { 00250 finished_.push(subproc); 00251 running_.resize(end - running_.begin()); 00252 } 00253 } 00254 00255 return false; 00256 } 00257 00258 Subprocess* SubprocessSet::NextFinished() { 00259 if (finished_.empty()) 00260 return NULL; 00261 Subprocess* subproc = finished_.front(); 00262 finished_.pop(); 00263 return subproc; 00264 } 00265 00266 void SubprocessSet::Clear() { 00267 for (vector<Subprocess*>::iterator i = running_.begin(); 00268 i != running_.end(); ++i) { 00269 if ((*i)->child_) { 00270 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 00271 GetProcessId((*i)->child_))) { 00272 Win32Fatal("GenerateConsoleCtrlEvent"); 00273 } 00274 } 00275 } 00276 for (vector<Subprocess*>::iterator i = running_.begin(); 00277 i != running_.end(); ++i) 00278 delete *i; 00279 running_.clear(); 00280 }