1 // 2 // windows/basic_object_handle.hpp 3 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // Copyright (c) 2011 Boris Schaeling ([email protected]) 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 <boost/asio/any_io_executor.hpp> 25 #include <boost/asio/async_result.hpp> 26 #include <boost/asio/detail/io_object_impl.hpp> 27 #include <boost/asio/detail/throw_error.hpp> 28 #include <boost/asio/detail/win_object_handle_service.hpp> 29 #include <boost/asio/error.hpp> 30 #include <boost/asio/execution_context.hpp> 31 32 #if defined(BOOST_ASIO_HAS_MOVE) 33 # include <utility> 34 #endif // defined(BOOST_ASIO_HAS_MOVE) 35 36 #include <boost/asio/detail/push_options.hpp> 37 38 namespace boost { 39 namespace asio { 40 namespace windows { 41 42 /// Provides object-oriented handle functionality. 43 /** 44 * The windows::basic_object_handle class provides asynchronous and blocking 45 * object-oriented handle functionality. 46 * 47 * @par Thread Safety 48 * @e Distinct @e objects: Safe.@n 49 * @e Shared @e objects: Unsafe. 50 */ 51 template <typename Executor = any_io_executor> 52 class basic_object_handle 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 */ basic_object_handle(const executor_type & ex)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> basic_object_handle(ExecutionContext & context,typename constraint<is_convertible<ExecutionContext &,execution_context &>::value,defaulted_constraint>::type=defaulted_constraint ())99 explicit basic_object_handle(ExecutionContext& context, 100 typename constraint< 101 is_convertible<ExecutionContext&, execution_context&>::value, 102 defaulted_constraint 103 >::type = 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 */ basic_object_handle(const executor_type & ex,const native_handle_type & native_handle)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> basic_object_handle(ExecutionContext & context,const native_handle_type & native_handle,typename constraint<is_convertible<ExecutionContext &,execution_context &>::value>::type=0)144 basic_object_handle(ExecutionContext& context, 145 const native_handle_type& native_handle, 146 typename constraint< 147 is_convertible<ExecutionContext&, execution_context&>::value 148 >::type = 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 #if defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 157 /// Move-construct an object handle from another. 158 /** 159 * This constructor moves an object handle from one object to another. 160 * 161 * @param other The other object handle object from which the move will 162 * occur. 163 * 164 * @note Following the move, the moved-from object is in the same state as if 165 * constructed using the @c basic_object_handle(const executor_type&) 166 * constructor. 167 */ basic_object_handle(basic_object_handle && other)168 basic_object_handle(basic_object_handle&& other) 169 : impl_(std::move(other.impl_)) 170 { 171 } 172 173 /// Move-assign an object handle from another. 174 /** 175 * This assignment operator moves an object handle from one object to another. 176 * 177 * @param other The other object handle object from which the move will 178 * occur. 179 * 180 * @note Following the move, the moved-from object is in the same state as if 181 * constructed using the @c basic_object_handle(const executor_type&) 182 * constructor. 183 */ operator =(basic_object_handle && other)184 basic_object_handle& operator=(basic_object_handle&& other) 185 { 186 impl_ = std::move(other.impl_); 187 return *this; 188 } 189 #endif // defined(BOOST_ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION) 190 191 /// Get the executor associated with the object. get_executor()192 executor_type get_executor() BOOST_ASIO_NOEXCEPT 193 { 194 return impl_.get_executor(); 195 } 196 197 /// Get a reference to the lowest layer. 198 /** 199 * This function returns a reference to the lowest layer in a stack of 200 * layers. Since an object handle cannot contain any further layers, it simply 201 * returns a reference to itself. 202 * 203 * @return A reference to the lowest layer in the stack of layers. Ownership 204 * is not transferred to the caller. 205 */ lowest_layer()206 lowest_layer_type& lowest_layer() 207 { 208 return *this; 209 } 210 211 /// Get a const reference to the lowest layer. 212 /** 213 * This function returns a const reference to the lowest layer in a stack of 214 * layers. Since an object handle cannot contain any further layers, it simply 215 * returns a reference to itself. 216 * 217 * @return A const reference to the lowest layer in the stack of layers. 218 * Ownership is not transferred to the caller. 219 */ lowest_layer() const220 const lowest_layer_type& lowest_layer() const 221 { 222 return *this; 223 } 224 225 /// Assign an existing native handle to the handle. 226 /* 227 * This function opens the handle to hold an existing native handle. 228 * 229 * @param handle A native handle. 230 * 231 * @throws boost::system::system_error Thrown on failure. 232 */ assign(const native_handle_type & handle)233 void assign(const native_handle_type& handle) 234 { 235 boost::system::error_code ec; 236 impl_.get_service().assign(impl_.get_implementation(), handle, ec); 237 boost::asio::detail::throw_error(ec, "assign"); 238 } 239 240 /// Assign an existing native handle to the handle. 241 /* 242 * This function opens the handle to hold an existing native handle. 243 * 244 * @param handle A native handle. 245 * 246 * @param ec Set to indicate what error occurred, if any. 247 */ assign(const native_handle_type & handle,boost::system::error_code & ec)248 BOOST_ASIO_SYNC_OP_VOID assign(const native_handle_type& handle, 249 boost::system::error_code& ec) 250 { 251 impl_.get_service().assign(impl_.get_implementation(), handle, ec); 252 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 253 } 254 255 /// Determine whether the handle is open. is_open() const256 bool is_open() const 257 { 258 return impl_.get_service().is_open(impl_.get_implementation()); 259 } 260 261 /// Close the handle. 262 /** 263 * This function is used to close the handle. Any asynchronous read or write 264 * operations will be cancelled immediately, and will complete with the 265 * boost::asio::error::operation_aborted error. 266 * 267 * @throws boost::system::system_error Thrown on failure. 268 */ close()269 void close() 270 { 271 boost::system::error_code ec; 272 impl_.get_service().close(impl_.get_implementation(), ec); 273 boost::asio::detail::throw_error(ec, "close"); 274 } 275 276 /// Close the handle. 277 /** 278 * This function is used to close the handle. Any asynchronous read or write 279 * operations will be cancelled immediately, and will complete with the 280 * boost::asio::error::operation_aborted error. 281 * 282 * @param ec Set to indicate what error occurred, if any. 283 */ close(boost::system::error_code & ec)284 BOOST_ASIO_SYNC_OP_VOID close(boost::system::error_code& ec) 285 { 286 impl_.get_service().close(impl_.get_implementation(), ec); 287 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 288 } 289 290 /// Get the native handle representation. 291 /** 292 * This function may be used to obtain the underlying representation of the 293 * handle. This is intended to allow access to native handle functionality 294 * that is not otherwise provided. 295 */ native_handle()296 native_handle_type native_handle() 297 { 298 return impl_.get_service().native_handle(impl_.get_implementation()); 299 } 300 301 /// Cancel all asynchronous operations associated with the handle. 302 /** 303 * This function causes all outstanding asynchronous read or write operations 304 * to finish immediately, and the handlers for cancelled operations will be 305 * passed the boost::asio::error::operation_aborted error. 306 * 307 * @throws boost::system::system_error Thrown on failure. 308 */ cancel()309 void cancel() 310 { 311 boost::system::error_code ec; 312 impl_.get_service().cancel(impl_.get_implementation(), ec); 313 boost::asio::detail::throw_error(ec, "cancel"); 314 } 315 316 /// Cancel all asynchronous operations associated with the handle. 317 /** 318 * This function causes all outstanding asynchronous read or write operations 319 * to finish immediately, and the handlers for cancelled operations will be 320 * passed the boost::asio::error::operation_aborted error. 321 * 322 * @param ec Set to indicate what error occurred, if any. 323 */ cancel(boost::system::error_code & ec)324 BOOST_ASIO_SYNC_OP_VOID cancel(boost::system::error_code& ec) 325 { 326 impl_.get_service().cancel(impl_.get_implementation(), ec); 327 BOOST_ASIO_SYNC_OP_VOID_RETURN(ec); 328 } 329 330 /// Perform a blocking wait on the object handle. 331 /** 332 * This function is used to wait for the object handle to be set to the 333 * signalled state. This function blocks and does not return until the object 334 * handle has been set to the signalled state. 335 * 336 * @throws boost::system::system_error Thrown on failure. 337 */ wait()338 void wait() 339 { 340 boost::system::error_code ec; 341 impl_.get_service().wait(impl_.get_implementation(), ec); 342 boost::asio::detail::throw_error(ec, "wait"); 343 } 344 345 /// Perform a blocking wait on the object handle. 346 /** 347 * This function is used to wait for the object handle to be set to the 348 * signalled state. This function blocks and does not return until the object 349 * handle has been set to the signalled state. 350 * 351 * @param ec Set to indicate what error occurred, if any. 352 */ wait(boost::system::error_code & ec)353 void wait(boost::system::error_code& ec) 354 { 355 impl_.get_service().wait(impl_.get_implementation(), ec); 356 } 357 358 /// Start an asynchronous wait on the object handle. 359 /** 360 * This function is be used to initiate an asynchronous wait against the 361 * object handle. It always returns immediately. 362 * 363 * @param handler The handler to be called when the object handle is set to 364 * the signalled state. Copies will be made of the handler as required. The 365 * function signature of the handler must be: 366 * @code void handler( 367 * const boost::system::error_code& error // Result of operation. 368 * ); @endcode 369 * Regardless of whether the asynchronous operation completes immediately or 370 * not, the handler will not be invoked from within this function. On 371 * immediate completion, invocation of the handler will be performed in a 372 * manner equivalent to using boost::asio::post(). 373 */ 374 template < 375 BOOST_ASIO_COMPLETION_TOKEN_FOR(void (boost::system::error_code)) 376 WaitHandler BOOST_ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)> BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler,void (boost::system::error_code))377 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(WaitHandler, 378 void (boost::system::error_code)) 379 async_wait( 380 BOOST_ASIO_MOVE_ARG(WaitHandler) handler 381 BOOST_ASIO_DEFAULT_COMPLETION_TOKEN(executor_type)) 382 { 383 return async_initiate<WaitHandler, void (boost::system::error_code)>( 384 initiate_async_wait(this), handler); 385 } 386 387 private: 388 // Disallow copying and assignment. 389 basic_object_handle(const basic_object_handle&) BOOST_ASIO_DELETED; 390 basic_object_handle& operator=(const basic_object_handle&) BOOST_ASIO_DELETED; 391 392 class initiate_async_wait 393 { 394 public: 395 typedef Executor executor_type; 396 initiate_async_wait(basic_object_handle * self)397 explicit initiate_async_wait(basic_object_handle* self) 398 : self_(self) 399 { 400 } 401 get_executor() const402 executor_type get_executor() const BOOST_ASIO_NOEXCEPT 403 { 404 return self_->get_executor(); 405 } 406 407 template <typename WaitHandler> operator ()(BOOST_ASIO_MOVE_ARG (WaitHandler)handler) const408 void operator()(BOOST_ASIO_MOVE_ARG(WaitHandler) handler) const 409 { 410 // If you get an error on the following line it means that your handler 411 // does not meet the documented type requirements for a WaitHandler. 412 BOOST_ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check; 413 414 detail::non_const_lvalue<WaitHandler> handler2(handler); 415 self_->impl_.get_service().async_wait( 416 self_->impl_.get_implementation(), 417 handler2.value, self_->impl_.get_executor()); 418 } 419 420 private: 421 basic_object_handle* self_; 422 }; 423 424 boost::asio::detail::io_object_impl< 425 boost::asio::detail::win_object_handle_service, Executor> impl_; 426 }; 427 428 } // namespace windows 429 } // namespace asio 430 } // namespace boost 431 432 #include <boost/asio/detail/pop_options.hpp> 433 434 #endif // defined(BOOST_ASIO_HAS_WINDOWS_OBJECT_HANDLE) 435 // || defined(GENERATING_DOCUMENTATION) 436 437 #endif // BOOST_ASIO_WINDOWS_BASIC_OBJECT_HANDLE_HPP 438