1 // 2 // detail/win_event.hpp 3 // ~~~~~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #ifndef BOOST_ASIO_DETAIL_WIN_EVENT_HPP 12 #define BOOST_ASIO_DETAIL_WIN_EVENT_HPP 13 14 #if defined(_MSC_VER) && (_MSC_VER >= 1200) 15 # pragma once 16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18 #include <boost/asio/detail/config.hpp> 19 20 #if defined(BOOST_ASIO_WINDOWS) 21 22 #include <cstddef> 23 #include <boost/asio/detail/assert.hpp> 24 #include <boost/asio/detail/noncopyable.hpp> 25 #include <boost/asio/detail/socket_types.hpp> 26 27 #include <boost/asio/detail/push_options.hpp> 28 29 namespace boost { 30 namespace asio { 31 namespace detail { 32 33 class win_event 34 : private noncopyable 35 { 36 public: 37 // Constructor. 38 BOOST_ASIO_DECL win_event(); 39 40 // Destructor. 41 BOOST_ASIO_DECL ~win_event(); 42 43 // Signal the event. (Retained for backward compatibility.) 44 template <typename Lock> signal(Lock & lock)45 void signal(Lock& lock) 46 { 47 this->signal_all(lock); 48 } 49 50 // Signal all waiters. 51 template <typename Lock> signal_all(Lock & lock)52 void signal_all(Lock& lock) 53 { 54 BOOST_ASIO_ASSERT(lock.locked()); 55 (void)lock; 56 state_ |= 1; 57 ::SetEvent(events_[0]); 58 } 59 60 // Unlock the mutex and signal one waiter. 61 template <typename Lock> unlock_and_signal_one(Lock & lock)62 void unlock_and_signal_one(Lock& lock) 63 { 64 BOOST_ASIO_ASSERT(lock.locked()); 65 state_ |= 1; 66 bool have_waiters = (state_ > 1); 67 lock.unlock(); 68 if (have_waiters) 69 ::SetEvent(events_[1]); 70 } 71 72 // Unlock the mutex and signal one waiter who may destroy us. 73 template <typename Lock> unlock_and_signal_one_for_destruction(Lock & lock)74 void unlock_and_signal_one_for_destruction(Lock& lock) 75 { 76 BOOST_ASIO_ASSERT(lock.locked()); 77 state_ |= 1; 78 bool have_waiters = (state_ > 1); 79 if (have_waiters) 80 ::SetEvent(events_[1]); 81 lock.unlock(); 82 } 83 84 // If there's a waiter, unlock the mutex and signal it. 85 template <typename Lock> maybe_unlock_and_signal_one(Lock & lock)86 bool maybe_unlock_and_signal_one(Lock& lock) 87 { 88 BOOST_ASIO_ASSERT(lock.locked()); 89 state_ |= 1; 90 if (state_ > 1) 91 { 92 lock.unlock(); 93 ::SetEvent(events_[1]); 94 return true; 95 } 96 return false; 97 } 98 99 // Reset the event. 100 template <typename Lock> clear(Lock & lock)101 void clear(Lock& lock) 102 { 103 BOOST_ASIO_ASSERT(lock.locked()); 104 (void)lock; 105 ::ResetEvent(events_[0]); 106 state_ &= ~std::size_t(1); 107 } 108 109 // Wait for the event to become signalled. 110 template <typename Lock> wait(Lock & lock)111 void wait(Lock& lock) 112 { 113 BOOST_ASIO_ASSERT(lock.locked()); 114 while ((state_ & 1) == 0) 115 { 116 state_ += 2; 117 lock.unlock(); 118 #if defined(BOOST_ASIO_WINDOWS_APP) 119 ::WaitForMultipleObjectsEx(2, events_, false, INFINITE, false); 120 #else // defined(BOOST_ASIO_WINDOWS_APP) 121 ::WaitForMultipleObjects(2, events_, false, INFINITE); 122 #endif // defined(BOOST_ASIO_WINDOWS_APP) 123 lock.lock(); 124 state_ -= 2; 125 } 126 } 127 128 // Timed wait for the event to become signalled. 129 template <typename Lock> wait_for_usec(Lock & lock,long usec)130 bool wait_for_usec(Lock& lock, long usec) 131 { 132 BOOST_ASIO_ASSERT(lock.locked()); 133 if ((state_ & 1) == 0) 134 { 135 state_ += 2; 136 lock.unlock(); 137 DWORD msec = usec > 0 ? (usec < 1000 ? 1 : usec / 1000) : 0; 138 #if defined(BOOST_ASIO_WINDOWS_APP) 139 ::WaitForMultipleObjectsEx(2, events_, false, msec, false); 140 #else // defined(BOOST_ASIO_WINDOWS_APP) 141 ::WaitForMultipleObjects(2, events_, false, msec); 142 #endif // defined(BOOST_ASIO_WINDOWS_APP) 143 lock.lock(); 144 state_ -= 2; 145 } 146 return (state_ & 1) != 0; 147 } 148 149 private: 150 HANDLE events_[2]; 151 std::size_t state_; 152 }; 153 154 } // namespace detail 155 } // namespace asio 156 } // namespace boost 157 158 #include <boost/asio/detail/pop_options.hpp> 159 160 #if defined(BOOST_ASIO_HEADER_ONLY) 161 # include <boost/asio/detail/impl/win_event.ipp> 162 #endif // defined(BOOST_ASIO_HEADER_ONLY) 163 164 #endif // defined(BOOST_ASIO_WINDOWS) 165 166 #endif // BOOST_ASIO_DETAIL_WIN_EVENT_HPP 167