1// Copyright 2012 Google Inc. All Rights Reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15#include "subprocess.h" 16 17#include <assert.h> 18#include <stdio.h> 19 20#include <algorithm> 21 22#include "util.h" 23 24using namespace std; 25 26Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(), 27 is_reading_(false), 28 use_console_(use_console) { 29} 30 31Subprocess::~Subprocess() { 32 if (pipe_) { 33 if (!CloseHandle(pipe_)) 34 Win32Fatal("CloseHandle"); 35 } 36 // Reap child if forgotten. 37 if (child_) 38 Finish(); 39} 40 41HANDLE Subprocess::SetupPipe(HANDLE ioport) { 42 char pipe_name[100]; 43 snprintf(pipe_name, sizeof(pipe_name), 44 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this); 45 46 pipe_ = ::CreateNamedPipeA(pipe_name, 47 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, 48 PIPE_TYPE_BYTE, 49 PIPE_UNLIMITED_INSTANCES, 50 0, 0, INFINITE, NULL); 51 if (pipe_ == INVALID_HANDLE_VALUE) 52 Win32Fatal("CreateNamedPipe"); 53 54 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0)) 55 Win32Fatal("CreateIoCompletionPort"); 56 57 memset(&overlapped_, 0, sizeof(overlapped_)); 58 if (!ConnectNamedPipe(pipe_, &overlapped_) && 59 GetLastError() != ERROR_IO_PENDING) { 60 Win32Fatal("ConnectNamedPipe"); 61 } 62 63 // Get the write end of the pipe as a handle inheritable across processes. 64 HANDLE output_write_handle = 65 CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 66 HANDLE output_write_child; 67 if (!DuplicateHandle(GetCurrentProcess(), output_write_handle, 68 GetCurrentProcess(), &output_write_child, 69 0, TRUE, DUPLICATE_SAME_ACCESS)) { 70 Win32Fatal("DuplicateHandle"); 71 } 72 CloseHandle(output_write_handle); 73 74 return output_write_child; 75} 76 77bool Subprocess::Start(SubprocessSet* set, const string& command) { 78 HANDLE child_pipe = SetupPipe(set->ioport_); 79 80 SECURITY_ATTRIBUTES security_attributes; 81 memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES)); 82 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); 83 security_attributes.bInheritHandle = TRUE; 84 // Must be inheritable so subprocesses can dup to children. 85 HANDLE nul = 86 CreateFileA("NUL", GENERIC_READ, 87 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 88 &security_attributes, OPEN_EXISTING, 0, NULL); 89 if (nul == INVALID_HANDLE_VALUE) 90 Fatal("couldn't open nul"); 91 92 STARTUPINFOA startup_info; 93 memset(&startup_info, 0, sizeof(startup_info)); 94 startup_info.cb = sizeof(STARTUPINFO); 95 if (!use_console_) { 96 startup_info.dwFlags = STARTF_USESTDHANDLES; 97 startup_info.hStdInput = nul; 98 startup_info.hStdOutput = child_pipe; 99 startup_info.hStdError = child_pipe; 100 } 101 // In the console case, child_pipe is still inherited by the child and closed 102 // when the subprocess finishes, which then notifies ninja. 103 104 PROCESS_INFORMATION process_info; 105 memset(&process_info, 0, sizeof(process_info)); 106 107 // Ninja handles ctrl-c, except for subprocesses in console pools. 108 DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP; 109 110 // Do not prepend 'cmd /c' on Windows, this breaks command 111 // lines greater than 8,191 chars. 112 if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL, 113 /* inherit handles */ TRUE, process_flags, 114 NULL, NULL, 115 &startup_info, &process_info)) { 116 DWORD error = GetLastError(); 117 if (error == ERROR_FILE_NOT_FOUND) { 118 // File (program) not found error is treated as a normal build 119 // action failure. 120 if (child_pipe) 121 CloseHandle(child_pipe); 122 CloseHandle(pipe_); 123 CloseHandle(nul); 124 pipe_ = NULL; 125 // child_ is already NULL; 126 buf_ = "CreateProcess failed: The system cannot find the file " 127 "specified.\n"; 128 return true; 129 } else { 130 fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n", 131 command.c_str()); 132 const char* hint = NULL; 133 // ERROR_INVALID_PARAMETER means the command line was formatted 134 // incorrectly. This can be caused by a command line being too long or 135 // leading whitespace in the command. Give extra context for this case. 136 if (error == ERROR_INVALID_PARAMETER) { 137 if (command.length() > 0 && (command[0] == ' ' || command[0] == '\t')) 138 hint = "command contains leading whitespace"; 139 else 140 hint = "is the command line too long?"; 141 } 142 Win32Fatal("CreateProcess", hint); 143 } 144 } 145 146 // Close pipe channel only used by the child. 147 if (child_pipe) 148 CloseHandle(child_pipe); 149 CloseHandle(nul); 150 151 CloseHandle(process_info.hThread); 152 child_ = process_info.hProcess; 153 154 return true; 155} 156 157void Subprocess::OnPipeReady() { 158 DWORD bytes; 159 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) { 160 if (GetLastError() == ERROR_BROKEN_PIPE) { 161 CloseHandle(pipe_); 162 pipe_ = NULL; 163 return; 164 } 165 Win32Fatal("GetOverlappedResult"); 166 } 167 168 if (is_reading_ && bytes) 169 buf_.append(overlapped_buf_, bytes); 170 171 memset(&overlapped_, 0, sizeof(overlapped_)); 172 is_reading_ = true; 173 if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_), 174 &bytes, &overlapped_)) { 175 if (GetLastError() == ERROR_BROKEN_PIPE) { 176 CloseHandle(pipe_); 177 pipe_ = NULL; 178 return; 179 } 180 if (GetLastError() != ERROR_IO_PENDING) 181 Win32Fatal("ReadFile"); 182 } 183 184 // Even if we read any bytes in the readfile call, we'll enter this 185 // function again later and get them at that point. 186} 187 188ExitStatus Subprocess::Finish() { 189 if (!child_) 190 return ExitFailure; 191 192 // TODO: add error handling for all of these. 193 WaitForSingleObject(child_, INFINITE); 194 195 DWORD exit_code = 0; 196 GetExitCodeProcess(child_, &exit_code); 197 198 CloseHandle(child_); 199 child_ = NULL; 200 201 return exit_code == 0 ? ExitSuccess : 202 exit_code == CONTROL_C_EXIT ? ExitInterrupted : 203 ExitFailure; 204} 205 206bool Subprocess::Done() const { 207 return pipe_ == NULL; 208} 209 210const string& Subprocess::GetOutput() const { 211 return buf_; 212} 213 214HANDLE SubprocessSet::ioport_; 215 216SubprocessSet::SubprocessSet() { 217 ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1); 218 if (!ioport_) 219 Win32Fatal("CreateIoCompletionPort"); 220 if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE)) 221 Win32Fatal("SetConsoleCtrlHandler"); 222} 223 224SubprocessSet::~SubprocessSet() { 225 Clear(); 226 227 SetConsoleCtrlHandler(NotifyInterrupted, FALSE); 228 CloseHandle(ioport_); 229} 230 231BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) { 232 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { 233 if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL)) 234 Win32Fatal("PostQueuedCompletionStatus"); 235 return TRUE; 236 } 237 238 return FALSE; 239} 240 241Subprocess *SubprocessSet::Add(const string& command, bool use_console) { 242 Subprocess *subprocess = new Subprocess(use_console); 243 if (!subprocess->Start(this, command)) { 244 delete subprocess; 245 return 0; 246 } 247 if (subprocess->child_) 248 running_.push_back(subprocess); 249 else 250 finished_.push(subprocess); 251 return subprocess; 252} 253 254bool SubprocessSet::DoWork() { 255 DWORD bytes_read; 256 Subprocess* subproc; 257 OVERLAPPED* overlapped; 258 259 if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc, 260 &overlapped, INFINITE)) { 261 if (GetLastError() != ERROR_BROKEN_PIPE) 262 Win32Fatal("GetQueuedCompletionStatus"); 263 } 264 265 if (!subproc) // A NULL subproc indicates that we were interrupted and is 266 // delivered by NotifyInterrupted above. 267 return true; 268 269 subproc->OnPipeReady(); 270 271 if (subproc->Done()) { 272 vector<Subprocess*>::iterator end = 273 remove(running_.begin(), running_.end(), subproc); 274 if (running_.end() != end) { 275 finished_.push(subproc); 276 running_.resize(end - running_.begin()); 277 } 278 } 279 280 return false; 281} 282 283Subprocess* SubprocessSet::NextFinished() { 284 if (finished_.empty()) 285 return NULL; 286 Subprocess* subproc = finished_.front(); 287 finished_.pop(); 288 return subproc; 289} 290 291void SubprocessSet::Clear() { 292 for (vector<Subprocess*>::iterator i = running_.begin(); 293 i != running_.end(); ++i) { 294 // Since the foreground process is in our process group, it will receive a 295 // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us. 296 if ((*i)->child_ && !(*i)->use_console_) { 297 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 298 GetProcessId((*i)->child_))) { 299 Win32Fatal("GenerateConsoleCtrlEvent"); 300 } 301 } 302 } 303 for (vector<Subprocess*>::iterator i = running_.begin(); 304 i != running_.end(); ++i) 305 delete *i; 306 running_.clear(); 307} 308