Chris@16
|
1 //
|
Chris@16
|
2 // detail/std_event.hpp
|
Chris@16
|
3 // ~~~~~~~~~~~~~~~~~~~~
|
Chris@16
|
4 //
|
Chris@101
|
5 // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
Chris@16
|
6 //
|
Chris@16
|
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 //
|
Chris@16
|
10
|
Chris@16
|
11 #ifndef BOOST_ASIO_DETAIL_STD_EVENT_HPP
|
Chris@16
|
12 #define BOOST_ASIO_DETAIL_STD_EVENT_HPP
|
Chris@16
|
13
|
Chris@16
|
14 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
15 # pragma once
|
Chris@16
|
16 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
Chris@16
|
17
|
Chris@16
|
18 #include <boost/asio/detail/config.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #if defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR)
|
Chris@16
|
21
|
Chris@16
|
22 #include <chrono>
|
Chris@16
|
23 #include <condition_variable>
|
Chris@16
|
24 #include <boost/asio/detail/assert.hpp>
|
Chris@16
|
25 #include <boost/asio/detail/noncopyable.hpp>
|
Chris@16
|
26
|
Chris@16
|
27 #include <boost/asio/detail/push_options.hpp>
|
Chris@16
|
28
|
Chris@16
|
29 namespace boost {
|
Chris@16
|
30 namespace asio {
|
Chris@16
|
31 namespace detail {
|
Chris@16
|
32
|
Chris@16
|
33 class std_event
|
Chris@16
|
34 : private noncopyable
|
Chris@16
|
35 {
|
Chris@16
|
36 public:
|
Chris@16
|
37 // Constructor.
|
Chris@16
|
38 std_event()
|
Chris@101
|
39 : state_(0)
|
Chris@16
|
40 {
|
Chris@16
|
41 }
|
Chris@16
|
42
|
Chris@16
|
43 // Destructor.
|
Chris@16
|
44 ~std_event()
|
Chris@16
|
45 {
|
Chris@16
|
46 }
|
Chris@16
|
47
|
Chris@101
|
48 // Signal the event. (Retained for backward compatibility.)
|
Chris@16
|
49 template <typename Lock>
|
Chris@16
|
50 void signal(Lock& lock)
|
Chris@16
|
51 {
|
Chris@101
|
52 this->signal_all(lock);
|
Chris@101
|
53 }
|
Chris@101
|
54
|
Chris@101
|
55 // Signal all waiters.
|
Chris@101
|
56 template <typename Lock>
|
Chris@101
|
57 void signal_all(Lock& lock)
|
Chris@101
|
58 {
|
Chris@16
|
59 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@16
|
60 (void)lock;
|
Chris@101
|
61 state_ |= 1;
|
Chris@101
|
62 cond_.notify_all();
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@101
|
65 // Unlock the mutex and signal one waiter.
|
Chris@16
|
66 template <typename Lock>
|
Chris@101
|
67 void unlock_and_signal_one(Lock& lock)
|
Chris@16
|
68 {
|
Chris@16
|
69 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@101
|
70 state_ |= 1;
|
Chris@101
|
71 bool have_waiters = (state_ > 1);
|
Chris@16
|
72 lock.unlock();
|
Chris@101
|
73 if (have_waiters)
|
Chris@101
|
74 cond_.notify_one();
|
Chris@101
|
75 }
|
Chris@101
|
76
|
Chris@101
|
77 // If there's a waiter, unlock the mutex and signal it.
|
Chris@101
|
78 template <typename Lock>
|
Chris@101
|
79 bool maybe_unlock_and_signal_one(Lock& lock)
|
Chris@101
|
80 {
|
Chris@101
|
81 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@101
|
82 state_ |= 1;
|
Chris@101
|
83 if (state_ > 1)
|
Chris@101
|
84 {
|
Chris@101
|
85 lock.unlock();
|
Chris@101
|
86 cond_.notify_one();
|
Chris@101
|
87 return true;
|
Chris@101
|
88 }
|
Chris@101
|
89 return false;
|
Chris@16
|
90 }
|
Chris@16
|
91
|
Chris@16
|
92 // Reset the event.
|
Chris@16
|
93 template <typename Lock>
|
Chris@16
|
94 void clear(Lock& lock)
|
Chris@16
|
95 {
|
Chris@16
|
96 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@16
|
97 (void)lock;
|
Chris@101
|
98 state_ &= ~std::size_t(1);
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 // Wait for the event to become signalled.
|
Chris@16
|
102 template <typename Lock>
|
Chris@16
|
103 void wait(Lock& lock)
|
Chris@16
|
104 {
|
Chris@16
|
105 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@16
|
106 unique_lock_adapter u_lock(lock);
|
Chris@101
|
107 while ((state_ & 1) == 0)
|
Chris@101
|
108 {
|
Chris@101
|
109 waiter w(state_);
|
Chris@16
|
110 cond_.wait(u_lock.unique_lock_);
|
Chris@101
|
111 }
|
Chris@16
|
112 }
|
Chris@16
|
113
|
Chris@16
|
114 // Timed wait for the event to become signalled.
|
Chris@16
|
115 template <typename Lock>
|
Chris@16
|
116 bool wait_for_usec(Lock& lock, long usec)
|
Chris@16
|
117 {
|
Chris@16
|
118 BOOST_ASIO_ASSERT(lock.locked());
|
Chris@16
|
119 unique_lock_adapter u_lock(lock);
|
Chris@101
|
120 if ((state_ & 1) == 0)
|
Chris@101
|
121 {
|
Chris@101
|
122 waiter w(state_);
|
Chris@16
|
123 cond_.wait_for(u_lock.unique_lock_, std::chrono::microseconds(usec));
|
Chris@101
|
124 }
|
Chris@101
|
125 return (state_ & 1) != 0;
|
Chris@16
|
126 }
|
Chris@16
|
127
|
Chris@16
|
128 private:
|
Chris@16
|
129 // Helper class to temporarily adapt a scoped_lock into a unique_lock so that
|
Chris@16
|
130 // it can be passed to std::condition_variable::wait().
|
Chris@16
|
131 struct unique_lock_adapter
|
Chris@16
|
132 {
|
Chris@16
|
133 template <typename Lock>
|
Chris@16
|
134 explicit unique_lock_adapter(Lock& lock)
|
Chris@16
|
135 : unique_lock_(lock.mutex().mutex_, std::adopt_lock)
|
Chris@16
|
136 {
|
Chris@16
|
137 }
|
Chris@16
|
138
|
Chris@16
|
139 ~unique_lock_adapter()
|
Chris@16
|
140 {
|
Chris@16
|
141 unique_lock_.release();
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 std::unique_lock<std::mutex> unique_lock_;
|
Chris@16
|
145 };
|
Chris@16
|
146
|
Chris@101
|
147 // Helper to increment and decrement the state to track outstanding waiters.
|
Chris@101
|
148 class waiter
|
Chris@101
|
149 {
|
Chris@101
|
150 public:
|
Chris@101
|
151 explicit waiter(std::size_t& state)
|
Chris@101
|
152 : state_(state)
|
Chris@101
|
153 {
|
Chris@101
|
154 state_ += 2;
|
Chris@101
|
155 }
|
Chris@101
|
156
|
Chris@101
|
157 ~waiter()
|
Chris@101
|
158 {
|
Chris@101
|
159 state_ -= 2;
|
Chris@101
|
160 }
|
Chris@101
|
161
|
Chris@101
|
162 private:
|
Chris@101
|
163 std::size_t& state_;
|
Chris@101
|
164 };
|
Chris@101
|
165
|
Chris@16
|
166 std::condition_variable cond_;
|
Chris@101
|
167 std::size_t state_;
|
Chris@16
|
168 };
|
Chris@16
|
169
|
Chris@16
|
170 } // namespace detail
|
Chris@16
|
171 } // namespace asio
|
Chris@16
|
172 } // namespace boost
|
Chris@16
|
173
|
Chris@16
|
174 #include <boost/asio/detail/pop_options.hpp>
|
Chris@16
|
175
|
Chris@16
|
176 #endif // defined(BOOST_ASIO_HAS_STD_MUTEX_AND_CONDVAR)
|
Chris@16
|
177
|
Chris@16
|
178 #endif // BOOST_ASIO_DETAIL_STD_EVENT_HPP
|