Ninja
|
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 }