From f4b8c7510029f3f5898c2fb4a9c04fb2c6ecaeb2 Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Fri, 27 Jul 2012 12:24:40 -0700 Subject: rename subprocess.cc to reflex its posixness --- bootstrap.py | 2 +- configure.py | 2 +- src/subprocess-posix.cc | 300 ++++++++++++++++++++++++++++++++++++++++++++++++ src/subprocess.cc | 300 ------------------------------------------------ 4 files changed, 302 insertions(+), 302 deletions(-) create mode 100644 src/subprocess-posix.cc delete mode 100644 src/subprocess.cc diff --git a/bootstrap.py b/bootstrap.py index 33acc5d..ab03cf8 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -61,7 +61,7 @@ for src in glob.glob('src/*.cc'): continue if sys.platform.startswith('win32'): - if filename == 'subprocess.cc': + if src.endswith('-posix.cc'): continue else: if src.endswith('-win32.cc'): diff --git a/configure.py b/configure.py index 41b3cf7..95f88b1 100755 --- a/configure.py +++ b/configure.py @@ -249,7 +249,7 @@ if platform in ('mingw', 'windows'): objs += cxx('minidump-win32') objs += cc('getopt') else: - objs += cxx('subprocess') + objs += cxx('subprocess-posix') if platform == 'windows': ninja_lib = n.build(built('ninja.lib'), 'ar', objs) else: diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc new file mode 100644 index 0000000..1c47fd1 --- /dev/null +++ b/src/subprocess-posix.cc @@ -0,0 +1,300 @@ +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Older versions of glibc (like 2.4) won't find this in . glibc +// 2.4 keeps it in , 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(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 fds; + nfds_t nfds = 0; + + for (vector::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::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::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::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::iterator i = running_.begin(); + i != running_.end(); ++i) + kill(-(*i)->pid_, SIGINT); + for (vector::iterator i = running_.begin(); + i != running_.end(); ++i) + delete *i; + running_.clear(); +} 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Older versions of glibc (like 2.4) won't find this in . glibc -// 2.4 keeps it in , 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(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 fds; - nfds_t nfds = 0; - - for (vector::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::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::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::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::iterator i = running_.begin(); - i != running_.end(); ++i) - kill(-(*i)->pid_, SIGINT); - for (vector::iterator i = running_.begin(); - i != running_.end(); ++i) - delete *i; - running_.clear(); -} -- cgit v0.12