229 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			229 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| // 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);
 | |
|     }
 | |
|     /** 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 >
 | |
|     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 >
 | |
|     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 >
 | |
|     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 >
 | |
|     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);
 | |
|     }
 | |
| 
 | |
|     ///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
 | |
| 
 |