123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- // 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),
- _terminated (lhs._terminated)
- {
- lhs._attached = false;
- }
- template<typename ...Args>
- explicit child(Args&&...args);
- child() { } // Must be kept non defaulted for MSVC 14.1 & 14.2 #113
- 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;
- _terminated = lhs._terminated;
- 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(); }
- int native_exit_code() const {return _exit_status->load();}
- bool running()
- {
- std::error_code ec;
- bool b = running(ec);
- boost::process::detail::throw_error(ec, "running error");
- return b;
- }
- void terminate()
- {
- std::error_code ec;
- terminate(ec);
- boost::process::detail::throw_error(ec, "terminate error");
- }
- void wait()
- {
- std::error_code ec;
- wait(ec);
- boost::process::detail::throw_error(ec, "wait error");
- }
- template< class Rep, class Period >
- bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
- {
- std::error_code ec;
- bool b = wait_for(rel_time, ec);
- boost::process::detail::throw_error(ec, "wait_for error");
- return b;
- }
- template< class Clock, class Duration >
- bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
- {
- std::error_code ec;
- bool b = wait_until(timeout_time, ec);
- boost::process::detail::throw_error(ec, "wait_until error");
- return b;
- }
- bool running(std::error_code & ec) noexcept
- {
- ec.clear();
- if (valid() && !_exited() && !ec)
- {
- int exit_code = 0;
- auto res = boost::process::detail::api::is_running(_child_handle, exit_code, ec);
- if (!ec && !res && !_exited())
- _exit_status->store(exit_code);
- return res;
- }
- return false;
- }
- void terminate(std::error_code & ec) noexcept
- {
- if (valid() && running(ec) && !ec)
- boost::process::detail::api::terminate(_child_handle, ec);
- if (!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);
- if (!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
- {
- return wait_until(std::chrono::steady_clock::now() + rel_time, ec);
- }
- 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 || ec)
- 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
|