1 | // |
2 | // windows/basic_object_handle.hpp |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
4 | // |
5 | // Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com) |
6 | // Copyright (c) 2011 Boris Schaeling (boris@highscore.de) |
7 | // |
8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying |
9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
10 | // |
11 | |
12 | #ifndef BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP |
13 | #define BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP |
14 | |
15 | #if defined(_MSC_VER) && (_MSC_VER >= 1200) |
16 | # pragma once |
17 | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) |
18 | |
19 | #include <boost/asio/detail/config.hpp> |
20 | |
21 | #if defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) \ |
22 | || defined(GENERATING_DOCUMENTATION) |
23 | |
24 | #include <utility> |
25 | #include <boost/asio/any_io_executor.hpp> |
26 | #include <boost/asio/async_result.hpp> |
27 | #include <boost/asio/detail/io_object_impl.hpp> |
28 | #include <boost/asio/detail/throw_error.hpp> |
29 | #include <boost/asio/detail/win_object_handle_service.hpp> |
30 | #include <boost/asio/error.hpp> |
31 | #include <boost/asio/execution_context.hpp> |
32 | |
33 | #include <boost/asio/detail/push_options.hpp> |
34 | |
35 | namespace boost { |
36 | namespace asio { |
37 | namespace windows { |
38 | |
39 | /// Provides object-oriented handle functionality. |
40 | /** |
41 | * The windows::basic_object_handle class provides asynchronous and blocking |
42 | * object-oriented handle functionality. |
43 | * |
44 | * @par Thread Safety |
45 | * @e Distinct @e objects: Safe.@n |
46 | * @e Shared @e objects: Unsafe. |
47 | */ |
48 | template <typename Executor = any_io_executor> |
49 | class basic_object_handle |
50 | { |
51 | private: |
52 | class initiate_async_wait; |
53 | |
54 | public: |
55 | /// The type of the executor associated with the object. |
56 | typedef Executor executor_type; |
57 | |
58 | /// Rebinds the handle type to another executor. |
59 | template <typename Executor1> |
60 | struct rebind_executor |
61 | { |
62 | /// The handle type when rebound to the specified executor. |
63 | typedef basic_object_handle<Executor1> other; |
64 | }; |
65 | |
66 | /// The native representation of a handle. |
67 | #if defined(GENERATING_DOCUMENTATION) |
68 | typedef implementation_defined native_handle_type; |
69 | #else |
70 | typedef boost::asio::detail::win_object_handle_service::native_handle_type |
71 | native_handle_type; |
72 | #endif |
73 | |
74 | /// An object handle is always the lowest layer. |
75 | typedef basic_object_handle lowest_layer_type; |
76 | |
77 | /// Construct an object handle without opening it. |
78 | /** |
79 | * This constructor creates an object handle without opening it. |
80 | * |
81 | * @param ex The I/O executor that the object handle will use, by default, to |
82 | * dispatch handlers for any asynchronous operations performed on the |
83 | * object handle. |
84 | */ |
85 | explicit basic_object_handle(const executor_type& ex) |
86 | : impl_(0, ex) |
87 | { |
88 | } |
89 | |
90 | /// Construct an object handle without opening it. |
91 | /** |
92 | * This constructor creates an object handle without opening it. |
93 | * |
94 | * @param context An execution context which provides the I/O executor that |
95 | * the object handle will use, by default, to dispatch handlers for any |
96 | * asynchronous operations performed on the object handle. |
97 | */ |
98 | template <typename ExecutionContext> |
99 | explicit basic_object_handle(ExecutionContext& context, |
100 | constraint_t< |
101 | is_convertible<ExecutionContext&, execution_context&>::value, |
102 | defaulted_constraint |
103 | > = defaulted_constraint()) |
104 | : impl_(0, 0, context) |
105 | { |
106 | } |
107 | |
108 | /// Construct an object handle on an existing native handle. |
109 | /** |
110 | * This constructor creates an object handle object to hold an existing native |
111 | * handle. |
112 | * |
113 | * @param ex The I/O executor that the object handle will use, by default, to |
114 | * dispatch handlers for any asynchronous operations performed on the |
115 | * object handle. |
116 | * |
117 | * @param native_handle The new underlying handle implementation. |
118 | * |
119 | * @throws boost::system::system_error Thrown on failure. |
120 | */ |
121 | basic_object_handle(const executor_type& ex, |
122 | const native_handle_type& native_handle) |
123 | : impl_(0, ex) |
124 | { |
125 | boost::system::error_code ec; |
126 | impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); |
127 | boost::asio::detail::throw_error(ec, "assign" ); |
128 | } |
129 | |
130 | /// Construct an object handle on an existing native handle. |
131 | /** |
132 | * This constructor creates an object handle object to hold an existing native |
133 | * handle. |
134 | * |
135 | * @param context An execution context which provides the I/O executor that |
136 | * the object handle will use, by default, to dispatch handlers for any |
137 | * asynchronous operations performed on the object handle. |
138 | * |
139 | * @param native_handle The new underlying handle implementation. |
140 | * |
141 | * @throws boost::system::system_error Thrown on failure. |
142 | */ |
143 | template <typename ExecutionContext> |
144 | basic_object_handle(ExecutionContext& context, |
145 | const native_handle_type& native_handle, |
146 | constraint_t< |
147 | is_convertible<ExecutionContext&, execution_context&>::value |
148 | > = 0) |
149 | : impl_(0, 0, context) |
150 | { |
151 | boost::system::error_code ec; |
152 | impl_.get_service().assign(impl_.get_implementation(), native_handle, ec); |
153 | boost::asio::detail::throw_error(ec, "assign" ); |
154 | } |
155 | |
156 | /// Move-construct an object handle from another. |
157 | /** |
158 | * This constructor moves an object handle from one object to another. |
159 | * |
160 | * @param other The other object handle object from which the move will |
161 | * occur. |
162 | * |
163 | * @note Following the move, the moved-from object is in the same state as if |
164 | * constructed using the @c basic_object_handle(const executor_type&) |
165 | * constructor. |
166 | */ |
167 | basic_object_handle(basic_object_handle&& other) |
168 | : impl_(std::move(other.impl_)) |
169 | { |
170 | } |
171 | |
172 | /// Move-assign an object handle from another. |
173 | /** |
174 | * This assignment operator moves an object handle from one object to another. |
175 | * |
176 | * @param other The other object handle object from which the move will |
177 | * occur. |
178 | * |
179 | * @note Following the move, the moved-from object is in the same state as if |
180 | * constructed using the @c basic_object_handle(const executor_type&) |
181 | * constructor. |
182 | */ |
183 | basic_object_handle& operator=(basic_object_handle&& other) |
184 | { |
185 | impl_ = std::move(other.impl_); |
186 | return *this; |
187 | } |
188 | |
189 | // All handles have access to each other's implementations. |
190 | template <typename Executor1> |
191 | friend class basic_object_handle; |
192 | |
193 | /// Move-construct an object handle from a handle of another executor type. |
194 | /** |
195 | * This constructor moves an object handle from one object to another. |
196 | * |
197 | * @param other The other object handle object from which the move will |
198 | * occur. |
199 | * |
200 | * @note Following the move, the moved-from object is in the same state as if |
201 | * constructed using the @c basic_object_handle(const executor_type&) |
202 | * constructor. |
203 | */ |
204 | template<typename Executor1> |
205 | basic_object_handle(basic_object_handle<Executor1>&& other, |
206 | constraint_t< |
207 | is_convertible<Executor1, Executor>::value, |
208 | defaulted_constraint |
209 | > = defaulted_constraint()) |
210 | : impl_(std::move(other.impl_)) |
211 | { |
212 | } |
213 | |
214 | /// Move-assign an object handle from a handle of another executor type. |
215 | /** |
216 | * This assignment operator moves an object handle from one object to another. |
217 | * |
218 | * @param other The other object handle object from which the move will |
219 | * occur. |
220 | * |
221 | * @note Following the move, the moved-from object is in the same state as if |
222 | * constructed using the @c basic_object_handle(const executor_type&) |
223 | * constructor. |
224 | */ |
225 | template<typename Executor1> |
226 | constraint_t< |
227 | is_convertible<Executor1, Executor>::value, |
228 | basic_object_handle& |
229 | > operator=(basic_object_handle<Executor1>&& other) |
230 | { |
231 | impl_ = std::move(other.impl_); |
232 | return *this; |
233 | } |
234 | |
235 | /// Get the executor associated with the object. |
236 | const executor_type& get_executor() noexcept |
237 | { |
238 | return impl_.get_executor(); |
239 | } |
240 | |
241 | /// Get a reference to the lowest layer. |
242 | /** |
243 | * This function returns a reference to the lowest layer in a stack of |
244 | * layers. Since an object handle cannot contain any further layers, it simply |
245 | * returns a reference to itself. |
246 | * |
247 | * @return A reference to the lowest layer in the stack of layers. Ownership |
248 | * is not transferred to the caller. |
249 | */ |
250 | lowest_layer_type& lowest_layer() |
251 | { |
252 | return *this; |
253 | } |
254 | |
255 | /// Get a const reference to the lowest layer. |
256 | /** |
257 | * This function returns a const reference to the lowest layer in a stack of |
258 | * layers. Since an object handle cannot contain any further layers, it simply |
259 | * returns a reference to itself. |
260 | * |
261 | * @return A const reference to the lowest layer in the stack of layers. |
262 | * Ownership is not transferred to the caller. |
263 | */ |
264 | const lowest_layer_type& lowest_layer() const |
265 | { |
266 | return *this; |
267 | } |
268 | |
269 | /// Assign an existing native handle to the handle. |
270 | /* |
271 | * This function opens the handle to hold an existing native handle. |
272 | * |
273 | * @param handle A native handle. |
274 | * |
275 | * @throws boost::system::system_error Thrown on failure. |
276 | */ |
277 | void assign(const native_handle_type& handle) |
278 | { |
279 | boost::system::error_code ec; |
280 | impl_.get_service().assign(impl_.get_implementation(), handle, ec); |
281 | boost::asio::detail::throw_error(ec, "assign" ); |
282 | } |
283 | |
284 | /// Assign an existing native handle to the handle. |
285 | /* |
286 | * This function opens the handle to hold an existing native handle. |
287 | * |
288 | * @param handle A native handle. |
289 | * |
290 | * @param ec Set to indicate what error occurred, if any. |
291 | */ |
292 | BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, |
293 | boost::system::error_code& ec) |
294 | { |
295 | impl_.get_service().assign(impl_.get_implementation(), handle, ec); |
296 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
297 | } |
298 | |
299 | /// Determine whether the handle is open. |
300 | bool is_open() const |
301 | { |
302 | return impl_.get_service().is_open(impl_.get_implementation()); |
303 | } |
304 | |
305 | /// Close the handle. |
306 | /** |
307 | * This function is used to close the handle. Any asynchronous read or write |
308 | * operations will be cancelled immediately, and will complete with the |
309 | * boost::asio::error::operation_aborted error. |
310 | * |
311 | * @throws boost::system::system_error Thrown on failure. |
312 | */ |
313 | void close() |
314 | { |
315 | boost::system::error_code ec; |
316 | impl_.get_service().close(impl_.get_implementation(), ec); |
317 | boost::asio::detail::throw_error(ec, "close" ); |
318 | } |
319 | |
320 | /// Close the handle. |
321 | /** |
322 | * This function is used to close the handle. Any asynchronous read or write |
323 | * operations will be cancelled immediately, and will complete with the |
324 | * boost::asio::error::operation_aborted error. |
325 | * |
326 | * @param ec Set to indicate what error occurred, if any. |
327 | */ |
328 | BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) |
329 | { |
330 | impl_.get_service().close(impl_.get_implementation(), ec); |
331 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
332 | } |
333 | |
334 | /// Get the native handle representation. |
335 | /** |
336 | * This function may be used to obtain the underlying representation of the |
337 | * handle. This is intended to allow access to native handle functionality |
338 | * that is not otherwise provided. |
339 | */ |
340 | native_handle_type native_handle() |
341 | { |
342 | return impl_.get_service().native_handle(impl_.get_implementation()); |
343 | } |
344 | |
345 | /// Cancel all asynchronous operations associated with the handle. |
346 | /** |
347 | * This function causes all outstanding asynchronous read or write operations |
348 | * to finish immediately, and the handlers for cancelled operations will be |
349 | * passed the boost::asio::error::operation_aborted error. |
350 | * |
351 | * @throws boost::system::system_error Thrown on failure. |
352 | */ |
353 | void cancel() |
354 | { |
355 | boost::system::error_code ec; |
356 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
357 | boost::asio::detail::throw_error(ec, "cancel" ); |
358 | } |
359 | |
360 | /// Cancel all asynchronous operations associated with the handle. |
361 | /** |
362 | * This function causes all outstanding asynchronous read or write operations |
363 | * to finish immediately, and the handlers for cancelled operations will be |
364 | * passed the boost::asio::error::operation_aborted error. |
365 | * |
366 | * @param ec Set to indicate what error occurred, if any. |
367 | */ |
368 | BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) |
369 | { |
370 | impl_.get_service().cancel(impl_.get_implementation(), ec); |
371 | BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); |
372 | } |
373 | |
374 | /// Perform a blocking wait on the object handle. |
375 | /** |
376 | * This function is used to wait for the object handle to be set to the |
377 | * signalled state. This function blocks and does not return until the object |
378 | * handle has been set to the signalled state. |
379 | * |
380 | * @throws boost::system::system_error Thrown on failure. |
381 | */ |
382 | void wait() |
383 | { |
384 | boost::system::error_code ec; |
385 | impl_.get_service().wait(impl_.get_implementation(), ec); |
386 | boost::asio::detail::throw_error(ec, "wait" ); |
387 | } |
388 | |
389 | /// Perform a blocking wait on the object handle. |
390 | /** |
391 | * This function is used to wait for the object handle to be set to the |
392 | * signalled state. This function blocks and does not return until the object |
393 | * handle has been set to the signalled state. |
394 | * |
395 | * @param ec Set to indicate what error occurred, if any. |
396 | */ |
397 | void wait(boost::system::error_code& ec) |
398 | { |
399 | impl_.get_service().wait(impl_.get_implementation(), ec); |
400 | } |
401 | |
402 | /// Start an asynchronous wait on the object handle. |
403 | /** |
404 | * This function is be used to initiate an asynchronous wait against the |
405 | * object handle. It is an initiating function for an @ref |
406 | * asynchronous_operation, and always returns immediately. |
407 | * |
408 | * @param token The @ref completion_token that will be used to produce a |
409 | * completion handler, which will be called when the wait completes. |
410 | * Potential completion tokens include @ref use_future, @ref use_awaitable, |
411 | * @ref yield_context, or a function object with the correct completion |
412 | * signature. The function signature of the completion handler must be: |
413 | * @code void handler( |
414 | * const boost::system::error_code& error // Result of operation. |
415 | * ); @endcode |
416 | * Regardless of whether the asynchronous operation completes immediately or |
417 | * not, the completion handler will not be invoked from within this function. |
418 | * On immediate completion, invocation of the handler will be performed in a |
419 | * manner equivalent to using boost::asio::post(). |
420 | * |
421 | * @par Completion Signature |
422 | * @code void(boost::system::error_code) @endcode |
423 | */ |
424 | template < |
425 | BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) |
426 | WaitToken = default_completion_token_t<executor_type>> |
427 | auto async_wait( |
428 | WaitToken&& token = default_completion_token_t<executor_type>()) |
429 | -> decltype( |
430 | async_initiate<WaitToken, void (boost::system::error_code)>( |
431 | declval<initiate_async_wait>(), token)) |
432 | { |
433 | return async_initiate<WaitToken, void (boost::system::error_code)>( |
434 | initiate_async_wait(this), token); |
435 | } |
436 | |
437 | private: |
438 | // Disallow copying and assignment. |
439 | basic_object_handle(const basic_object_handle&) = delete; |
440 | basic_object_handle& operator=(const basic_object_handle&) = delete; |
441 | |
442 | class initiate_async_wait |
443 | { |
444 | public: |
445 | typedef Executor executor_type; |
446 | |
447 | explicit initiate_async_wait(basic_object_handle* self) |
448 | : self_(self) |
449 | { |
450 | } |
451 | |
452 | const executor_type& get_executor() const noexcept |
453 | { |
454 | return self_->get_executor(); |
455 | } |
456 | |
457 | template <typename WaitHandler> |
458 | void operator()(WaitHandler&& handler) const |
459 | { |
460 | // If you get an error on the following line it means that your handler |
461 | // does not meet the documented type requirements for a WaitHandler. |
462 | BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; |
463 | |
464 | detail::non_const_lvalue<WaitHandler> handler2(handler); |
465 | self_->impl_.get_service().async_wait( |
466 | self_->impl_.get_implementation(), |
467 | handler2.value, self_->impl_.get_executor()); |
468 | } |
469 | |
470 | private: |
471 | basic_object_handle* self_; |
472 | }; |
473 | |
474 | boost::asio::detail::io_object_impl< |
475 | boost::asio::detail::win_object_handle_service, Executor> impl_; |
476 | }; |
477 | |
478 | } // namespace windows |
479 | } // namespace asio |
480 | } // namespace boost |
481 | |
482 | #include <boost/asio/detail/pop_options.hpp> |
483 | |
484 | #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) |
485 | // || defined(GENERATING_DOCUMENTATION) |
486 | |
487 | #endif // BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP |
488 | |