4bab71939d6d9c8c65054460003601777a942aaa
[platform/upstream/ninja.git] / src / subprocess-win32.cc
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
24 Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(),
25                                            is_reading_(false),
26                                            use_console_(use_console) {
27 }
28
29 Subprocess::~Subprocess() {
30   if (pipe_) {
31     if (!CloseHandle(pipe_))
32       Win32Fatal("CloseHandle");
33   }
34   // Reap child if forgotten.
35   if (child_)
36     Finish();
37 }
38
39 HANDLE Subprocess::SetupPipe(HANDLE ioport) {
40   char pipe_name[100];
41   snprintf(pipe_name, sizeof(pipe_name),
42            "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);
43
44   pipe_ = ::CreateNamedPipeA(pipe_name,
45                              PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
46                              PIPE_TYPE_BYTE,
47                              PIPE_UNLIMITED_INSTANCES,
48                              0, 0, INFINITE, NULL);
49   if (pipe_ == INVALID_HANDLE_VALUE)
50     Win32Fatal("CreateNamedPipe");
51
52   if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
53     Win32Fatal("CreateIoCompletionPort");
54
55   memset(&overlapped_, 0, sizeof(overlapped_));
56   if (!ConnectNamedPipe(pipe_, &overlapped_) &&
57       GetLastError() != ERROR_IO_PENDING) {
58     Win32Fatal("ConnectNamedPipe");
59   }
60
61   // Get the write end of the pipe as a handle inheritable across processes.
62   HANDLE output_write_handle = CreateFile(pipe_name, GENERIC_WRITE, 0,
63                                           NULL, OPEN_EXISTING, 0, NULL);
64   HANDLE output_write_child;
65   if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
66                        GetCurrentProcess(), &output_write_child,
67                        0, TRUE, DUPLICATE_SAME_ACCESS)) {
68     Win32Fatal("DuplicateHandle");
69   }
70   CloseHandle(output_write_handle);
71
72   return output_write_child;
73 }
74
75 bool Subprocess::Start(SubprocessSet* set, const string& command) {
76   HANDLE child_pipe = SetupPipe(set->ioport_);
77
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;
82   // Must be inheritable so subprocesses can dup to children.
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");
88
89   STARTUPINFOA startup_info;
90   memset(&startup_info, 0, sizeof(startup_info));
91   startup_info.cb = sizeof(STARTUPINFO);
92   if (!use_console_) {
93     startup_info.dwFlags = STARTF_USESTDHANDLES;
94     startup_info.hStdInput = nul;
95     startup_info.hStdOutput = child_pipe;
96     startup_info.hStdError = child_pipe;
97   }
98   // In the console case, child_pipe is still inherited by the child and closed
99   // when the subprocess finishes, which then notifies ninja.
100
101   PROCESS_INFORMATION process_info;
102   memset(&process_info, 0, sizeof(process_info));
103
104   // Ninja handles ctrl-c, except for subprocesses in console pools.
105   DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
106
107   // Do not prepend 'cmd /c' on Windows, this breaks command
108   // lines greater than 8,191 chars.
109   if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
110                       /* inherit handles */ TRUE, process_flags,
111                       NULL, NULL,
112                       &startup_info, &process_info)) {
113     DWORD error = GetLastError();
114     if (error == ERROR_FILE_NOT_FOUND) {
115       // File (program) not found error is treated as a normal build
116       // action failure.
117       if (child_pipe)
118         CloseHandle(child_pipe);
119       CloseHandle(pipe_);
120       CloseHandle(nul);
121       pipe_ = NULL;
122       // child_ is already NULL;
123       buf_ = "CreateProcess failed: The system cannot find the file "
124           "specified.\n";
125       return true;
126     } else {
127       Win32Fatal("CreateProcess");    // pass all other errors to Win32Fatal
128     }
129   }
130
131   // Close pipe channel only used by the child.
132   if (child_pipe)
133     CloseHandle(child_pipe);
134   CloseHandle(nul);
135
136   CloseHandle(process_info.hThread);
137   child_ = process_info.hProcess;
138
139   return true;
140 }
141
142 void Subprocess::OnPipeReady() {
143   DWORD bytes;
144   if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
145     if (GetLastError() == ERROR_BROKEN_PIPE) {
146       CloseHandle(pipe_);
147       pipe_ = NULL;
148       return;
149     }
150     Win32Fatal("GetOverlappedResult");
151   }
152
153   if (is_reading_ && bytes)
154     buf_.append(overlapped_buf_, bytes);
155
156   memset(&overlapped_, 0, sizeof(overlapped_));
157   is_reading_ = true;
158   if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
159                   &bytes, &overlapped_)) {
160     if (GetLastError() == ERROR_BROKEN_PIPE) {
161       CloseHandle(pipe_);
162       pipe_ = NULL;
163       return;
164     }
165     if (GetLastError() != ERROR_IO_PENDING)
166       Win32Fatal("ReadFile");
167   }
168
169   // Even if we read any bytes in the readfile call, we'll enter this
170   // function again later and get them at that point.
171 }
172
173 ExitStatus Subprocess::Finish() {
174   if (!child_)
175     return ExitFailure;
176
177   // TODO: add error handling for all of these.
178   WaitForSingleObject(child_, INFINITE);
179
180   DWORD exit_code = 0;
181   GetExitCodeProcess(child_, &exit_code);
182
183   CloseHandle(child_);
184   child_ = NULL;
185
186   return exit_code == 0              ? ExitSuccess :
187          exit_code == CONTROL_C_EXIT ? ExitInterrupted :
188                                        ExitFailure;
189 }
190
191 bool Subprocess::Done() const {
192   return pipe_ == NULL;
193 }
194
195 const string& Subprocess::GetOutput() const {
196   return buf_;
197 }
198
199 HANDLE SubprocessSet::ioport_;
200
201 SubprocessSet::SubprocessSet() {
202   ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
203   if (!ioport_)
204     Win32Fatal("CreateIoCompletionPort");
205   if (!SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
206     Win32Fatal("SetConsoleCtrlHandler");
207 }
208
209 SubprocessSet::~SubprocessSet() {
210   Clear();
211
212   SetConsoleCtrlHandler(NotifyInterrupted, FALSE);
213   CloseHandle(ioport_);
214 }
215
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");
220     return TRUE;
221   }
222
223   return FALSE;
224 }
225
226 Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
227   Subprocess *subprocess = new Subprocess(use_console);
228   if (!subprocess->Start(this, command)) {
229     delete subprocess;
230     return 0;
231   }
232   if (subprocess->child_)
233     running_.push_back(subprocess);
234   else
235     finished_.push(subprocess);
236   return subprocess;
237 }
238
239 bool SubprocessSet::DoWork() {
240   DWORD bytes_read;
241   Subprocess* subproc;
242   OVERLAPPED* overlapped;
243
244   if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
245                                  &overlapped, INFINITE)) {
246     if (GetLastError() != ERROR_BROKEN_PIPE)
247       Win32Fatal("GetQueuedCompletionStatus");
248   }
249
250   if (!subproc) // A NULL subproc indicates that we were interrupted and is
251                 // delivered by NotifyInterrupted above.
252     return true;
253
254   subproc->OnPipeReady();
255
256   if (subproc->Done()) {
257     vector<Subprocess*>::iterator end =
258         remove(running_.begin(), running_.end(), subproc);
259     if (running_.end() != end) {
260       finished_.push(subproc);
261       running_.resize(end - running_.begin());
262     }
263   }
264
265   return false;
266 }
267
268 Subprocess* SubprocessSet::NextFinished() {
269   if (finished_.empty())
270     return NULL;
271   Subprocess* subproc = finished_.front();
272   finished_.pop();
273   return subproc;
274 }
275
276 void SubprocessSet::Clear() {
277   for (vector<Subprocess*>::iterator i = running_.begin();
278        i != running_.end(); ++i) {
279     // Since the foreground process is in our process group, it will receive a
280     // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us.
281     if ((*i)->child_ && !(*i)->use_console_) {
282       if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
283                                     GetProcessId((*i)->child_))) {
284         Win32Fatal("GenerateConsoleCtrlEvent");
285       }
286     }
287   }
288   for (vector<Subprocess*>::iterator i = running_.begin();
289        i != running_.end(); ++i)
290     delete *i;
291   running_.clear();
292 }