28 if (!CloseHandle(pipe_))
29 Win32Fatal(
"CloseHandle");
38 snprintf(pipe_name,
sizeof(pipe_name),
39 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(),
this);
41 pipe_ = ::CreateNamedPipeA(pipe_name,
42 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
44 PIPE_UNLIMITED_INSTANCES,
45 0, 0, INFINITE, NULL);
46 if (pipe_ == INVALID_HANDLE_VALUE)
47 Win32Fatal(
"CreateNamedPipe");
49 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)
this, 0))
50 Win32Fatal(
"CreateIoCompletionPort");
52 memset(&overlapped_, 0,
sizeof(overlapped_));
53 if (!ConnectNamedPipe(pipe_, &overlapped_) &&
54 GetLastError() != ERROR_IO_PENDING) {
55 Win32Fatal(
"ConnectNamedPipe");
59 HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
60 NULL, OPEN_EXISTING, 0, NULL);
62 if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
63 GetCurrentProcess(), &output_write_child,
64 0, TRUE, DUPLICATE_SAME_ACCESS)) {
65 Win32Fatal(
"DuplicateHandle");
67 CloseHandle(output_write_handle);
69 return output_write_child;
73 HANDLE child_pipe = SetupPipe(set->ioport_);
75 SECURITY_ATTRIBUTES security_attributes;
76 memset(&security_attributes, 0,
sizeof(SECURITY_ATTRIBUTES));
77 security_attributes.nLength =
sizeof(SECURITY_ATTRIBUTES);
78 security_attributes.bInheritHandle = TRUE;
80 HANDLE nul = CreateFile(
"NUL", GENERIC_READ,
81 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
82 &security_attributes, OPEN_EXISTING, 0, NULL);
83 if (nul == INVALID_HANDLE_VALUE)
84 Fatal(
"couldn't open nul");
86 STARTUPINFOA startup_info;
87 memset(&startup_info, 0,
sizeof(startup_info));
88 startup_info.cb =
sizeof(STARTUPINFO);
89 startup_info.dwFlags = STARTF_USESTDHANDLES;
90 startup_info.hStdInput = nul;
91 startup_info.hStdOutput = child_pipe;
92 startup_info.hStdError = child_pipe;
94 PROCESS_INFORMATION process_info;
95 memset(&process_info, 0,
sizeof(process_info));
99 if (!CreateProcessA(NULL, (
char*)command.c_str(), NULL, NULL,
100 TRUE, CREATE_NEW_PROCESS_GROUP,
102 &startup_info, &process_info)) {
103 DWORD error = GetLastError();
104 if (error == ERROR_FILE_NOT_FOUND) {
108 CloseHandle(child_pipe);
113 buf_ =
"CreateProcess failed: The system cannot find the file "
117 Win32Fatal(
"CreateProcess");
123 CloseHandle(child_pipe);
126 CloseHandle(process_info.hThread);
127 child_ = process_info.hProcess;
134 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
135 if (GetLastError() == ERROR_BROKEN_PIPE) {
140 Win32Fatal(
"GetOverlappedResult");
143 if (is_reading_ && bytes)
144 buf_.append(overlapped_buf_, bytes);
146 memset(&overlapped_, 0,
sizeof(overlapped_));
148 if (!::
ReadFile(pipe_, overlapped_buf_,
sizeof(overlapped_buf_),
149 &bytes, &overlapped_)) {
150 if (GetLastError() == ERROR_BROKEN_PIPE) {
155 if (GetLastError() != ERROR_IO_PENDING)
156 Win32Fatal(
"ReadFile");
168 WaitForSingleObject(child_, INFINITE);
171 GetExitCodeProcess(child_, &exit_code);
182 return pipe_ == NULL;
189 HANDLE SubprocessSet::ioport_;
192 ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
194 Win32Fatal(
"CreateIoCompletionPort");
195 if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
196 Win32Fatal(
"SetConsoleCtrlHandler");
202 SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
203 CloseHandle(ioport_);
206 BOOL WINAPI SubprocessSet::NotifyInterrupted(
DWORD dwCtrlType) {
207 if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
208 if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
209 Win32Fatal(
"PostQueuedCompletionStatus");
218 if (!subprocess->
Start(
this, command)) {
222 if (subprocess->child_)
232 OVERLAPPED* overlapped;
234 if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
235 &overlapped, INFINITE)) {
236 if (GetLastError() != ERROR_BROKEN_PIPE)
237 Win32Fatal(
"GetQueuedCompletionStatus");
244 subproc->OnPipeReady();
246 if (subproc->Done()) {
247 vector<Subprocess*>::iterator end =
267 for (vector<Subprocess*>::iterator i =
running_.begin();
270 if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
271 GetProcessId((*i)->child_))) {
272 Win32Fatal(
"GenerateConsoleCtrlEvent");
276 for (vector<Subprocess*>::iterator i =
running_.begin();
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
Subprocess * NextFinished()
Subprocess * Add(const string &command)
vector< Subprocess * > running_
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
const string & GetOutput() const
Subprocess wraps a single async subprocess.
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_