]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | /* |
1e59de90 | 2 | * Copyright Andrey Semashev 2007 - 2021. |
7c673cae FG |
3 | * Distributed under the Boost Software License, Version 1.0. |
4 | * (See accompanying file LICENSE_1_0.txt or copy at | |
5 | * http://www.boost.org/LICENSE_1_0.txt) | |
6 | */ | |
7 | /*! | |
8 | * \file event.cpp | |
9 | * \author Andrey Semashev | |
10 | * \date 24.07.2011 | |
11 | * | |
12 | * \brief This header is the Boost.Log library implementation, see the library documentation | |
13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. | |
14 | */ | |
15 | ||
16 | #include <boost/log/detail/config.hpp> | |
17 | ||
18 | #ifndef BOOST_LOG_NO_THREADS | |
19 | ||
20 | #include <boost/assert.hpp> | |
21 | #include <boost/cstdint.hpp> | |
22 | #include <boost/throw_exception.hpp> | |
23 | #include <boost/log/detail/event.hpp> | |
24 | #include <boost/log/exceptions.hpp> | |
25 | ||
1e59de90 | 26 | #if defined(BOOST_LOG_EVENT_USE_ATOMIC) |
7c673cae | 27 | |
7c673cae | 28 | #include <boost/memory_order.hpp> |
1e59de90 TL |
29 | #include <boost/atomic/atomic.hpp> |
30 | #include <boost/atomic/fences.hpp> | |
7c673cae FG |
31 | |
32 | #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) | |
33 | ||
34 | #include <errno.h> | |
35 | #include <semaphore.h> | |
36 | #include <boost/memory_order.hpp> | |
37 | #include <boost/atomic/fences.hpp> | |
38 | ||
39 | #elif defined(BOOST_LOG_EVENT_USE_WINAPI) | |
40 | ||
41 | #include <windows.h> | |
1e59de90 TL |
42 | #include <boost/memory_order.hpp> |
43 | #include <boost/atomic/atomic.hpp> | |
44 | #include <boost/atomic/fences.hpp> | |
7c673cae FG |
45 | |
46 | #else | |
47 | ||
48 | #include <boost/thread/locks.hpp> | |
49 | ||
50 | #endif | |
51 | ||
52 | #include <boost/log/detail/header.hpp> | |
53 | ||
54 | namespace boost { | |
55 | ||
56 | BOOST_LOG_OPEN_NAMESPACE | |
57 | ||
58 | namespace aux { | |
59 | ||
1e59de90 | 60 | #if defined(BOOST_LOG_EVENT_USE_ATOMIC) |
7c673cae FG |
61 | |
62 | //! Waits for the object to become signalled | |
1e59de90 | 63 | BOOST_LOG_API void atomic_based_event::wait() |
7c673cae | 64 | { |
1e59de90 | 65 | while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) |
7c673cae | 66 | { |
1e59de90 | 67 | m_state.wait(0u, boost::memory_order_relaxed); |
7c673cae FG |
68 | } |
69 | } | |
70 | ||
71 | //! Sets the object to a signalled state | |
1e59de90 | 72 | BOOST_LOG_API void atomic_based_event::set_signalled() |
7c673cae | 73 | { |
1e59de90 | 74 | if (m_state.load(boost::memory_order_relaxed) != 0u) |
7c673cae | 75 | { |
1e59de90 TL |
76 | boost::atomic_thread_fence(boost::memory_order_release); |
77 | } | |
78 | else if (m_state.exchange(1u, boost::memory_order_release) == 0u) | |
79 | { | |
80 | m_state.notify_one(); | |
7c673cae FG |
81 | } |
82 | } | |
83 | ||
84 | #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) | |
85 | ||
86 | //! Default constructor | |
87 | BOOST_LOG_API sem_based_event::sem_based_event() : m_state() | |
88 | { | |
89 | if (BOOST_UNLIKELY(sem_init(&m_semaphore, 0, 0) != 0)) | |
90 | { | |
91 | const int err = errno; | |
92 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize semaphore", (err)); | |
93 | } | |
94 | } | |
95 | ||
96 | //! Destructor | |
97 | BOOST_LOG_API sem_based_event::~sem_based_event() | |
98 | { | |
99 | BOOST_VERIFY(sem_destroy(&m_semaphore) == 0); | |
100 | } | |
101 | ||
102 | //! Waits for the object to become signalled | |
103 | BOOST_LOG_API void sem_based_event::wait() | |
104 | { | |
105 | boost::atomic_thread_fence(boost::memory_order_acq_rel); | |
106 | while (true) | |
107 | { | |
108 | if (sem_wait(&m_semaphore) != 0) | |
109 | { | |
110 | const int err = errno; | |
111 | if (BOOST_UNLIKELY(err != EINTR)) | |
112 | { | |
113 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the semaphore", (err)); | |
114 | } | |
115 | } | |
116 | else | |
117 | break; | |
118 | } | |
119 | m_state.clear(boost::memory_order_relaxed); | |
120 | } | |
121 | ||
122 | //! Sets the object to a signalled state | |
123 | BOOST_LOG_API void sem_based_event::set_signalled() | |
124 | { | |
125 | if (!m_state.test_and_set(boost::memory_order_release)) | |
126 | { | |
127 | if (BOOST_UNLIKELY(sem_post(&m_semaphore) != 0)) | |
128 | { | |
129 | const int err = errno; | |
130 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
135 | #elif defined(BOOST_LOG_EVENT_USE_WINAPI) | |
136 | ||
137 | //! Default constructor | |
138 | BOOST_LOG_API winapi_based_event::winapi_based_event() : | |
1e59de90 TL |
139 | m_state(0u), |
140 | m_event(NULL) | |
7c673cae | 141 | { |
1e59de90 | 142 | if (!m_state.has_native_wait_notify()) |
7c673cae | 143 | { |
1e59de90 TL |
144 | m_event = CreateEventA(NULL, false, false, NULL); |
145 | if (BOOST_UNLIKELY(!m_event)) | |
146 | { | |
147 | const DWORD err = GetLastError(); | |
148 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err)); | |
149 | } | |
7c673cae FG |
150 | } |
151 | } | |
152 | ||
153 | //! Destructor | |
154 | BOOST_LOG_API winapi_based_event::~winapi_based_event() | |
155 | { | |
1e59de90 TL |
156 | if (!!m_event) |
157 | { | |
158 | BOOST_VERIFY(CloseHandle(m_event) != 0); | |
159 | } | |
7c673cae FG |
160 | } |
161 | ||
162 | //! Waits for the object to become signalled | |
163 | BOOST_LOG_API void winapi_based_event::wait() | |
164 | { | |
1e59de90 | 165 | if (!m_event) |
7c673cae | 166 | { |
1e59de90 | 167 | while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) |
7c673cae | 168 | { |
1e59de90 TL |
169 | m_state.wait(0u, boost::memory_order_relaxed); |
170 | } | |
171 | } | |
172 | else | |
173 | { | |
174 | while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) | |
175 | { | |
176 | if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0)) | |
177 | { | |
178 | const DWORD err = GetLastError(); | |
179 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err)); | |
180 | } | |
7c673cae FG |
181 | } |
182 | } | |
7c673cae FG |
183 | } |
184 | ||
185 | //! Sets the object to a signalled state | |
186 | BOOST_LOG_API void winapi_based_event::set_signalled() | |
187 | { | |
1e59de90 TL |
188 | if (m_state.load(boost::memory_order_relaxed) != 0u) |
189 | { | |
190 | boost::atomic_thread_fence(boost::memory_order_release); | |
191 | } | |
192 | else if (m_state.exchange(1u, boost::memory_order_release) == 0u) | |
7c673cae | 193 | { |
1e59de90 | 194 | if (!m_event) |
7c673cae | 195 | { |
1e59de90 TL |
196 | m_state.notify_one(); |
197 | } | |
198 | else | |
199 | { | |
200 | if (BOOST_UNLIKELY(SetEvent(m_event) == 0)) | |
201 | { | |
202 | const DWORD err = GetLastError(); | |
203 | m_state.store(0u, boost::memory_order_relaxed); | |
204 | BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); | |
205 | } | |
7c673cae FG |
206 | } |
207 | } | |
208 | } | |
209 | ||
210 | #else | |
211 | ||
212 | //! Default constructor | |
213 | BOOST_LOG_API generic_event::generic_event() : m_state(false) | |
214 | { | |
215 | } | |
216 | ||
217 | //! Destructor | |
218 | BOOST_LOG_API generic_event::~generic_event() | |
219 | { | |
220 | } | |
221 | ||
222 | //! Waits for the object to become signalled | |
223 | BOOST_LOG_API void generic_event::wait() | |
224 | { | |
225 | boost::unique_lock< boost::mutex > lock(m_mutex); | |
226 | while (!m_state) | |
227 | { | |
228 | m_cond.wait(lock); | |
229 | } | |
230 | m_state = false; | |
231 | } | |
232 | ||
233 | //! Sets the object to a signalled state | |
234 | BOOST_LOG_API void generic_event::set_signalled() | |
235 | { | |
236 | boost::lock_guard< boost::mutex > lock(m_mutex); | |
237 | if (!m_state) | |
238 | { | |
239 | m_state = true; | |
240 | m_cond.notify_one(); | |
241 | } | |
242 | } | |
243 | ||
244 | #endif | |
245 | ||
246 | } // namespace aux | |
247 | ||
248 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
249 | ||
250 | } // namespace boost | |
251 | ||
252 | #include <boost/log/detail/footer.hpp> | |
253 | ||
254 | #endif // BOOST_LOG_NO_THREADS |