Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / process / detail / windows / group_handle.hpp
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/detail/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::detail::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::detail::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::detail::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     }
87
88
89 }
90
91
92 struct group_handle
93 {
94     ::boost::detail::winapi::HANDLE_ _job_object;
95
96     typedef ::boost::detail::winapi::HANDLE_ handle_t;
97     handle_t handle() const { return _job_object; }
98
99     explicit group_handle(handle_t h) :
100         _job_object(h)
101     {
102         enable_break_away(_job_object);
103     }
104
105
106     group_handle() : group_handle(::boost::detail::winapi::CreateJobObjectA(nullptr, nullptr))
107     {
108
109     }
110     ~group_handle()
111     {
112         ::boost::detail::winapi::CloseHandle(_job_object);
113     }
114     group_handle(const group_handle & c) = delete;
115     group_handle(group_handle && c) : _job_object(c._job_object)
116     {
117         c._job_object = ::boost::detail::winapi::invalid_handle_value;
118     }
119     group_handle &operator=(const group_handle & c) = delete;
120     group_handle &operator=(group_handle && c)
121     {
122
123         ::boost::detail::winapi::CloseHandle(_job_object);
124         _job_object = c._job_object;
125         c._job_object = ::boost::detail::winapi::invalid_handle_value;
126         return *this;
127     }
128
129     void add(handle_t proc)
130     {
131         if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
132             throw_last_error();
133     }
134     void add(handle_t proc, std::error_code & ec) noexcept
135     {
136         if (!::boost::detail::winapi::AssignProcessToJobObject(_job_object, proc))
137             ec = get_last_error();
138     }
139
140     bool has(handle_t proc)
141     {
142         ::boost::detail::winapi::BOOL_ is;
143         if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object,  &is))
144             throw_last_error();
145
146         return is!=0;
147     }
148     bool has(handle_t proc, std::error_code & ec) noexcept
149     {
150         ::boost::detail::winapi::BOOL_ is;
151         if (!::boost::detail::winapi::IsProcessInJob(proc, _job_object,  &is))
152             ec = get_last_error();
153         return is!=0;
154     }
155
156     bool valid() const
157     {
158         return _job_object != nullptr;
159     }
160
161 };
162
163 inline void terminate(const group_handle &p)
164 {
165     if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
166         boost::process::detail::throw_last_error("TerminateJobObject() failed");
167 }
168
169 inline void terminate(const group_handle &p, std::error_code &ec) noexcept
170 {
171     if (!::boost::detail::winapi::TerminateJobObject(p.handle(), EXIT_FAILURE))
172         ec = boost::process::detail::get_last_error();
173     else
174         ec.clear();
175 }
176
177 inline bool in_group()
178 {
179     ::boost::detail::winapi::BOOL_ res;
180     if (!::boost::detail::winapi::IsProcessInJob(boost::detail::winapi::GetCurrentProcess(), nullptr, &res))
181         throw_last_error("IsProcessInJob failed");
182
183     return res!=0;
184 }
185
186
187
188 }}}}
189
190
191 #endif /* BOOST_PROCESS_DETAIL_WINDOWS_GROUP_HPP_ */