summaryrefslogtreecommitdiffstats
path: root/src/subprocess.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/subprocess.cc')
-rw-r--r--src/subprocess.cc60
1 files changed, 56 insertions, 4 deletions
diff --git a/src/subprocess.cc b/src/subprocess.cc
index d4a7d03..3de574b 100644
--- a/src/subprocess.cc
+++ b/src/subprocess.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 Google Inc. All Rights Reserved.
+// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -42,10 +42,12 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
if (pipe(output_pipe) < 0)
Fatal("pipe: %s", strerror(errno));
fd_ = output_pipe[0];
- // fd_ may be a member of the pselect set in SubprocessSet::DoWork. Check
- // that it falls below the system limit.
+#if !defined(OS_LINUX)
+ // On linux we use ppoll in DoWork(); elsewhere we use pselect and so must
+ // avoid overly-large FDs.
if (fd_ >= FD_SETSIZE)
Fatal("pipe: %s", strerror(EMFILE));
+#endif // !OS_LINUX
SetCloseOnExec(fd_);
pid_ = fork();
@@ -180,6 +182,55 @@ Subprocess *SubprocessSet::Add(const string &command) {
return subprocess;
}
+#ifdef OS_LINUX
+bool SubprocessSet::DoWork() {
+ struct pollfd* fds = new pollfd[running_.size()](); // XXX: scoped_array?
+ memset(fds, 0, running_.size() * sizeof(struct pollfd));
+ nfds_t nfds = 0;
+
+ for (vector<Subprocess*>::iterator i = running_.begin();
+ i != running_.end(); ++i) {
+ int fd = (*i)->fd_;
+ if (fd < 0)
+ continue;
+ fds[nfds].fd = fd;
+ fds[nfds].events = POLLIN | POLLPRI | POLLRDHUP;
+ ++nfds;
+ }
+
+ int ret = ppoll(fds, nfds, NULL, &old_mask_);
+ if (ret == -1) {
+ if (errno != EINTR) {
+ perror("ninja: ppoll");
+ return false;
+ }
+ bool interrupted = interrupted_;
+ interrupted_ = false;
+ return interrupted;
+ }
+
+ nfds_t cur_nfd = 0;
+ for (vector<Subprocess*>::iterator i = running_.begin();
+ i != running_.end(); ) {
+ int fd = (*i)->fd_;
+ if (fd < 0)
+ continue;
+ assert(fd == fds[cur_nfd].fd);
+ if (fds[cur_nfd++].revents) {
+ (*i)->OnPipeReady();
+ if ((*i)->Done()) {
+ finished_.push(*i);
+ i = running_.erase(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+
+ return false;
+}
+
+#else // OS_LINUX
bool SubprocessSet::DoWork() {
fd_set set;
int nfds = 0;
@@ -213,7 +264,7 @@ bool SubprocessSet::DoWork() {
(*i)->OnPipeReady();
if ((*i)->Done()) {
finished_.push(*i);
- running_.erase(i);
+ i = running_.erase(i);
continue;
}
}
@@ -222,6 +273,7 @@ bool SubprocessSet::DoWork() {
return false;
}
+#endif // OS_LINUX
Subprocess* SubprocessSet::NextFinished() {
if (finished_.empty())