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