diff options
Diffstat (limited to 'boost/process/detail/child_decl.hpp')
-rw-r--r-- | boost/process/detail/child_decl.hpp | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/boost/process/detail/child_decl.hpp b/boost/process/detail/child_decl.hpp new file mode 100644 index 0000000000..3483f7c4b8 --- /dev/null +++ b/boost/process/detail/child_decl.hpp @@ -0,0 +1,243 @@ +// Copyright (c) 2006, 2007 Julio M. Merino Vidal +// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling +// Copyright (c) 2009 Boris Schaeling +// Copyright (c) 2010 Felipe Tanus, Boris Schaeling +// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling +// Copyright (c) 2016 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/** + * \file boost/process/child.hpp + * + * Defines a child process class. + */ + +#ifndef BOOST_PROCESS_CHILD_DECL_HPP +#define BOOST_PROCESS_CHILD_DECL_HPP + +#include <boost/process/detail/config.hpp> +#include <chrono> +#include <memory> + +#include <boost/none.hpp> +#include <atomic> + +#if defined(BOOST_POSIX_API) +#include <boost/process/detail/posix/child_handle.hpp> +#include <boost/process/detail/posix/terminate.hpp> +#include <boost/process/detail/posix/wait_for_exit.hpp> +#include <boost/process/detail/posix/is_running.hpp> +#elif defined(BOOST_WINDOWS_API) +#include <boost/process/detail/windows/child_handle.hpp> +#include <boost/process/detail/windows/terminate.hpp> +#include <boost/process/detail/windows/wait_for_exit.hpp> +#include <boost/process/detail/windows/is_running.hpp> + +#endif +namespace boost { + +namespace process { + +using ::boost::process::detail::api::pid_t; + +class child +{ + ::boost::process::detail::api::child_handle _child_handle; + std::shared_ptr<std::atomic<int>> _exit_status = std::make_shared<std::atomic<int>>(::boost::process::detail::api::still_active); + bool _attached = true; + bool _terminated = false; + + bool _exited() + { + return _terminated || !::boost::process::detail::api::is_running(_exit_status->load()); + }; +public: + typedef ::boost::process::detail::api::child_handle child_handle; + typedef child_handle::process_handle_t native_handle_t; + explicit child(child_handle &&ch, std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} + explicit child(child_handle &&ch, const std::shared_ptr<std::atomic<int>> &ptr) : _child_handle(std::move(ch)), _exit_status(ptr) {} + explicit child(child_handle &&ch) : _child_handle(std::move(ch)) {} + + explicit child(pid_t & pid) : _child_handle(pid), _attached(false) {}; + child(const child&) = delete; + child(child && lhs) noexcept + : _child_handle(std::move(lhs._child_handle)), + _exit_status(std::move(lhs._exit_status)), + _attached (lhs._attached) + { + lhs._attached = false; + } + + template<typename ...Args> + explicit child(Args&&...args); + child() {} + child& operator=(const child&) = delete; + child& operator=(child && lhs) + { + _child_handle= std::move(lhs._child_handle); + _exit_status = std::move(lhs._exit_status); + _attached = lhs._attached; + lhs._attached = false; + return *this; + }; + + void detach() {_attached = false; } + void join() {wait();} + bool joinable() { return _attached;} + + ~child() + { + std::error_code ec; + if (_attached && !_exited() && running(ec)) + terminate(ec); + } + native_handle_t native_handle() const { return _child_handle.process_handle(); } + + + int exit_code() const {return ::boost::process::detail::api::eval_exit_status(_exit_status->load());} + pid_t id() const {return _child_handle.id(); } + + bool running() + { + if (valid() && !_exited()) + { + int code; + auto res = boost::process::detail::api::is_running(_child_handle, code); + if (!res && !_exited()) + _exit_status->store(code); + + return res; + } + return false; + } + + void terminate() + { + if (valid() && running()) + boost::process::detail::api::terminate(_child_handle); + + _terminated = true; + } + + void wait() + { + if (!_exited() && valid()) + { + int exit_code = 0; + boost::process::detail::api::wait(_child_handle, exit_code); + _exit_status->store(exit_code); + } + } + + template< class Rep, class Period > + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time) + { + if (!_exited()) + { + int exit_code = 0; + auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time); + if (!b) + return false; + _exit_status->store(exit_code); + } + return true; + } + + template< class Clock, class Duration > + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) + { + if (!_exited()) + { + int exit_code = 0; + auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time); + if (!b) + return false; + _exit_status->store(exit_code); + } + return true; + } + + bool running(std::error_code & ec) noexcept + { + if (valid() && !_exited()) + { + int code; + auto res = boost::process::detail::api::is_running(_child_handle, code, ec); + if (!res && !_exited()) + _exit_status->store(code); + + return res; + } + return false; + } + + void terminate(std::error_code & ec) noexcept + { + if (valid() && running(ec)) + boost::process::detail::api::terminate(_child_handle, ec); + + _terminated = true; + } + + void wait(std::error_code & ec) noexcept + { + if (!_exited() && valid()) + { + int exit_code = 0; + boost::process::detail::api::wait(_child_handle, exit_code, ec); + _exit_status->store(exit_code); + } + } + + template< class Rep, class Period > + bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept + { + if (!_exited()) + { + int exit_code = 0; + auto b = boost::process::detail::api::wait_for(_child_handle, exit_code, rel_time, ec); + if (!b) + return false; + _exit_status->store(exit_code); + } + return true; + } + + template< class Clock, class Duration > + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept + { + if (!_exited()) + { + int exit_code = 0; + auto b = boost::process::detail::api::wait_until(_child_handle, exit_code, timeout_time, ec); + if (!b) + return false; + _exit_status->store(exit_code); + } + return true; + } + + + bool valid() const + { + return _child_handle.valid(); + } + operator bool() const {return valid();} + + bool in_group() const + { + return _child_handle.in_group(); + } + bool in_group(std::error_code &ec) const noexcept + { + return _child_handle.in_group(ec); + } +}; + + + +}} +#endif + |