Ninja
subprocess-posix.cc
Go to the documentation of this file.
00001 // Copyright 2012 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include "subprocess.h"
00016 
00017 #include <assert.h>
00018 #include <errno.h>
00019 #include <fcntl.h>
00020 #include <poll.h>
00021 #include <unistd.h>
00022 #include <stdio.h>
00023 #include <string.h>
00024 #include <sys/wait.h>
00025 
00026 #include "util.h"
00027 
00028 Subprocess::Subprocess() : fd_(-1), pid_(-1) {
00029 }
00030 Subprocess::~Subprocess() {
00031   if (fd_ >= 0)
00032     close(fd_);
00033   // Reap child if forgotten.
00034   if (pid_ != -1)
00035     Finish();
00036 }
00037 
00038 bool Subprocess::Start(SubprocessSet* set, const string& command) {
00039   int output_pipe[2];
00040   if (pipe(output_pipe) < 0)
00041     Fatal("pipe: %s", strerror(errno));
00042   fd_ = output_pipe[0];
00043 #if !defined(USE_PPOLL)
00044   // On Linux and OpenBSD, we use ppoll in DoWork(); elsewhere we use pselect
00045   // and so must avoid overly-large FDs.
00046   if (fd_ >= static_cast<int>(FD_SETSIZE))
00047     Fatal("pipe: %s", strerror(EMFILE));
00048 #endif  // !USE_PPOLL
00049   SetCloseOnExec(fd_);
00050 
00051   pid_ = fork();
00052   if (pid_ < 0)
00053     Fatal("fork: %s", strerror(errno));
00054 
00055   if (pid_ == 0) {
00056     close(output_pipe[0]);
00057 
00058     // Track which fd we use to report errors on.
00059     int error_pipe = output_pipe[1];
00060     do {
00061       if (setpgid(0, 0) < 0)
00062         break;
00063 
00064       if (sigaction(SIGINT, &set->old_act_, 0) < 0)
00065         break;
00066       if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0)
00067         break;
00068 
00069       // Open /dev/null over stdin.
00070       int devnull = open("/dev/null", O_RDONLY);
00071       if (devnull < 0)
00072         break;
00073       if (dup2(devnull, 0) < 0)
00074         break;
00075       close(devnull);
00076 
00077       if (dup2(output_pipe[1], 1) < 0 ||
00078           dup2(output_pipe[1], 2) < 0)
00079         break;
00080 
00081       // Now can use stderr for errors.
00082       error_pipe = 2;
00083       close(output_pipe[1]);
00084 
00085       execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL);
00086     } while (false);
00087 
00088     // If we get here, something went wrong; the execl should have
00089     // replaced us.
00090     char* err = strerror(errno);
00091     if (write(error_pipe, err, strlen(err)) < 0) {
00092       // If the write fails, there's nothing we can do.
00093       // But this block seems necessary to silence the warning.
00094     }
00095     _exit(1);
00096   }
00097 
00098   close(output_pipe[1]);
00099   return true;
00100 }
00101 
00102 void Subprocess::OnPipeReady() {
00103   char buf[4 << 10];
00104   ssize_t len = read(fd_, buf, sizeof(buf));
00105   if (len > 0) {
00106     buf_.append(buf, len);
00107   } else {
00108     if (len < 0)
00109       Fatal("read: %s", strerror(errno));
00110     close(fd_);
00111     fd_ = -1;
00112   }
00113 }
00114 
00115 ExitStatus Subprocess::Finish() {
00116   assert(pid_ != -1);
00117   int status;
00118   if (waitpid(pid_, &status, 0) < 0)
00119     Fatal("waitpid(%d): %s", pid_, strerror(errno));
00120   pid_ = -1;
00121 
00122   if (WIFEXITED(status)) {
00123     int exit = WEXITSTATUS(status);
00124     if (exit == 0)
00125       return ExitSuccess;
00126   } else if (WIFSIGNALED(status)) {
00127     if (WTERMSIG(status) == SIGINT)
00128       return ExitInterrupted;
00129   }
00130   return ExitFailure;
00131 }
00132 
00133 bool Subprocess::Done() const {
00134   return fd_ == -1;
00135 }
00136 
00137 const string& Subprocess::GetOutput() const {
00138   return buf_;
00139 }
00140 
00141 bool SubprocessSet::interrupted_;
00142 
00143 void SubprocessSet::SetInterruptedFlag(int signum) {
00144   (void) signum;
00145   interrupted_ = true;
00146 }
00147 
00148 SubprocessSet::SubprocessSet() {
00149   sigset_t set;
00150   sigemptyset(&set);
00151   sigaddset(&set, SIGINT);
00152   if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
00153     Fatal("sigprocmask: %s", strerror(errno));
00154 
00155   struct sigaction act;
00156   memset(&act, 0, sizeof(act));
00157   act.sa_handler = SetInterruptedFlag;
00158   if (sigaction(SIGINT, &act, &old_act_) < 0)
00159     Fatal("sigaction: %s", strerror(errno));
00160 }
00161 
00162 SubprocessSet::~SubprocessSet() {
00163   Clear();
00164 
00165   if (sigaction(SIGINT, &old_act_, 0) < 0)
00166     Fatal("sigaction: %s", strerror(errno));
00167   if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
00168     Fatal("sigprocmask: %s", strerror(errno));
00169 }
00170 
00171 Subprocess *SubprocessSet::Add(const string& command) {
00172   Subprocess *subprocess = new Subprocess;
00173   if (!subprocess->Start(this, command)) {
00174     delete subprocess;
00175     return 0;
00176   }
00177   running_.push_back(subprocess);
00178   return subprocess;
00179 }
00180 
00181 #ifdef USE_PPOLL
00182 bool SubprocessSet::DoWork() {
00183   vector<pollfd> fds;
00184   nfds_t nfds = 0;
00185 
00186   for (vector<Subprocess*>::iterator i = running_.begin();
00187        i != running_.end(); ++i) {
00188     int fd = (*i)->fd_;
00189     if (fd < 0)
00190       continue;
00191     pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
00192     fds.push_back(pfd);
00193     ++nfds;
00194   }
00195 
00196   interrupted_ = false;
00197   int ret = ppoll(&fds.front(), nfds, NULL, &old_mask_);
00198   if (ret == -1) {
00199     if (errno != EINTR) {
00200       perror("ninja: ppoll");
00201       return false;
00202     }
00203     return interrupted_;
00204   }
00205 
00206   nfds_t cur_nfd = 0;
00207   for (vector<Subprocess*>::iterator i = running_.begin();
00208        i != running_.end(); ) {
00209     int fd = (*i)->fd_;
00210     if (fd < 0)
00211       continue;
00212     assert(fd == fds[cur_nfd].fd);
00213     if (fds[cur_nfd++].revents) {
00214       (*i)->OnPipeReady();
00215       if ((*i)->Done()) {
00216         finished_.push(*i);
00217         i = running_.erase(i);
00218         continue;
00219       }
00220     }
00221     ++i;
00222   }
00223 
00224   return interrupted_;
00225 }
00226 
00227 #else  // linux || __OpenBSD__
00228 bool SubprocessSet::DoWork() {
00229   fd_set set;
00230   int nfds = 0;
00231   FD_ZERO(&set);
00232 
00233   for (vector<Subprocess*>::iterator i = running_.begin();
00234        i != running_.end(); ++i) {
00235     int fd = (*i)->fd_;
00236     if (fd >= 0) {
00237       FD_SET(fd, &set);
00238       if (nfds < fd+1)
00239         nfds = fd+1;
00240     }
00241   }
00242 
00243   interrupted_ = false;
00244   int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_);
00245   if (ret == -1) {
00246     if (errno != EINTR) {
00247       perror("ninja: pselect");
00248       return false;
00249     }
00250     return interrupted_;
00251   }
00252 
00253   for (vector<Subprocess*>::iterator i = running_.begin();
00254        i != running_.end(); ) {
00255     int fd = (*i)->fd_;
00256     if (fd >= 0 && FD_ISSET(fd, &set)) {
00257       (*i)->OnPipeReady();
00258       if ((*i)->Done()) {
00259         finished_.push(*i);
00260         i = running_.erase(i);
00261         continue;
00262       }
00263     }
00264     ++i;
00265   }
00266 
00267   return interrupted_;
00268 }
00269 #endif  // linux || __OpenBSD__
00270 
00271 Subprocess* SubprocessSet::NextFinished() {
00272   if (finished_.empty())
00273     return NULL;
00274   Subprocess* subproc = finished_.front();
00275   finished_.pop();
00276   return subproc;
00277 }
00278 
00279 void SubprocessSet::Clear() {
00280   for (vector<Subprocess*>::iterator i = running_.begin();
00281        i != running_.end(); ++i)
00282     kill(-(*i)->pid_, SIGINT);
00283   for (vector<Subprocess*>::iterator i = running_.begin();
00284        i != running_.end(); ++i)
00285     delete *i;
00286   running_.clear();
00287 }