Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / subprocess-posix.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 <errno.h>
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <sys/wait.h>
25 #include <spawn.h>
26
27 extern char** environ;
28
29 #include "util.h"
30
31 Subprocess::Subprocess(bool use_console) : fd_(-1), pid_(-1),
32                                            use_console_(use_console) {
33 }
34
35 Subprocess::~Subprocess() {
36   if (fd_ >= 0)
37     close(fd_);
38   // Reap child if forgotten.
39   if (pid_ != -1)
40     Finish();
41 }
42
43 bool Subprocess::Start(SubprocessSet* set, const string& command) {
44   int output_pipe[2];
45   if (pipe(output_pipe) < 0)
46     Fatal("pipe: %s", strerror(errno));
47   fd_ = output_pipe[0];
48 #if !defined(USE_PPOLL)
49   // If available, we use ppoll in DoWork(); otherwise we use pselect
50   // and so must avoid overly-large FDs.
51   if (fd_ >= static_cast<int>(FD_SETSIZE))
52     Fatal("pipe: %s", strerror(EMFILE));
53 #endif  // !USE_PPOLL
54   SetCloseOnExec(fd_);
55
56   posix_spawn_file_actions_t action;
57   if (posix_spawn_file_actions_init(&action) != 0)
58     Fatal("posix_spawn_file_actions_init: %s", strerror(errno));
59
60   if (posix_spawn_file_actions_addclose(&action, output_pipe[0]) != 0)
61     Fatal("posix_spawn_file_actions_addclose: %s", strerror(errno));
62
63   posix_spawnattr_t attr;
64   if (posix_spawnattr_init(&attr) != 0)
65     Fatal("posix_spawnattr_init: %s", strerror(errno));
66
67   short flags = 0;
68
69   flags |= POSIX_SPAWN_SETSIGMASK;
70   if (posix_spawnattr_setsigmask(&attr, &set->old_mask_) != 0)
71     Fatal("posix_spawnattr_setsigmask: %s", strerror(errno));
72   // Signals which are set to be caught in the calling process image are set to
73   // default action in the new process image, so no explicit
74   // POSIX_SPAWN_SETSIGDEF parameter is needed.
75
76   // TODO: Consider using POSIX_SPAWN_USEVFORK on Linux with glibc?
77
78   if (!use_console_) {
79     // Put the child in its own process group, so ctrl-c won't reach it.
80     flags |= POSIX_SPAWN_SETPGROUP;
81     // No need to posix_spawnattr_setpgroup(&attr, 0), it's the default.
82
83     // Open /dev/null over stdin.
84     if (posix_spawn_file_actions_addopen(&action, 0, "/dev/null", O_RDONLY,
85                                          0) != 0) {
86       Fatal("posix_spawn_file_actions_addopen: %s", strerror(errno));
87     }
88
89     if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1) != 0)
90       Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
91     if (posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2) != 0)
92       Fatal("posix_spawn_file_actions_adddup2: %s", strerror(errno));
93     // In the console case, output_pipe is still inherited by the child and
94     // closed when the subprocess finishes, which then notifies ninja.
95   }
96
97   if (posix_spawnattr_setflags(&attr, flags) != 0)
98     Fatal("posix_spawnattr_setflags: %s", strerror(errno));
99
100   const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL };
101   if (posix_spawn(&pid_, "/bin/sh", &action, &attr,
102                   const_cast<char**>(spawned_args), environ) != 0)
103     Fatal("posix_spawn: %s", strerror(errno));
104
105   if (posix_spawnattr_destroy(&attr) != 0)
106     Fatal("posix_spawnattr_destroy: %s", strerror(errno));
107   if (posix_spawn_file_actions_destroy(&action) != 0)
108     Fatal("posix_spawn_file_actions_destroy: %s", strerror(errno));
109
110   close(output_pipe[1]);
111   return true;
112 }
113
114 void Subprocess::OnPipeReady() {
115   char buf[4 << 10];
116   ssize_t len = read(fd_, buf, sizeof(buf));
117   if (len > 0) {
118     buf_.append(buf, len);
119   } else {
120     if (len < 0)
121       Fatal("read: %s", strerror(errno));
122     close(fd_);
123     fd_ = -1;
124   }
125 }
126
127 ExitStatus Subprocess::Finish() {
128   assert(pid_ != -1);
129   int status;
130   if (waitpid(pid_, &status, 0) < 0)
131     Fatal("waitpid(%d): %s", pid_, strerror(errno));
132   pid_ = -1;
133
134   if (WIFEXITED(status)) {
135     int exit = WEXITSTATUS(status);
136     if (exit == 0)
137       return ExitSuccess;
138   } else if (WIFSIGNALED(status)) {
139     if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
140         || WTERMSIG(status) == SIGHUP)
141       return ExitInterrupted;
142   }
143   return ExitFailure;
144 }
145
146 bool Subprocess::Done() const {
147   return fd_ == -1;
148 }
149
150 const string& Subprocess::GetOutput() const {
151   return buf_;
152 }
153
154 int SubprocessSet::interrupted_;
155
156 void SubprocessSet::SetInterruptedFlag(int signum) {
157   interrupted_ = signum;
158 }
159
160 void SubprocessSet::HandlePendingInterruption() {
161   sigset_t pending;
162   sigemptyset(&pending);
163   if (sigpending(&pending) == -1) {
164     perror("ninja: sigpending");
165     return;
166   }
167   if (sigismember(&pending, SIGINT))
168     interrupted_ = SIGINT;
169   else if (sigismember(&pending, SIGTERM))
170     interrupted_ = SIGTERM;
171   else if (sigismember(&pending, SIGHUP))
172     interrupted_ = SIGHUP;
173 }
174
175 SubprocessSet::SubprocessSet() {
176   sigset_t set;
177   sigemptyset(&set);
178   sigaddset(&set, SIGINT);
179   sigaddset(&set, SIGTERM);
180   sigaddset(&set, SIGHUP);
181   if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
182     Fatal("sigprocmask: %s", strerror(errno));
183
184   struct sigaction act;
185   memset(&act, 0, sizeof(act));
186   act.sa_handler = SetInterruptedFlag;
187   if (sigaction(SIGINT, &act, &old_int_act_) < 0)
188     Fatal("sigaction: %s", strerror(errno));
189   if (sigaction(SIGTERM, &act, &old_term_act_) < 0)
190     Fatal("sigaction: %s", strerror(errno));
191   if (sigaction(SIGHUP, &act, &old_hup_act_) < 0)
192     Fatal("sigaction: %s", strerror(errno));
193 }
194
195 SubprocessSet::~SubprocessSet() {
196   Clear();
197
198   if (sigaction(SIGINT, &old_int_act_, 0) < 0)
199     Fatal("sigaction: %s", strerror(errno));
200   if (sigaction(SIGTERM, &old_term_act_, 0) < 0)
201     Fatal("sigaction: %s", strerror(errno));
202   if (sigaction(SIGHUP, &old_hup_act_, 0) < 0)
203     Fatal("sigaction: %s", strerror(errno));
204   if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
205     Fatal("sigprocmask: %s", strerror(errno));
206 }
207
208 Subprocess *SubprocessSet::Add(const string& command, bool use_console) {
209   Subprocess *subprocess = new Subprocess(use_console);
210   if (!subprocess->Start(this, command)) {
211     delete subprocess;
212     return 0;
213   }
214   running_.push_back(subprocess);
215   return subprocess;
216 }
217
218 #ifdef USE_PPOLL
219 bool SubprocessSet::DoWork() {
220   vector<pollfd> fds;
221   nfds_t nfds = 0;
222
223   for (vector<Subprocess*>::iterator i = running_.begin();
224        i != running_.end(); ++i) {
225     int fd = (*i)->fd_;
226     if (fd < 0)
227       continue;
228     pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
229     fds.push_back(pfd);
230     ++nfds;
231   }
232
233   interrupted_ = 0;
234   int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
235   if (ret == -1) {
236     if (errno != EINTR) {
237       perror("ninja: ppoll");
238       return false;
239     }
240     return IsInterrupted();
241   }
242
243   HandlePendingInterruption();
244   if (IsInterrupted())
245     return true;
246
247   nfds_t cur_nfd = 0;
248   for (vector<Subprocess*>::iterator i = running_.begin();
249        i != running_.end(); ) {
250     int fd = (*i)->fd_;
251     if (fd < 0)
252       continue;
253     assert(fd == fds[cur_nfd].fd);
254     if (fds[cur_nfd++].revents) {
255       (*i)->OnPipeReady();
256       if ((*i)->Done()) {
257         finished_.push(*i);
258         i = running_.erase(i);
259         continue;
260       }
261     }
262     ++i;
263   }
264
265   return IsInterrupted();
266 }
267
268 #else  // !defined(USE_PPOLL)
269 bool SubprocessSet::DoWork() {
270   fd_set set;
271   int nfds = 0;
272   FD_ZERO(&set);
273
274   for (vector<Subprocess*>::iterator i = running_.begin();
275        i != running_.end(); ++i) {
276     int fd = (*i)->fd_;
277     if (fd >= 0) {
278       FD_SET(fd, &set);
279       if (nfds < fd+1)
280         nfds = fd+1;
281     }
282   }
283
284   interrupted_ = 0;
285   int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_);
286   if (ret == -1) {
287     if (errno != EINTR) {
288       perror("ninja: pselect");
289       return false;
290     }
291     return IsInterrupted();
292   }
293
294   HandlePendingInterruption();
295   if (IsInterrupted())
296     return true;
297
298   for (vector<Subprocess*>::iterator i = running_.begin();
299        i != running_.end(); ) {
300     int fd = (*i)->fd_;
301     if (fd >= 0 && FD_ISSET(fd, &set)) {
302       (*i)->OnPipeReady();
303       if ((*i)->Done()) {
304         finished_.push(*i);
305         i = running_.erase(i);
306         continue;
307       }
308     }
309     ++i;
310   }
311
312   return IsInterrupted();
313 }
314 #endif  // !defined(USE_PPOLL)
315
316 Subprocess* SubprocessSet::NextFinished() {
317   if (finished_.empty())
318     return NULL;
319   Subprocess* subproc = finished_.front();
320   finished_.pop();
321   return subproc;
322 }
323
324 void SubprocessSet::Clear() {
325   for (vector<Subprocess*>::iterator i = running_.begin();
326        i != running_.end(); ++i)
327     // Since the foreground process is in our process group, it will receive
328     // the interruption signal (i.e. SIGINT or SIGTERM) at the same time as us.
329     if (!(*i)->use_console_)
330       kill(-(*i)->pid_, interrupted_);
331   for (vector<Subprocess*>::iterator i = running_.begin();
332        i != running_.end(); ++i)
333     delete *i;
334   running_.clear();
335 }