• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 /**
7  * \file boost/process/group.hpp
8  *
9  * Defines a group process class.
10  * For additional information see the platform specific implementations:
11  *
12  *   - [windows - job object](https://msdn.microsoft.com/en-us/library/windows/desktop/ms684161.aspx)
13  *   - [posix - process group](http://pubs.opengroup.org/onlinepubs/009695399/functions/setpgid.html)
14  *
15  */
16 
17 #ifndef BOOST_PROCESS_GROUP_HPP
18 #define BOOST_PROCESS_GROUP_HPP
19 
20 #include <boost/process/detail/config.hpp>
21 #include <boost/process/child.hpp>
22 #include <chrono>
23 #include <memory>
24 
25 #include <boost/none.hpp>
26 #include <atomic>
27 
28 
29 #if defined(BOOST_POSIX_API)
30 #include <boost/process/detail/posix/group_handle.hpp>
31 #include <boost/process/detail/posix/group_ref.hpp>
32 #include <boost/process/detail/posix/wait_group.hpp>
33 #elif defined(BOOST_WINDOWS_API)
34 #include <boost/process/detail/windows/group_handle.hpp>
35 #include <boost/process/detail/windows/group_ref.hpp>
36 #include <boost/process/detail/windows/wait_group.hpp>
37 #endif
38 
39 namespace boost {
40 
41 namespace process {
42 
43 namespace detail {
44     struct group_builder;
45 }
46 
47 /**
48  * Represents a process group.
49  *
50  * Groups are movable but non-copyable. The destructor
51  * automatically closes handles to the group process.
52  *
53  * The group will have the same interface as std::thread.
54  *
55  * \note If the destructor is called without a previous detach or wait, the group will be terminated.
56  *
57  * \attention If a default-constructed group is used before being used in a process launch, the behaviour is undefined.
58  *
59  * \attention Waiting for groups is currently broken on windows and will most likely result in a dead-lock.
60  */
61 class group
62 {
63     ::boost::process::detail::api::group_handle _group_handle;
64     bool _attached = true;
65 public:
66     typedef ::boost::process::detail::api::group_handle group_handle;
67     ///Native representation of the handle.
68     typedef group_handle::handle_t native_handle_t;
group(group_handle && ch)69     explicit group(group_handle &&ch) : _group_handle(std::move(ch)) {}
70     ///Construct the group from a native_handle
group(native_handle_t & handle)71     explicit group(native_handle_t & handle) : _group_handle(handle) {};
72     group(const group&) = delete;
73     ///Move constructor
group(group && lhs)74     group(group && lhs)
75         : _group_handle(std::move(lhs._group_handle)),
76           _attached (lhs._attached)
77     {
78         lhs._attached = false;
79     }
80     ///Default constructor
81     group() = default;
82     group& operator=(const group&) = delete;
83     ///Move assign
operator =(group && lhs)84     group& operator=(group && lhs)
85     {
86         _group_handle= std::move(lhs._group_handle);
87         _attached    = lhs._attached;
88 
89         return *this;
90     };
91 
92     ///Detach the group
detach()93     void detach() {_attached = false; }
94 
95     /** Join the child. This just calls wait, but that way the naming is similar to std::thread */
join()96     void join() {wait();}
97     /** Check if the child is joinable. */
joinable()98     bool joinable() {return _attached;}
99 
100     /** Destructor
101      *
102      * \note If the destructor is called without a previous detach or wait, the group will be terminated.
103      *
104      */
~group()105     ~group()
106     {
107         std::error_code ec;
108         if ( _attached && valid())
109             terminate(ec);
110     }
111 
112     ///Obtain the native handle of the group.
native_handle() const113     native_handle_t native_handle() const { return _group_handle.handle(); }
114 
115     ///Wait for the process group to exit.
wait()116     void wait()
117     {
118         boost::process::detail::api::wait(_group_handle);
119     }
120     ///\overload void wait()
wait(std::error_code & ec)121     void wait(std::error_code & ec) noexcept
122     {
123         boost::process::detail::api::wait(_group_handle, ec);
124     }
125     /** Wait for the process group to exit for period of time.
126       *  \return True if all child processes exited while waiting.*/
127     template< class Rep, class Period >
wait_for(const std::chrono::duration<Rep,Period> & rel_time)128     bool wait_for  (const std::chrono::duration<Rep, Period>& rel_time)
129     {
130         return boost::process::detail::api::wait_for(_group_handle, rel_time);
131     }
132 
133     /** \overload bool wait_for(const std::chrono::duration<Rep, Period>& timeout_time ) */
134     template< class Rep, class Period >
wait_for(const std::chrono::duration<Rep,Period> & rel_time,std::error_code & ec)135     bool wait_for  (const std::chrono::duration<Rep, Period>& rel_time, std::error_code & ec) noexcept
136     {
137         return boost::process::detail::api::wait_for(_group_handle, rel_time, ec);
138     }
139 
140     /** Wait for the process group to exit until a point in time.
141       *  \return True if all child processes exited while waiting.*/
142     template< class Clock, class Duration >
wait_until(const std::chrono::time_point<Clock,Duration> & timeout_time)143     bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time )
144     {
145         return boost::process::detail::api::wait_until(_group_handle, timeout_time);
146     }
147     /** \overload bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time ) */
148     template< class Clock, class Duration >
wait_until(const std::chrono::time_point<Clock,Duration> & timeout_time,std::error_code & ec)149     bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, std::error_code & ec) noexcept
150     {
151         return boost::process::detail::api::wait_until(_group_handle, timeout_time, ec);
152     }
153 
154     ///Check if the group has a valid handle.
valid() const155     bool valid() const
156     {
157         return _group_handle.valid();
158     }
159     ///Convenience to call valid.
operator bool() const160     explicit operator bool() const {return valid();}
161 
162     ///Terminate the process group, i.e. all processes in the group
terminate()163     void terminate()
164     {
165         ::boost::process::detail::api::terminate(_group_handle);
166     }
167     ///\overload void terminate()
terminate(std::error_code & ec)168     void terminate(std::error_code & ec) noexcept
169     {
170         ::boost::process::detail::api::terminate(_group_handle, ec);
171     }
172 
173     ///Assign a child process to the group
add(const child & c)174     void add(const child &c)
175     {
176         _group_handle.add(c.native_handle());
177     }
178     ///\overload void assign(const child & c)
add(const child & c,std::error_code & ec)179     void add(const child &c, std::error_code & ec) noexcept
180     {
181         _group_handle.add(c.native_handle(), ec);
182     }
183 
184     ///Check if the child process is in the group
has(const child & c)185     bool has(const child &c)
186     {
187         return _group_handle.has(c.native_handle());
188     }
189     ///\overload bool has(const child &)
has(const child & c,std::error_code & ec)190     bool has(const child &c, std::error_code & ec) noexcept
191     {
192         return _group_handle.has(c.native_handle(), ec);
193 
194     }
195 
196     friend struct detail::group_builder;
197 };
198 
199 namespace detail
200 {
201 
202 struct group_tag;
203 struct group_builder
204 {
205     group * group_p;
206 
operator ()boost::process::detail::group_builder207     void operator()(group & grp) {this->group_p = &grp;};
208 
209     typedef api::group_ref result_type;
get_initializerboost::process::detail::group_builder210     api::group_ref get_initializer() {return api::group_ref (group_p->_group_handle);};
211 };
212 
213 template<>
214 struct initializer_tag<group>
215 {
216     typedef group_tag type;
217 };
218 
219 template<>
220 struct initializer_builder<group_tag>
221 {
222     typedef group_builder type;
223 };
224 
225 }
226 }}
227 #endif
228 
229