X-Git-Url: https://gerrit.akraino.org/r/gitweb?a=blobdiff_plain;f=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fexternal%2Fprocess-cpp-minimal%2Fsrc%2Fcore%2Fposix%2Fchild_process.cpp;fp=src%2Ftype3_AndroidCloud%2Fanbox-master%2Fexternal%2Fprocess-cpp-minimal%2Fsrc%2Fcore%2Fposix%2Fchild_process.cpp;h=ad1657174e6f84baeb1f946c40636ff042d17768;hb=e26c1ec581be598521517829adba8c8dd23a768f;hp=0000000000000000000000000000000000000000;hpb=6699c1aea74eeb0eb400e6299079f0c7576f716f;p=iec.git diff --git a/src/type3_AndroidCloud/anbox-master/external/process-cpp-minimal/src/core/posix/child_process.cpp b/src/type3_AndroidCloud/anbox-master/external/process-cpp-minimal/src/core/posix/child_process.cpp new file mode 100644 index 0000000..ad16571 --- /dev/null +++ b/src/type3_AndroidCloud/anbox-master/external/process-cpp-minimal/src/core/posix/child_process.cpp @@ -0,0 +1,422 @@ +/* + * Copyright © 2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + * + * Authored by: Thomas Voß + */ + +#include + +#ifndef ANDROID +#include +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include + +#ifndef ANDROID +namespace io = boost::iostreams; +#endif + +namespace +{ + +struct DeathObserverImpl : public core::posix::ChildProcess::DeathObserver +{ + DeathObserverImpl(const std::shared_ptr& trap) + : on_sig_child_connection + { + trap->signal_raised().connect([this](core::posix::Signal signal) + { + switch (signal) + { + case core::posix::Signal::sig_chld: + on_sig_child(); + break; + default: + break; + } + }) + } + { + if (!trap->has(core::posix::Signal::sig_chld)) + throw std::logic_error( + "DeathObserver::DeathObserverImpl: Given SignalTrap" + " instance does not trap Signal::sig_chld."); + } + + bool add(const core::posix::ChildProcess& process) override + { + if (process.pid() == -1) + return false; + + std::lock_guard lg(guard); + + bool added = false; + auto new_process = std::make_pair(process.pid(), process); + std::tie(std::ignore, added) = children.insert(new_process); + + if (added) + { + // The process may have died between it's instantiation and it + // being added to the children map. Check that it's still alive. + int status{-1}; + if (::waitpid(process.pid(), &status, WNOHANG) != 0) // child no longer alive + { + // we missed the SIGCHLD signal so we must now manually + // inform our subscribers. + signals.child_died(new_process.second); + children.erase(new_process.first); + return false; + } + } + + return added; + } + + bool has(const core::posix::ChildProcess& process) const override + { + std::lock_guard lg(guard); + return children.count(process.pid()) > 0; + } + + const core::Signal& child_died() const override + { + return signals.child_died; + } + + void on_sig_child() override + { + pid_t pid{-1}; int status{-1}; + while (true) + { + pid = ::waitpid(0, &status, WNOHANG); + + if (pid == -1) + { + if (errno == ECHILD) + { + break; // No more children + } + continue; // Ignore stray SIGCHLD signals + } + else if (pid == 0) + { + break; // No more children + } + else + { + std::lock_guard lg(guard); + auto it = children.find(pid); + + if (it != children.end()) + { + if (WIFSIGNALED(status) || WIFEXITED(status)) + { + signals.child_died(it->second); + children.erase(it); + } + } + } + } + } + + mutable std::mutex guard; + std::unordered_map children; + core::ScopedConnection on_sig_child_connection; + struct + { + core::Signal child_died; + } signals; +}; +} + +std::unique_ptr +core::posix::ChildProcess::DeathObserver::create_once_with_signal_trap( + std::shared_ptr trap) +{ + static std::atomic has_been_created_once{false}; + + if (has_been_created_once.exchange(true)) + throw std::runtime_error + { + "DeathObserver::create_once_with_signal_trap: " + "Cannot create more than one instance." + }; + + try + { + std::unique_ptr result + { + new DeathObserverImpl{trap} + }; + + return result; + } catch(...) + { + // We make sure that a throwing c'tor does not impact our ability to + // retry creation of a DeathObserver instance. + has_been_created_once.store(false); + + std::rethrow_exception(std::current_exception()); + } + + assert(false && "We should never reach here."); + + // Silence the compiler. + return std::unique_ptr{}; +} + +namespace core +{ +namespace posix +{ +ChildProcess::Pipe ChildProcess::Pipe::invalid() +{ + static Pipe p; + static std::once_flag flag; + + std::call_once(flag, [&]() { p.close_read_fd(); p.close_write_fd(); }); + + return p; +} + +ChildProcess::Pipe::Pipe() +{ + int rc = ::pipe(fds); + + if (rc == -1) + throw std::system_error(errno, std::system_category()); +} + +ChildProcess::Pipe::Pipe(const ChildProcess::Pipe& rhs) : fds{-1, -1} +{ + if (rhs.fds[0] != -1) + fds[0] = ::dup(rhs.fds[0]); + + if (rhs.fds[1] != -1) + fds[1] = ::dup(rhs.fds[1]); +} + +ChildProcess::Pipe::~Pipe() +{ + if (fds[0] != -1) + ::close(fds[0]); + if (fds[1] != -1) + ::close(fds[1]); +} + +int ChildProcess::Pipe::read_fd() const +{ + return fds[0]; +} + +void ChildProcess::Pipe::close_read_fd() +{ + if (fds[0] != -1) + { + ::close(fds[0]); + fds[0] = -1; + } +} + +int ChildProcess::Pipe::write_fd() const +{ + return fds[1]; +} + +void ChildProcess::Pipe::close_write_fd() +{ + if (fds[1] != -1) + { + ::close(fds[1]); + fds[1] = -1; + } +} + +ChildProcess::Pipe& ChildProcess::Pipe::operator=(const ChildProcess::Pipe& rhs) +{ + if (fds[0] != -1) + ::close(fds[0]); + if (fds[1] != -1) + ::close(fds[1]); + + if (rhs.fds[0] != -1) + fds[0] = ::dup(rhs.fds[0]); + else + fds[0] = -1; + if (rhs.fds[1] != -1) + fds[1] = ::dup(rhs.fds[1]); + else + fds[1] = -1; + + return *this; +} + +struct ChildProcess::Private +{ + // stdin and stdout are always "relative" to the childprocess, i.e., we + // write to stdin of the child process and read from its stdout. + Private(pid_t pid, + const ChildProcess::Pipe& stderr, + const ChildProcess::Pipe& stdin, + const ChildProcess::Pipe& stdout) + : pipes{stderr, stdin, stdout}, +#ifndef ANDROID + serr(pipes.stderr.read_fd(), io::never_close_handle), + sin(pipes.stdin.write_fd(), io::never_close_handle), + sout(pipes.stdout.read_fd(), io::never_close_handle), + cerr(&serr), + cin(&sin), + cout(&sout), +#endif + original_parent_pid(::getpid()), + original_child_pid(pid) + { + } + + ~Private() + { + // Check if we are in the original parent process. + if (original_parent_pid == getpid() && !dont_kill_on_cleanup) + { + // If so, check if we are considering a valid pid here. + // If so, we kill the original child. + if (original_child_pid != -1) + ::kill(original_child_pid, SIGKILL); + } + } + + struct + { + ChildProcess::Pipe stdin; + ChildProcess::Pipe stdout; + ChildProcess::Pipe stderr; + } pipes; + +#ifndef ANDROID + io::stream_buffer serr; + io::stream_buffer sin; + io::stream_buffer sout; + std::istream cerr; + std::ostream cin; + std::istream cout; +#endif + + // We need to store the original parent pid as we might have been forked + // and with our automatic cleanup in place, it might happen that the d'tor + // is called from the child process. + pid_t original_parent_pid; + pid_t original_child_pid; + + bool dont_kill_on_cleanup = false; +}; + +ChildProcess ChildProcess::invalid() +{ + // We take the init process as child. + static const pid_t invalid_pid = 1; + return ChildProcess(invalid_pid, Pipe::invalid(), Pipe::invalid(), Pipe::invalid()); +} + +ChildProcess::ChildProcess(pid_t pid, + const ChildProcess::Pipe& stdin_pipe, + const ChildProcess::Pipe& stdout_pipe, + const ChildProcess::Pipe& stderr_pipe) + : Process(pid), + d(new Private{pid, stdin_pipe, stdout_pipe, stderr_pipe}) +{ +} + +ChildProcess::~ChildProcess() +{ +} + +wait::Result ChildProcess::wait_for(const wait::Flags& flags) +{ + int status = -1; + pid_t result_pid = ::waitpid(pid(), std::addressof(status), static_cast(flags)); + + if (result_pid == -1) + throw std::system_error(errno, std::system_category()); + + wait::Result result; + + if (result_pid == 0) + { + result.status = wait::Result::Status::no_state_change; + return result; + } + + if (WIFEXITED(status)) + { + result.status = wait::Result::Status::exited; + result.detail.if_exited.status = static_cast(WEXITSTATUS(status)); + } else if (WIFSIGNALED(status)) + { + result.status = wait::Result::Status::signaled; + result.detail.if_signaled.signal = static_cast(WTERMSIG(status)); + result.detail.if_signaled.core_dumped = WCOREDUMP(status); + } else if (WIFSTOPPED(status)) + { + result.status = wait::Result::Status::stopped; + result.detail.if_stopped.signal = static_cast(WSTOPSIG(status)); + } +#ifndef ANDROID + else if (WIFCONTINUED(status)) + { + result.status = wait::Result::Status::continued; + } +#endif + + return result; +} + +void ChildProcess::dont_kill_on_cleanup() +{ + d->dont_kill_on_cleanup = true; +} + +#ifndef ANDROID +std::istream& ChildProcess::cerr() +{ + return d->cerr; +} + +std::ostream& ChildProcess::cin() +{ + return d->cin; +} + +std::istream& ChildProcess::cout() +{ + return d->cout; +} +#endif +} +}