diff options
Diffstat (limited to 'src/subprocess.cc')
-rw-r--r-- | src/subprocess.cc | 300 |
1 files changed, 0 insertions, 300 deletions
diff --git a/src/subprocess.cc b/src/subprocess.cc deleted file mode 100644 index 1c47fd1..0000000 --- a/src/subprocess.cc +++ /dev/null @@ -1,300 +0,0 @@ -// 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. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include "subprocess.h" - -#include <algorithm> -#include <map> -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <sys/wait.h> - -// Older versions of glibc (like 2.4) won't find this in <poll.h>. glibc -// 2.4 keeps it in <asm-generic/poll.h>, though attempting to include that -// will redefine the pollfd structure. -#ifndef POLLRDHUP -#define POLLRDHUP 0x2000 -#endif - -#include "util.h" - -Subprocess::Subprocess() : fd_(-1), pid_(-1) { -} -Subprocess::~Subprocess() { - if (fd_ >= 0) - close(fd_); - // Reap child if forgotten. - if (pid_ != -1) - Finish(); -} - -bool Subprocess::Start(SubprocessSet* set, const string& command) { - int output_pipe[2]; - if (pipe(output_pipe) < 0) - Fatal("pipe: %s", strerror(errno)); - fd_ = output_pipe[0]; -#if !defined(linux) - // On linux we use ppoll in DoWork(); elsewhere we use pselect and so must - // avoid overly-large FDs. - if (fd_ >= static_cast<int>(FD_SETSIZE)) - Fatal("pipe: %s", strerror(EMFILE)); -#endif // !linux - SetCloseOnExec(fd_); - - pid_ = fork(); - if (pid_ < 0) - Fatal("fork: %s", strerror(errno)); - - if (pid_ == 0) { - close(output_pipe[0]); - - // Track which fd we use to report errors on. - int error_pipe = output_pipe[1]; - do { - if (setpgid(0, 0) < 0) - break; - - if (sigaction(SIGINT, &set->old_act_, 0) < 0) - break; - if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0) - break; - - // Open /dev/null over stdin. - int devnull = open("/dev/null", O_WRONLY); - if (devnull < 0) - break; - if (dup2(devnull, 0) < 0) - break; - close(devnull); - - if (dup2(output_pipe[1], 1) < 0 || - dup2(output_pipe[1], 2) < 0) - break; - - // Now can use stderr for errors. - error_pipe = 2; - close(output_pipe[1]); - - execl("/bin/sh", "/bin/sh", "-c", command.c_str(), (char *) NULL); - } while (false); - - // If we get here, something went wrong; the execl should have - // replaced us. - char* err = strerror(errno); - if (write(error_pipe, err, strlen(err)) < 0) { - // If the write fails, there's nothing we can do. - // But this block seems necessary to silence the warning. - } - _exit(1); - } - - close(output_pipe[1]); - return true; -} - -void Subprocess::OnPipeReady() { - char buf[4 << 10]; - ssize_t len = read(fd_, buf, sizeof(buf)); - if (len > 0) { - buf_.append(buf, len); - } else { - if (len < 0) - Fatal("read: %s", strerror(errno)); - close(fd_); - fd_ = -1; - } -} - -ExitStatus Subprocess::Finish() { - assert(pid_ != -1); - int status; - if (waitpid(pid_, &status, 0) < 0) - Fatal("waitpid(%d): %s", pid_, strerror(errno)); - pid_ = -1; - - if (WIFEXITED(status)) { - int exit = WEXITSTATUS(status); - if (exit == 0) - return ExitSuccess; - } else if (WIFSIGNALED(status)) { - if (WTERMSIG(status) == SIGINT) - return ExitInterrupted; - } - return ExitFailure; -} - -bool Subprocess::Done() const { - return fd_ == -1; -} - -const string& Subprocess::GetOutput() const { - return buf_; -} - -bool SubprocessSet::interrupted_; - -void SubprocessSet::SetInterruptedFlag(int signum) { - (void) signum; - interrupted_ = true; -} - -SubprocessSet::SubprocessSet() { - interrupted_ = false; - - sigset_t set; - sigemptyset(&set); - sigaddset(&set, SIGINT); - if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0) - Fatal("sigprocmask: %s", strerror(errno)); - - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_handler = SetInterruptedFlag; - if (sigaction(SIGINT, &act, &old_act_) < 0) - Fatal("sigaction: %s", strerror(errno)); -} - -SubprocessSet::~SubprocessSet() { - Clear(); - - if (sigaction(SIGINT, &old_act_, 0) < 0) - Fatal("sigaction: %s", strerror(errno)); - if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0) - Fatal("sigprocmask: %s", strerror(errno)); -} - -Subprocess *SubprocessSet::Add(const string& command) { - Subprocess *subprocess = new Subprocess; - if (!subprocess->Start(this, command)) { - delete subprocess; - return 0; - } - running_.push_back(subprocess); - return subprocess; -} - -#ifdef linux -bool SubprocessSet::DoWork() { - vector<pollfd> fds; - nfds_t nfds = 0; - - for (vector<Subprocess*>::iterator i = running_.begin(); - i != running_.end(); ++i) { - int fd = (*i)->fd_; - if (fd < 0) - continue; - pollfd pfd = { fd, POLLIN | POLLPRI | POLLRDHUP, 0 }; - fds.push_back(pfd); - ++nfds; - } - - int ret = ppoll(&fds.front(), 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 // linux -bool SubprocessSet::DoWork() { - fd_set set; - int nfds = 0; - FD_ZERO(&set); - - for (vector<Subprocess*>::iterator i = running_.begin(); - i != running_.end(); ++i) { - int fd = (*i)->fd_; - if (fd >= 0) { - FD_SET(fd, &set); - if (nfds < fd+1) - nfds = fd+1; - } - } - - int ret = pselect(nfds, &set, 0, 0, 0, &old_mask_); - if (ret == -1) { - if (errno != EINTR) { - perror("ninja: pselect"); - return false; - } - bool interrupted = interrupted_; - interrupted_ = false; - return interrupted; - } - - for (vector<Subprocess*>::iterator i = running_.begin(); - i != running_.end(); ) { - int fd = (*i)->fd_; - if (fd >= 0 && FD_ISSET(fd, &set)) { - (*i)->OnPipeReady(); - if ((*i)->Done()) { - finished_.push(*i); - i = running_.erase(i); - continue; - } - } - ++i; - } - - return false; -} -#endif // linux - -Subprocess* SubprocessSet::NextFinished() { - if (finished_.empty()) - return NULL; - Subprocess* subproc = finished_.front(); - finished_.pop(); - return subproc; -} - -void SubprocessSet::Clear() { - for (vector<Subprocess*>::iterator i = running_.begin(); - i != running_.end(); ++i) - kill(-(*i)->pid_, SIGINT); - for (vector<Subprocess*>::iterator i = running_.begin(); - i != running_.end(); ++i) - delete *i; - running_.clear(); -} |