29 use_console_(use_console) {
34 if (!CloseHandle(pipe_))
35 Win32Fatal(
"CloseHandle");
42 HANDLE Subprocess::SetupPipe(HANDLE ioport) {
44 snprintf(pipe_name,
sizeof(pipe_name),
45 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(),
this);
47 pipe_ = ::CreateNamedPipeA(pipe_name,
48 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
50 PIPE_UNLIMITED_INSTANCES,
51 0, 0, INFINITE, NULL);
52 if (pipe_ == INVALID_HANDLE_VALUE)
53 Win32Fatal(
"CreateNamedPipe");
55 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)
this, 0))
56 Win32Fatal(
"CreateIoCompletionPort");
58 memset(&overlapped_, 0,
sizeof(overlapped_));
59 if (!ConnectNamedPipe(pipe_, &overlapped_) &&
60 GetLastError() != ERROR_IO_PENDING) {
61 Win32Fatal(
"ConnectNamedPipe");
65 HANDLE output_write_handle =
66 CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
67 HANDLE output_write_child;
68 if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
69 GetCurrentProcess(), &output_write_child,
70 0, TRUE, DUPLICATE_SAME_ACCESS)) {
71 Win32Fatal(
"DuplicateHandle");
73 CloseHandle(output_write_handle);
75 return output_write_child;
79 HANDLE child_pipe = SetupPipe(set->ioport_);
81 SECURITY_ATTRIBUTES security_attributes;
82 memset(&security_attributes, 0,
sizeof(SECURITY_ATTRIBUTES));
83 security_attributes.nLength =
sizeof(SECURITY_ATTRIBUTES);
84 security_attributes.bInheritHandle = TRUE;
87 CreateFileA(
"NUL", GENERIC_READ,
88 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
89 &security_attributes, OPEN_EXISTING, 0, NULL);
90 if (nul == INVALID_HANDLE_VALUE)
91 Fatal(
"couldn't open nul");
93 STARTUPINFOA startup_info;
94 memset(&startup_info, 0,
sizeof(startup_info));
95 startup_info.cb =
sizeof(STARTUPINFO);
97 startup_info.dwFlags = STARTF_USESTDHANDLES;
98 startup_info.hStdInput = nul;
99 startup_info.hStdOutput = child_pipe;
100 startup_info.hStdError = child_pipe;
105 PROCESS_INFORMATION process_info;
106 memset(&process_info, 0,
sizeof(process_info));
109 DWORD process_flags =
use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
113 if (!CreateProcessA(NULL, (
char*)command.c_str(), NULL, NULL,
116 &startup_info, &process_info)) {
117 DWORD error = GetLastError();
118 if (error == ERROR_FILE_NOT_FOUND) {
122 CloseHandle(child_pipe);
127 buf_ =
"CreateProcess failed: The system cannot find the file "
131 fprintf(stderr,
"\nCreateProcess failed. Command attempted:\n\"%s\"\n",
133 const char* hint = NULL;
137 if (error == ERROR_INVALID_PARAMETER) {
138 if (command.length() > 0 && (command[0] ==
' ' || command[0] ==
'\t'))
139 hint =
"command contains leading whitespace";
141 hint =
"is the command line too long?";
143 Win32Fatal(
"CreateProcess", hint);
149 CloseHandle(child_pipe);
152 CloseHandle(process_info.hThread);
153 child_ = process_info.hProcess;
160 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
161 if (GetLastError() == ERROR_BROKEN_PIPE) {
166 Win32Fatal(
"GetOverlappedResult");
169 if (is_reading_ && bytes)
170 buf_.append(overlapped_buf_, bytes);
172 memset(&overlapped_, 0,
sizeof(overlapped_));
174 if (!::
ReadFile(pipe_, overlapped_buf_,
sizeof(overlapped_buf_),
175 &bytes, &overlapped_)) {
176 if (GetLastError() == ERROR_BROKEN_PIPE) {
181 if (GetLastError() != ERROR_IO_PENDING)
182 Win32Fatal(
"ReadFile");
194 WaitForSingleObject(child_, INFINITE);
197 GetExitCodeProcess(child_, &exit_code);
207 return pipe_ == NULL;
214 HANDLE SubprocessSet::ioport_;
217 ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
219 Win32Fatal(
"CreateIoCompletionPort");
220 if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
221 Win32Fatal(
"SetConsoleCtrlHandler");
227 SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
228 CloseHandle(ioport_);
231 BOOL 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");
243 if (!subprocess->
Start(
this, command)) {
247 if (subprocess->child_)
257 OVERLAPPED* overlapped;
259 if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
260 &overlapped, INFINITE)) {
261 if (GetLastError() != ERROR_BROKEN_PIPE)
262 Win32Fatal(
"GetQueuedCompletionStatus");
269 subproc->OnPipeReady();
271 if (subproc->Done()) {
272 vector<Subprocess*>::iterator end =
292 for (vector<Subprocess*>::iterator i =
running_.begin();
296 if ((*i)->child_ && !(*i)->use_console_) {
297 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
298 GetProcessId((*i)->child_))) {
299 Win32Fatal(
"GenerateConsoleCtrlEvent");
303 for (vector<Subprocess*>::iterator i =
running_.begin();
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
std::queue< Subprocess * > finished_
Subprocess * NextFinished()
std::vector< Subprocess * > running_
Subprocess * Add(const std::string &command, bool use_console=false)
Subprocess wraps a single async subprocess.
bool Start(struct SubprocessSet *set, const std::string &command)
Subprocess(bool use_console)
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted,...
const std::string & GetOutput() const
void Fatal(const char *msg,...)
Log a fatal message and exit.
int ReadFile(const string &path, string *contents, string *err)