26 use_console_(use_console) {
31 if (!CloseHandle(pipe_))
32 Win32Fatal(
"CloseHandle");
41 snprintf(pipe_name,
sizeof(pipe_name),
42 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(),
this);
44 pipe_ = ::CreateNamedPipeA(pipe_name,
45 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
47 PIPE_UNLIMITED_INSTANCES,
48 0, 0, INFINITE, NULL);
49 if (pipe_ == INVALID_HANDLE_VALUE)
50 Win32Fatal(
"CreateNamedPipe");
52 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)
this, 0))
53 Win32Fatal(
"CreateIoCompletionPort");
55 memset(&overlapped_, 0,
sizeof(overlapped_));
56 if (!ConnectNamedPipe(pipe_, &overlapped_) &&
57 GetLastError() != ERROR_IO_PENDING) {
58 Win32Fatal(
"ConnectNamedPipe");
62 HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
63 NULL, OPEN_EXISTING, 0, NULL);
65 if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
66 GetCurrentProcess(), &output_write_child,
67 0, TRUE, DUPLICATE_SAME_ACCESS)) {
68 Win32Fatal(
"DuplicateHandle");
70 CloseHandle(output_write_handle);
72 return output_write_child;
76 HANDLE child_pipe = SetupPipe(set->ioport_);
78 SECURITY_ATTRIBUTES security_attributes;
79 memset(&security_attributes, 0,
sizeof(SECURITY_ATTRIBUTES));
80 security_attributes.nLength =
sizeof(SECURITY_ATTRIBUTES);
81 security_attributes.bInheritHandle = TRUE;
83 HANDLE nul = CreateFile(
"NUL", GENERIC_READ,
84 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
85 &security_attributes, OPEN_EXISTING, 0, NULL);
86 if (nul == INVALID_HANDLE_VALUE)
87 Fatal(
"couldn't open nul");
89 STARTUPINFOA startup_info;
90 memset(&startup_info, 0,
sizeof(startup_info));
91 startup_info.cb =
sizeof(STARTUPINFO);
93 startup_info.dwFlags = STARTF_USESTDHANDLES;
94 startup_info.hStdInput = nul;
95 startup_info.hStdOutput = child_pipe;
96 startup_info.hStdError = child_pipe;
101 PROCESS_INFORMATION process_info;
102 memset(&process_info, 0,
sizeof(process_info));
105 DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
109 if (!CreateProcessA(NULL, (
char*)command.c_str(), NULL, NULL,
112 &startup_info, &process_info)) {
113 DWORD error = GetLastError();
114 if (error == ERROR_FILE_NOT_FOUND) {
118 CloseHandle(child_pipe);
123 buf_ =
"CreateProcess failed: The system cannot find the file " 127 Win32Fatal(
"CreateProcess");
133 CloseHandle(child_pipe);
136 CloseHandle(process_info.hThread);
137 child_ = process_info.hProcess;
144 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
145 if (GetLastError() == ERROR_BROKEN_PIPE) {
150 Win32Fatal(
"GetOverlappedResult");
153 if (is_reading_ && bytes)
154 buf_.append(overlapped_buf_, bytes);
156 memset(&overlapped_, 0,
sizeof(overlapped_));
158 if (!::
ReadFile(pipe_, overlapped_buf_,
sizeof(overlapped_buf_),
159 &bytes, &overlapped_)) {
160 if (GetLastError() == ERROR_BROKEN_PIPE) {
165 if (GetLastError() != ERROR_IO_PENDING)
166 Win32Fatal(
"ReadFile");
178 WaitForSingleObject(child_, INFINITE);
181 GetExitCodeProcess(child_, &exit_code);
192 return pipe_ == NULL;
199 HANDLE SubprocessSet::ioport_;
202 ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
204 Win32Fatal(
"CreateIoCompletionPort");
205 if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
206 Win32Fatal(
"SetConsoleCtrlHandler");
212 SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
213 CloseHandle(ioport_);
216 BOOL WINAPI SubprocessSet::NotifyInterrupted(
DWORD dwCtrlType) {
217 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
218 if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
219 Win32Fatal(
"PostQueuedCompletionStatus");
228 if (!subprocess->
Start(
this, command)) {
232 if (subprocess->child_)
242 OVERLAPPED* overlapped;
244 if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
245 &overlapped, INFINITE)) {
246 if (GetLastError() != ERROR_BROKEN_PIPE)
247 Win32Fatal(
"GetQueuedCompletionStatus");
254 subproc->OnPipeReady();
256 if (subproc->Done()) {
257 vector<Subprocess*>::iterator end =
277 for (vector<Subprocess*>::iterator i =
running_.begin();
281 if ((*i)->child_ && !(*i)->use_console_) {
282 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
283 GetProcessId((*i)->child_))) {
284 Win32Fatal(
"GenerateConsoleCtrlEvent");
288 for (vector<Subprocess*>::iterator i =
running_.begin();
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
Subprocess * NextFinished()
vector< Subprocess * > running_
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
const string & GetOutput() const
Subprocess * Add(const string &command, bool use_console=false)
Subprocess wraps a single async subprocess.
Subprocess(bool use_console)
int ReadFile(const string &path, string *contents, string *err)
Read a file to a string (in text mode: with CRLF conversion on Windows).
bool Start(struct SubprocessSet *set, const string &command)
void Fatal(const char *msg,...)
Log a fatal message and exit.
typedef BOOL(WINAPI *MiniDumpWriteDumpFunc)(IN HANDLE
queue< Subprocess * > finished_