28 use_console_(use_console) {
33 if (!CloseHandle(pipe_))
34 Win32Fatal(
"CloseHandle");
41 HANDLE Subprocess::SetupPipe(HANDLE ioport) {
43 snprintf(pipe_name,
sizeof(pipe_name),
44 "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(),
this);
46 pipe_ = ::CreateNamedPipeA(pipe_name,
47 PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
49 PIPE_UNLIMITED_INSTANCES,
50 0, 0, INFINITE, NULL);
51 if (pipe_ == INVALID_HANDLE_VALUE)
52 Win32Fatal(
"CreateNamedPipe");
54 if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)
this, 0))
55 Win32Fatal(
"CreateIoCompletionPort");
57 memset(&overlapped_, 0,
sizeof(overlapped_));
58 if (!ConnectNamedPipe(pipe_, &overlapped_) &&
59 GetLastError() != ERROR_IO_PENDING) {
60 Win32Fatal(
"ConnectNamedPipe");
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");
72 CloseHandle(output_write_handle);
74 return output_write_child;
78 HANDLE child_pipe = SetupPipe(set->ioport_);
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;
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");
92 STARTUPINFOA startup_info;
93 memset(&startup_info, 0,
sizeof(startup_info));
94 startup_info.cb =
sizeof(STARTUPINFO);
96 startup_info.dwFlags = STARTF_USESTDHANDLES;
97 startup_info.hStdInput = nul;
98 startup_info.hStdOutput = child_pipe;
99 startup_info.hStdError = child_pipe;
104 PROCESS_INFORMATION process_info;
105 memset(&process_info, 0,
sizeof(process_info));
108 DWORD process_flags =
use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
112 if (!CreateProcessA(NULL, (
char*)command.c_str(), NULL, NULL,
115 &startup_info, &process_info)) {
116 DWORD error = GetLastError();
117 if (error == ERROR_FILE_NOT_FOUND) {
121 CloseHandle(child_pipe);
126 buf_ =
"CreateProcess failed: The system cannot find the file " 130 fprintf(stderr,
"\nCreateProcess failed. Command attempted:\n\"%s\"\n",
132 const char* hint = NULL;
136 if (error == ERROR_INVALID_PARAMETER) {
137 if (command.length() > 0 && (command[0] ==
' ' || command[0] ==
'\t'))
138 hint =
"command contains leading whitespace";
140 hint =
"is the command line too long?";
142 Win32Fatal(
"CreateProcess", hint);
148 CloseHandle(child_pipe);
151 CloseHandle(process_info.hThread);
152 child_ = process_info.hProcess;
159 if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
160 if (GetLastError() == ERROR_BROKEN_PIPE) {
165 Win32Fatal(
"GetOverlappedResult");
168 if (is_reading_ && bytes)
169 buf_.append(overlapped_buf_, bytes);
171 memset(&overlapped_, 0,
sizeof(overlapped_));
173 if (!::
ReadFile(pipe_, overlapped_buf_,
sizeof(overlapped_buf_),
174 &bytes, &overlapped_)) {
175 if (GetLastError() == ERROR_BROKEN_PIPE) {
180 if (GetLastError() != ERROR_IO_PENDING)
181 Win32Fatal(
"ReadFile");
193 WaitForSingleObject(child_, INFINITE);
196 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();
Subprocess * Add(const std::string &command, bool use_console=false)
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
std::queue< Subprocess * > finished_
Subprocess * NextFinished()
ExitStatus Finish()
Returns ExitSuccess on successful process exit, ExitInterrupted if the process was interrupted...
bool Start(struct SubprocessSet *set, const std::string &command)
Subprocess wraps a single async subprocess.
Subprocess(bool use_console)
int ReadFile(const string &path, string *contents, string *err)
void Fatal(const char *msg,...)
Log a fatal message and exit.
const std::string & GetOutput() const
std::vector< Subprocess * > running_