summaryrefslogtreecommitdiff
path: root/boost/process/group.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/process/group.hpp')
-rw-r--r--boost/process/group.hpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/boost/process/group.hpp b/boost/process/group.hpp
new file mode 100644
index 0000000000..b46f064475
--- /dev/null
+++ b/boost/process/group.hpp
@@ -0,0 +1,228 @@
+// 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
+