]>
Commit | Line | Data |
---|---|---|
b32b8144 FG |
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 | #ifndef BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ | |
7 | #define BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ | |
8 | ||
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> | |
14 | ||
15 | namespace boost { namespace process { namespace detail { namespace windows { | |
16 | ||
17 | inline bool break_away_enabled(::boost::winapi::HANDLE_ h) | |
18 | { | |
19 | workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; | |
20 | ||
21 | if (!workaround::query_information_job_object( | |
22 | h, | |
23 | workaround::JobObjectExtendedLimitInformation_, | |
24 | static_cast<void*>(&info), | |
25 | sizeof(info), | |
26 | nullptr)) | |
27 | throw_last_error("QueryInformationJobObject() failed"); | |
28 | ||
29 | return (info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0; | |
30 | } | |
31 | ||
32 | inline void enable_break_away(::boost::winapi::HANDLE_ h) | |
33 | { | |
34 | workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; | |
35 | ||
36 | if (!workaround::query_information_job_object( | |
37 | h, | |
38 | workaround::JobObjectExtendedLimitInformation_, | |
39 | static_cast<void*>(&info), | |
40 | sizeof(info), | |
41 | nullptr)) | |
42 | throw_last_error("QueryInformationJobObject() failed"); | |
43 | ||
44 | if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0) | |
45 | return; | |
46 | ||
47 | info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_; | |
48 | ||
49 | if (!workaround::set_information_job_object( | |
50 | h, | |
51 | workaround::JobObjectExtendedLimitInformation_, | |
52 | static_cast<void*>(&info), | |
53 | sizeof(info))) | |
54 | throw_last_error("SetInformationJobObject() failed"); | |
55 | } | |
56 | ||
57 | inline void enable_break_away(::boost::winapi::HANDLE_ h, std::error_code & ec) | |
58 | { | |
59 | workaround::JOBOBJECT_EXTENDED_LIMIT_INFORMATION_ info; | |
60 | ||
61 | ||
62 | if (!workaround::query_information_job_object( | |
63 | h, | |
64 | workaround::JobObjectExtendedLimitInformation_, | |
65 | static_cast<void*>(&info), | |
66 | sizeof(info), | |
67 | nullptr)) | |
68 | { | |
69 | ec = get_last_error(); | |
70 | return; | |
71 | } | |
72 | ||
73 | if ((info.BasicLimitInformation.LimitFlags & workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_) != 0) | |
74 | return; | |
75 | ||
76 | info.BasicLimitInformation.LimitFlags |= workaround::JOB_OBJECT_LIMIT_BREAKAWAY_OK_; | |
77 | ||
78 | if (!workaround::set_information_job_object( | |
79 | h, | |
80 | workaround::JobObjectExtendedLimitInformation_, | |
81 | static_cast<void*>(&info), | |
82 | sizeof(info))) | |
83 | { | |
84 | ec = get_last_error(); | |
85 | return; | |
86 | } | |
92f5a8d4 | 87 | } |
b32b8144 | 88 | |
92f5a8d4 TL |
89 | inline void associate_completion_port(::boost::winapi::HANDLE_ job, |
90 | ::boost::winapi::HANDLE_ io_port) | |
91 | { | |
92 | workaround::JOBOBJECT_ASSOCIATE_COMPLETION_PORT_ port; | |
93 | port.CompletionKey = job; | |
94 | port.CompletionPort = io_port; | |
b32b8144 | 95 | |
92f5a8d4 TL |
96 | if (!workaround::set_information_job_object( |
97 | job, | |
98 | workaround::JobObjectAssociateCompletionPortInformation_, | |
99 | static_cast<void*>(&port), | |
100 | sizeof(port))) | |
101 | throw_last_error("SetInformationJobObject() failed"); | |
b32b8144 FG |
102 | } |
103 | ||
b32b8144 FG |
104 | struct group_handle |
105 | { | |
106 | ::boost::winapi::HANDLE_ _job_object; | |
92f5a8d4 | 107 | ::boost::winapi::HANDLE_ _io_port; |
b32b8144 FG |
108 | |
109 | typedef ::boost::winapi::HANDLE_ handle_t; | |
110 | handle_t handle() const { return _job_object; } | |
111 | ||
112 | explicit group_handle(handle_t h) : | |
92f5a8d4 TL |
113 | _job_object(h), |
114 | _io_port(::CreateIoCompletionPort(::boost::winapi::INVALID_HANDLE_VALUE_, nullptr, 0, 1)) | |
b32b8144 FG |
115 | { |
116 | enable_break_away(_job_object); | |
92f5a8d4 | 117 | associate_completion_port(_job_object, _io_port); |
b32b8144 FG |
118 | } |
119 | ||
120 | ||
11fdf7f2 | 121 | group_handle() : group_handle(::boost::winapi::CreateJobObjectW(nullptr, nullptr)) |
b32b8144 FG |
122 | { |
123 | ||
124 | } | |
125 | ~group_handle() | |
126 | { | |
127 | ::boost::winapi::CloseHandle(_job_object); | |
92f5a8d4 | 128 | ::boost::winapi::CloseHandle(_io_port); |
b32b8144 FG |
129 | } |
130 | group_handle(const group_handle & c) = delete; | |
92f5a8d4 TL |
131 | group_handle(group_handle && c) : _job_object(c._job_object), |
132 | _io_port(c._io_port) | |
b32b8144 FG |
133 | { |
134 | c._job_object = ::boost::winapi::invalid_handle_value; | |
92f5a8d4 | 135 | c._io_port = ::boost::winapi::invalid_handle_value; |
b32b8144 FG |
136 | } |
137 | group_handle &operator=(const group_handle & c) = delete; | |
138 | group_handle &operator=(group_handle && c) | |
139 | { | |
92f5a8d4 TL |
140 | ::boost::winapi::CloseHandle(_io_port); |
141 | _io_port = c._io_port; | |
142 | c._io_port = ::boost::winapi::invalid_handle_value; | |
b32b8144 FG |
143 | |
144 | ::boost::winapi::CloseHandle(_job_object); | |
145 | _job_object = c._job_object; | |
146 | c._job_object = ::boost::winapi::invalid_handle_value; | |
147 | return *this; | |
148 | } | |
149 | ||
150 | void add(handle_t proc) | |
151 | { | |
152 | if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc)) | |
153 | throw_last_error(); | |
154 | } | |
155 | void add(handle_t proc, std::error_code & ec) noexcept | |
156 | { | |
157 | if (!::boost::winapi::AssignProcessToJobObject(_job_object, proc)) | |
158 | ec = get_last_error(); | |
159 | } | |
160 | ||
161 | bool has(handle_t proc) | |
162 | { | |
163 | ::boost::winapi::BOOL_ is; | |
164 | if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is)) | |
165 | throw_last_error(); | |
166 | ||
167 | return is!=0; | |
168 | } | |
169 | bool has(handle_t proc, std::error_code & ec) noexcept | |
170 | { | |
171 | ::boost::winapi::BOOL_ is; | |
172 | if (!::boost::winapi::IsProcessInJob(proc, _job_object, &is)) | |
173 | ec = get_last_error(); | |
174 | return is!=0; | |
175 | } | |
176 | ||
177 | bool valid() const | |
178 | { | |
179 | return _job_object != nullptr; | |
180 | } | |
181 | ||
182 | }; | |
183 | ||
184 | inline void terminate(const group_handle &p) | |
185 | { | |
186 | if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) | |
187 | boost::process::detail::throw_last_error("TerminateJobObject() failed"); | |
188 | } | |
189 | ||
190 | inline void terminate(const group_handle &p, std::error_code &ec) noexcept | |
191 | { | |
192 | if (!::boost::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE)) | |
193 | ec = boost::process::detail::get_last_error(); | |
194 | else | |
195 | ec.clear(); | |
196 | } | |
197 | ||
198 | inline bool in_group() | |
199 | { | |
200 | ::boost::winapi::BOOL_ res; | |
201 | if (!::boost::winapi::IsProcessInJob(boost::winapi::GetCurrentProcess(), nullptr, &res)) | |
202 | throw_last_error("IsProcessInJob failed"); | |
203 | ||
204 | return res!=0; | |
205 | } | |
206 | ||
207 | ||
208 | ||
209 | }}}} | |
210 | ||
211 | ||
212 | #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */ |