229 lines
6.6 KiB
C++
229 lines
6.6 KiB
C++
|
// 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
|
||
|
|