17 #include <sys/select.h> 27 #if defined(USE_PPOLL) 30 #include <sys/select.h> 40 use_console_(use_console) {
53 if (pipe(output_pipe) < 0)
54 Fatal(
"pipe: %s", strerror(errno));
56 #if !defined(USE_PPOLL) 59 if (
fd_ >= static_cast<int>(FD_SETSIZE))
60 Fatal(
"pipe: %s", strerror(EMFILE));
64 posix_spawn_file_actions_t action;
65 int err = posix_spawn_file_actions_init(&action);
67 Fatal(
"posix_spawn_file_actions_init: %s", strerror(err));
69 err = posix_spawn_file_actions_addclose(&action, output_pipe[0]);
71 Fatal(
"posix_spawn_file_actions_addclose: %s", strerror(err));
73 posix_spawnattr_t attr;
74 err = posix_spawnattr_init(&attr);
76 Fatal(
"posix_spawnattr_init: %s", strerror(err));
80 flags |= POSIX_SPAWN_SETSIGMASK;
81 err = posix_spawnattr_setsigmask(&attr, &set->old_mask_);
83 Fatal(
"posix_spawnattr_setsigmask: %s", strerror(err));
90 flags |= POSIX_SPAWN_SETPGROUP;
94 err = posix_spawn_file_actions_addopen(&action, 0,
"/dev/null", O_RDONLY,
97 Fatal(
"posix_spawn_file_actions_addopen: %s", strerror(err));
100 err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 1);
102 Fatal(
"posix_spawn_file_actions_adddup2: %s", strerror(err));
103 err = posix_spawn_file_actions_adddup2(&action, output_pipe[1], 2);
105 Fatal(
"posix_spawn_file_actions_adddup2: %s", strerror(err));
106 err = posix_spawn_file_actions_addclose(&action, output_pipe[1]);
108 Fatal(
"posix_spawn_file_actions_addclose: %s", strerror(err));
112 #ifdef POSIX_SPAWN_USEVFORK 113 flags |= POSIX_SPAWN_USEVFORK;
116 err = posix_spawnattr_setflags(&attr, flags);
118 Fatal(
"posix_spawnattr_setflags: %s", strerror(err));
120 const char* spawned_args[] = {
"/bin/sh",
"-c", command.c_str(), NULL };
121 err = posix_spawn(&
pid_,
"/bin/sh", &action, &attr,
122 const_cast<char**>(spawned_args),
environ);
124 Fatal(
"posix_spawn: %s", strerror(err));
126 err = posix_spawnattr_destroy(&attr);
128 Fatal(
"posix_spawnattr_destroy: %s", strerror(err));
129 err = posix_spawn_file_actions_destroy(&action);
131 Fatal(
"posix_spawn_file_actions_destroy: %s", strerror(err));
133 close(output_pipe[1]);
139 ssize_t len = read(
fd_, buf,
sizeof(buf));
141 buf_.append(buf, len);
144 Fatal(
"read: %s", strerror(errno));
153 if (waitpid(
pid_, &status, 0) < 0)
154 Fatal(
"waitpid(%d): %s",
pid_, strerror(errno));
158 if (WIFEXITED(status) && WEXITSTATUS(status) & 0x80) {
162 int signal = WEXITSTATUS(status) & 0x7f;
163 status = (signal << 16) | signal;
167 if (WIFEXITED(status)) {
168 int exit = WEXITSTATUS(status);
171 }
else if (WIFSIGNALED(status)) {
172 if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM
173 || WTERMSIG(status) == SIGHUP)
195 sigemptyset(&pending);
196 if (sigpending(&pending) == -1) {
197 perror(
"ninja: sigpending");
200 if (sigismember(&pending, SIGINT))
202 else if (sigismember(&pending, SIGTERM))
204 else if (sigismember(&pending, SIGHUP))
211 sigaddset(&
set, SIGINT);
212 sigaddset(&
set, SIGTERM);
213 sigaddset(&
set, SIGHUP);
214 if (sigprocmask(SIG_BLOCK, &
set, &
old_mask_) < 0)
215 Fatal(
"sigprocmask: %s", strerror(errno));
217 struct sigaction act;
218 memset(&act, 0,
sizeof(act));
221 Fatal(
"sigaction: %s", strerror(errno));
223 Fatal(
"sigaction: %s", strerror(errno));
225 Fatal(
"sigaction: %s", strerror(errno));
232 Fatal(
"sigaction: %s", strerror(errno));
234 Fatal(
"sigaction: %s", strerror(errno));
236 Fatal(
"sigaction: %s", strerror(errno));
237 if (sigprocmask(SIG_SETMASK, &
old_mask_, 0) < 0)
238 Fatal(
"sigprocmask: %s", strerror(errno));
243 if (!subprocess->
Start(
this, command)) {
256 for (vector<Subprocess*>::iterator i =
running_.begin();
261 pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
267 int ret = ppoll(&fds.front(), nfds, NULL, &
old_mask_);
269 if (errno != EINTR) {
270 perror(
"ninja: ppoll");
281 for (vector<Subprocess*>::iterator i =
running_.begin();
286 assert(fd == fds[cur_nfd].fd);
287 if (fds[cur_nfd++].revents) {
301 #else // !defined(USE_PPOLL) 307 for (vector<Subprocess*>::iterator i =
running_.begin();
318 int ret = pselect(nfds, &
set, 0, 0, 0, &
old_mask_);
320 if (errno != EINTR) {
321 perror(
"ninja: pselect");
331 for (vector<Subprocess*>::iterator i =
running_.begin();
334 if (fd >= 0 && FD_ISSET(fd, &
set)) {
347 #endif // !defined(USE_PPOLL) 358 for (vector<Subprocess*>::iterator i =
running_.begin();
362 if (!(*i)->use_console_)
364 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_
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...
bool Start(struct SubprocessSet *set, const std::string &command)
struct sigaction old_int_act_
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)
void Fatal(const char *msg,...)
Log a fatal message and exit.
static void HandlePendingInterruption()
const std::string & GetOutput() const
std::vector< Subprocess * > running_
struct sigaction old_term_act_