29 use_console_(use_console) {
41 if (pipe(output_pipe) < 0)
42 Fatal(
"pipe: %s", strerror(errno));
44 #if !defined(USE_PPOLL) 47 if (
fd_ >= static_cast<int>(FD_SETSIZE))
48 Fatal(
"pipe: %s", strerror(EMFILE));
54 Fatal(
"fork: %s", strerror(errno));
57 close(output_pipe[0]);
60 int error_pipe = output_pipe[1];
62 if (sigaction(SIGINT, &set->old_act_, 0) < 0)
64 if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0)
69 if (setpgid(0, 0) < 0)
73 int devnull = open(
"/dev/null", O_RDONLY);
76 if (dup2(devnull, 0) < 0)
80 if (dup2(output_pipe[1], 1) < 0 ||
81 dup2(output_pipe[1], 2) < 0)
86 close(output_pipe[1]);
91 execl(
"/bin/sh",
"/bin/sh",
"-c", command.c_str(), (
char *) NULL);
96 char* err = strerror(errno);
97 if (write(error_pipe, err, strlen(err)) < 0) {
104 close(output_pipe[1]);
110 ssize_t len = read(
fd_, buf,
sizeof(buf));
112 buf_.append(buf, len);
115 Fatal(
"read: %s", strerror(errno));
124 if (waitpid(
pid_, &status, 0) < 0)
125 Fatal(
"waitpid(%d): %s",
pid_, strerror(errno));
128 if (WIFEXITED(status)) {
129 int exit = WEXITSTATUS(status);
132 }
else if (WIFSIGNALED(status)) {
133 if (WTERMSIG(status) == SIGINT)
157 sigaddset(&
set, SIGINT);
158 if (sigprocmask(SIG_BLOCK, &
set, &old_mask_) < 0)
159 Fatal(
"sigprocmask: %s", strerror(errno));
161 struct sigaction act;
162 memset(&act, 0,
sizeof(act));
163 act.sa_handler = SetInterruptedFlag;
164 if (sigaction(SIGINT, &act, &old_act_) < 0)
165 Fatal(
"sigaction: %s", strerror(errno));
171 if (sigaction(SIGINT, &old_act_, 0) < 0)
172 Fatal(
"sigaction: %s", strerror(errno));
173 if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
174 Fatal(
"sigprocmask: %s", strerror(errno));
179 if (!subprocess->
Start(
this, command)) {
183 running_.push_back(subprocess);
192 for (vector<Subprocess*>::iterator i = running_.begin();
193 i != running_.end(); ++i) {
197 pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
202 interrupted_ =
false;
203 int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
205 if (errno != EINTR) {
206 perror(
"ninja: ppoll");
213 for (vector<Subprocess*>::iterator i = running_.begin();
214 i != running_.end(); ) {
218 assert(fd == fds[cur_nfd].fd);
219 if (fds[cur_nfd++].revents) {
223 i = running_.erase(i);
233 #else // !defined(USE_PPOLL) 239 for (vector<Subprocess*>::iterator i = running_.begin();
240 i != running_.end(); ++i) {
249 interrupted_ =
false;
250 int ret = pselect(nfds, &
set, 0, 0, 0, &old_mask_);
252 if (errno != EINTR) {
253 perror(
"ninja: pselect");
259 for (vector<Subprocess*>::iterator i = running_.begin();
260 i != running_.end(); ) {
262 if (fd >= 0 && FD_ISSET(fd, &
set)) {
266 i = running_.erase(i);
275 #endif // !defined(USE_PPOLL) 278 if (finished_.empty())
286 for (vector<Subprocess*>::iterator i = running_.begin();
287 i != running_.end(); ++i)
290 if (!(*i)->use_console_)
291 kill(-(*i)->pid_, SIGINT);
292 for (vector<Subprocess*>::iterator i = running_.begin();
293 i != running_.end(); ++i)
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
static void SetInterruptedFlag(int signum)
Subprocess * NextFinished()
void SetCloseOnExec(int fd)
Mark a file descriptor to not be inherited on exec()s.
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)
bool Start(struct SubprocessSet *set, const string &command)
void Fatal(const char *msg,...)
Log a fatal message and exit.