123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- // 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/group.hpp
- *
- * Defines a group process class.
- * For additional information see the platform specific implementations:
- *
- * - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx)
- * - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html)
- *
- */
- #ifndef BOOST_PROCESS_GROUP_HPP
- #define BOOST_PROCESS_GROUP_HPP
- #include <boost/process/detail/config.hpp>
- #include <boost/process/child.hpp>
- #include <chrono>
- #include <memory>
- #include <boost/none.hpp>
- #include <atomic>
- #if defined(BOOST_POSIX_API)
- #include <boost/process/detail/posix/group_handle.hpp>
- #include <boost/process/detail/posix/group_ref.hpp>
- #include <boost/process/detail/posix/wait_group.hpp>
- #elif defined(BOOST_WINDOWS_API)
- #include <boost/process/detail/windows/group_handle.hpp>
- #include <boost/process/detail/windows/group_ref.hpp>
- #include <boost/process/detail/windows/wait_group.hpp>
- #endif
- namespace boost {
- namespace process {
- namespace detail {
- struct group_builder;
- }
- /**
- * Represents a process group.
- *
- * Groups are movable but non-copyable. The destructor
- * automatically closes handles to the group process.
- *
- * The group will have the same interface as std::thread.
- *
- * \note If the destructor is called without a previous detach or wait, the group will be terminated.
- *
- * \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined.
- *
- * \attention Waiting for groups is currently broken on windows and will most likely result in a dead-lock.
- */
- class group
- {
- ::boost::process::detail::api::group_handle _group_handle;
- bool _attached = true;
- public:
- typedef ::boost::process::detail::api::group_handle group_handle;
- ///Native representation of the handle.
- typedef group_handle::handle_t native_handle_t;
- explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {}
- ///Construct the group from a native_handle
- explicit group(native_handle_t & handle) : _group_handle(handle) {};
- group(const group&) = delete;
- ///Move constructor
- group(group && lhs)
- : _group_handle(std::move(lhs._group_handle)),
- _attached (lhs._attached)
- {
- lhs._attached = false;
- }
- ///Default constructor
- group() = default;
- group& operator=(const group&) = delete;
- ///Move assign
- group& operator=(group && lhs)
- {
- _group_handle= std::move(lhs._group_handle);
- _attached = lhs._attached;
- return *this;
- };
- ///Detach the group
- void detach() {_attached = false; }
- /** Join the child. This just calls wait, but that way the naming is similar to std::thread */
- void join() {wait();}
- /** Check if the child is joinable. */
- bool joinable() {return _attached;}
- /** Destructor
- *
- * \note If the destructor is called without a previous detach or wait, the group will be terminated.
- *
- */
- ~group()
- {
- std::error_code ec;
- if ( _attached && valid())
- terminate(ec);
- }
- ///Obtain the native handle of the group.
- native_handle_t native_handle() const { return _group_handle.handle(); }
- ///Wait for the process group to exit.
- void wait()
- {
- boost::process::detail::api::wait(_group_handle);
- }
- ///\overload void wait()
- void wait(std::error_code & ec) noexcept
- {
- boost::process::detail::api::wait(_group_handle, ec);
- }
- #if !defined(BOOST_PROCESS_NO_DEPRECATED)
- /** Wait for the process group to exit for period of time.
- * \return True if all child processes exited while waiting.*/
- template< class Rep, class Period >
- BOOST_DEPRECATED("wait_for is unreliable")
- bool wait_for (const std::chrono::duration<Rep, Period>& rel_time)
- {
- return boost::process::detail::api::wait_for(_group_handle, rel_time);
- }
- /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
- template< class Rep, class Period >
- BOOST_DEPRECATED("wait_for is unreliable")
- bool wait_for (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
- {
- return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
- }
- /** Wait for the process group to exit until a point in time.
- * \return True if all child processes exited while waiting.*/
- template< class Clock, class Duration >
- BOOST_DEPRECATED("wait_until is unreliable")
- bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
- {
- return boost::process::detail::api::wait_until(_group_handle, timeout_time);
- }
- /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
- template< class Clock, class Duration >
- BOOST_DEPRECATED("wait_until is unreliable")
- bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
- {
- return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
- }
- #endif
- ///Check if the group has a valid handle.
- bool valid() const
- {
- return _group_handle.valid();
- }
- ///Convenience to call valid.
- explicit operator bool() const {return valid();}
- ///Terminate the process group, i.e. all processes in the group
- void terminate()
- {
- ::boost::process::detail::api::terminate(_group_handle);
- }
- ///\overload void terminate()
- void terminate(std::error_code & ec) noexcept
- {
- ::boost::process::detail::api::terminate(_group_handle, ec);
- }
- ///Assign a child process to the group
- void add(const child &c)
- {
- _group_handle.add(c.native_handle());
- }
- ///\overload void assign(const child & c)
- void add(const child &c, std::error_code & ec) noexcept
- {
- _group_handle.add(c.native_handle(), ec);
- }
- ///Check if the child process is in the group
- bool has(const child &c)
- {
- return _group_handle.has(c.native_handle());
- }
- ///\overload bool has(const child &)
- bool has(const child &c, std::error_code & ec) noexcept
- {
- return _group_handle.has(c.native_handle(), ec);
- }
- friend struct detail::group_builder;
- };
- namespace detail
- {
- struct group_tag;
- struct group_builder
- {
- group * group_p;
- void operator()(group & grp) {this->group_p = &grp;};
- typedef api::group_ref result_type;
- api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);};
- };
- template<>
- struct initializer_tag<group>
- {
- typedef group_tag type;
- };
- template<>
- struct initializer_builder<group_tag>
- {
- typedef group_builder type;
- };
- }
- }}
- #endif
|