1 // Copyright (c) 2016 Klemens D. Morgenstern
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)
6 #ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
7 #define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_
9 #include <boost/process/detail/windows/handler.hpp>
10 #include <boost/winapi/jobs.hpp>
11 #include <boost/process/detail/windows/child_handle.hpp>
12 #include <boost/process/detail/windows/job_workaround.hpp>
13 #include <system_error>
15 namespace boost { namespace process { namespace detail { namespace windows {
17 inline bool break_away_enabled(::boost::winapi::HANDLE_ h)
19 workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
21 if (!workaround::query_information_job_object(
23 workaround::JobObjectExtendedLimitInformation_,
24 static_cast<void*>(&info),
27 throw_last_error("QueryInformationJobObject() failed");
29 return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0;
32 inline void enable_break_away(::boost::winapi::HANDLE_ h)
34 workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
36 if (!workaround::query_information_job_object(
38 workaround::JobObjectExtendedLimitInformation_,
39 static_cast<void*>(&info),
42 throw_last_error("QueryInformationJobObject() failed");
44 if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
47 info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
49 if (!workaround::set_information_job_object(
51 workaround::JobObjectExtendedLimitInformation_,
52 static_cast<void*>(&info),
54 throw_last_error("SetInformationJobObject() failed");
57 inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec)
59 workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info;
62 if (!workaround::query_information_job_object(
64 workaround::JobObjectExtendedLimitInformation_,
65 static_cast<void*>(&info),
69 ec = get_last_error();
73 if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0)
76 info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_;
78 if (!workaround::set_information_job_object(
80 workaround::JobObjectExtendedLimitInformation_,
81 static_cast<void*>(&info),
84 ec = get_last_error();
89 inline void associate_completion_port(::boost::winapi::HANDLE_ job,
90 ::boost::winapi::HANDLE_ io_port)
92 workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port;
93 port.CompletionKey = job;
94 port.CompletionPort = io_port;
96 if (!workaround::set_information_job_object(
98 workaround::JobObjectAssociateCompletionPortInformation_,
99 static_cast<void*>(&port),
101 throw_last_error("SetInformationJobObject() failed");
106 ::boost::winapi::HANDLE_ _job_object;
107 ::boost::winapi::HANDLE_ _io_port;
109 typedef ::boost::winapi::HANDLE_ handle_t;
110 handle_t handle() const { return _job_object; }
112 explicit group_handle(handle_t h) :
114 _io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1))
116 enable_break_away(_job_object);
117 associate_completion_port(_job_object, _io_port);
121 group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr))
127 ::boost::winapi::CloseHandle(_job_object);
128 ::boost::winapi::CloseHandle(_io_port);
130 group_handle(const group_handle & c) = delete;
131 group_handle(group_handle && c) : _job_object(c._job_object),
134 c._job_object = ::boost::winapi::invalid_handle_value;
135 c._io_port = ::boost::winapi::invalid_handle_value;
137 group_handle &operator=(const group_handle & c) = delete;
138 group_handle &operator=(group_handle && c)
140 ::boost::winapi::CloseHandle(_io_port);
141 _io_port = c._io_port;
142 c._io_port = ::boost::winapi::invalid_handle_value;
144 ::boost::winapi::CloseHandle(_job_object);
145 _job_object = c._job_object;
146 c._job_object = ::boost::winapi::invalid_handle_value;
150 void add(handle_t proc)
152 if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
155 void add(handle_t proc, std::error_code & ec) noexcept
157 if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc))
158 ec = get_last_error();
161 bool has(handle_t proc)
163 ::boost::winapi::BOOL_ is;
164 if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
169 bool has(handle_t proc, std::error_code & ec) noexcept
171 ::boost::winapi::BOOL_ is;
172 if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is))
173 ec = get_last_error();
179 return _job_object != nullptr;
184 inline void terminate(const group_handle &p)
186 if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
187 boost::process::detail::throw_last_error("TerminateJobObject() failed");
190 inline void terminate(const group_handle &p, std::error_code &ec) noexcept
192 if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
193 ec = boost::process::detail::get_last_error();
198 inline bool in_group()
200 ::boost::winapi::BOOL_ res;
201 if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res))
202 throw_last_error("IsProcessInJob failed");
212 #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */