17 #include <sys/select.h> 33 use_console_(use_console) {
46 if (pipe(output_pipe) < 0)
47 Fatal(
"pipe: %s", strerror(errno));
49 #if !defined(USE_PPOLL) 52 if (
fd_ >= static_cast<int>(FD_SETSIZE))
53 Fatal(
"pipe: %s", strerror(EMFILE));
57 posix_spawn_file_actions_t action;
58 int err = posix_spawn_file_actions_init(&action);
60 Fatal(
"posix_spawn_file_actions_init: %s", strerror(err));
62 err = posix_spawn_file_actions_addclose(&action, output_pipe[0]);
64 Fatal(
"posix_spawn_file_actions_addclose: %s", strerror(err));
66 posix_spawnattr_t attr;
67 err = posix_spawnattr_init(&attr);
69 Fatal(
"posix_spawnattr_init: %s", strerror(err));
73 flags |= POSIX_SPAWN_SETSIGMASK;
74 err = posix_spawnattr_setsigmask(&attr, &set->old_mask_);
76 Fatal(
"posix_spawnattr_setsigmask: %s", strerror(err));
83 flags |= POSIX_SPAWN_SETPGROUP;
87 err = posix_spawn_file_actions_addopen(&action, 0,
"/dev/null", O_RDONLY,
90 Fatal(
"posix_spawn_file_actions_addopen: %s", strerror(err));
93 err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1);
95 Fatal(
"posix_spawn_file_actions_adddup2: %s", strerror(err));
96 err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2);
98 Fatal(
"posix_spawn_file_actions_adddup2: %s", strerror(err));
99 err = posix_spawn_file_actions_addclose(&action, output_pipe[1]);
101 Fatal(
"posix_spawn_file_actions_addclose: %s", strerror(err));
105 #ifdef POSIX_SPAWN_USEVFORK 106 flags |= POSIX_SPAWN_USEVFORK;
109 err = posix_spawnattr_setflags(&attr, flags);
111 Fatal(
"posix_spawnattr_setflags: %s", strerror(err));
113 const char* spawned_args[] = {
"/bin/sh",
"-c", command.c_str(), NULL };
114 err = posix_spawn(&
pid_,
"/bin/sh", &action, &attr,
115 const_cast<char**>(spawned_args),
environ);
117 Fatal(
"posix_spawn: %s", strerror(err));
119 err = posix_spawnattr_destroy(&attr);
121 Fatal(
"posix_spawnattr_destroy: %s", strerror(err));
122 err = posix_spawn_file_actions_destroy(&action);
124 Fatal(
"posix_spawn_file_actions_destroy: %s", strerror(err));
126 close(output_pipe[1]);
132 ssize_t len = read(
fd_, buf,
sizeof(buf));
134 buf_.append(buf, len);
137 Fatal(
"read: %s", strerror(errno));
146 if (waitpid(
pid_, &status, 0) < 0)
147 Fatal(
"waitpid(%d): %s",
pid_, strerror(errno));
150 if (WIFEXITED(status)) {
151 int exit = WEXITSTATUS(status);
154 }
else if (WIFSIGNALED(status)) {
155 if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
156 || WTERMSIG(status) == SIGHUP)
178 sigemptyset(&pending);
179 if (sigpending(&pending) == -1) {
180 perror(
"ninja: sigpending");
183 if (sigismember(&pending, SIGINT))
185 else if (sigismember(&pending, SIGTERM))
187 else if (sigismember(&pending, SIGHUP))
194 sigaddset(&
set, SIGINT);
195 sigaddset(&
set, SIGTERM);
196 sigaddset(&
set, SIGHUP);
197 if (sigprocmask(SIG_BLOCK, &
set, &
old_mask_) < 0)
198 Fatal(
"sigprocmask: %s", strerror(errno));
200 struct sigaction act;
201 memset(&act, 0,
sizeof(act));
204 Fatal(
"sigaction: %s", strerror(errno));
206 Fatal(
"sigaction: %s", strerror(errno));
208 Fatal(
"sigaction: %s", strerror(errno));
215 Fatal(
"sigaction: %s", strerror(errno));
217 Fatal(
"sigaction: %s", strerror(errno));
219 Fatal(
"sigaction: %s", strerror(errno));
220 if (sigprocmask(SIG_SETMASK, &
old_mask_, 0) < 0)
221 Fatal(
"sigprocmask: %s", strerror(errno));
226 if (!subprocess->
Start(
this, command)) {
239 for (vector<Subprocess*>::iterator i =
running_.begin();
244 pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
250 int ret = ppoll(&fds.front(), nfds, NULL, &
old_mask_);
252 if (errno != EINTR) {
253 perror(
"ninja: ppoll");
264 for (vector<Subprocess*>::iterator i =
running_.begin();
269 assert(fd == fds[cur_nfd].fd);
270 if (fds[cur_nfd++].revents) {
284 #else // !defined(USE_PPOLL) 290 for (vector<Subprocess*>::iterator i =
running_.begin();
301 int ret = pselect(nfds, &
set, 0, 0, 0, &
old_mask_);
303 if (errno != EINTR) {
304 perror(
"ninja: pselect");
314 for (vector<Subprocess*>::iterator i =
running_.begin();
317 if (fd >= 0 && FD_ISSET(fd, &
set)) {
330 #endif // !defined(USE_PPOLL) 341 for (vector<Subprocess*>::iterator i =
running_.begin();
345 if (!(*i)->use_console_)
347 for (vector<Subprocess*>::iterator i =
running_.begin();
SubprocessSet runs a ppoll/pselect() loop around a set of Subprocesses.
static void SetInterruptedFlag(int signum)
Subprocess * NextFinished()
vector< Subprocess * > running_
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...
struct sigaction old_int_act_
Subprocess * Add(const string &command, bool use_console=false)
Subprocess wraps a single async subprocess.
static bool IsInterrupted()
static int interrupted_
Store the signal number that causes the interruption.
struct sigaction old_hup_act_
Subprocess(bool use_console)
bool Start(struct SubprocessSet *set, const string &command)
void Fatal(const char *msg,...)
Log a fatal message and exit.
static void HandlePendingInterruption()
const string & GetOutput() const
queue< Subprocess * > finished_
struct sigaction old_term_act_