1/*
2 * Copyright Andrey Semashev 2007 - 2021.
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
26#if defined(BOOST_LOG_EVENT_USE_ATOMIC)
27
28#include <boost/memory_order.hpp>
29#include <boost/atomic/atomic.hpp>
30#include <boost/atomic/fences.hpp>
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>
42#include <boost/memory_order.hpp>
43#include <boost/atomic/atomic.hpp>
44#include <boost/atomic/fences.hpp>
45
46#else
47
48#include <boost/thread/locks.hpp>
49
50#endif
51
52#include <boost/log/detail/header.hpp>
53
54namespace boost {
55
56BOOST_LOG_OPEN_NAMESPACE
57
58namespace aux {
59
60#if defined(BOOST_LOG_EVENT_USE_ATOMIC)
61
62//! Waits for the object to become signalled
63BOOST_LOG_API void atomic_based_event::wait()
64{
65 while (m_state.exchange(v: 0u, order: boost::memory_order_acq_rel) == 0u)
66 {
67 m_state.wait(old_val: 0u, order: boost::memory_order_relaxed);
68 }
69}
70
71//! Sets the object to a signalled state
72BOOST_LOG_API void atomic_based_event::set_signalled()
73{
74 if (m_state.load(order: boost::memory_order_relaxed) != 0u)
75 {
76 boost::atomic_thread_fence(order: boost::memory_order_release);
77 }
78 else if (m_state.exchange(v: 1u, order: boost::memory_order_release) == 0u)
79 {
80 m_state.notify_one();
81 }
82}
83
84#elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
85
86//! Default constructor
87BOOST_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
97BOOST_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
103BOOST_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
123BOOST_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
138BOOST_LOG_API winapi_based_event::winapi_based_event() :
139 m_state(0u),
140 m_event(NULL)
141{
142 if (!m_state.has_native_wait_notify())
143 {
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 }
150 }
151}
152
153//! Destructor
154BOOST_LOG_API winapi_based_event::~winapi_based_event()
155{
156 if (!!m_event)
157 {
158 BOOST_VERIFY(CloseHandle(m_event) != 0);
159 }
160}
161
162//! Waits for the object to become signalled
163BOOST_LOG_API void winapi_based_event::wait()
164{
165 if (!m_event)
166 {
167 while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u)
168 {
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 }
181 }
182 }
183}
184
185//! Sets the object to a signalled state
186BOOST_LOG_API void winapi_based_event::set_signalled()
187{
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)
193 {
194 if (!m_event)
195 {
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 }
206 }
207 }
208}
209
210#else
211
212//! Default constructor
213BOOST_LOG_API generic_event::generic_event() : m_state(false)
214{
215}
216
217//! Destructor
218BOOST_LOG_API generic_event::~generic_event()
219{
220}
221
222//! Waits for the object to become signalled
223BOOST_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
234BOOST_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
248BOOST_LOG_CLOSE_NAMESPACE // namespace log
249
250} // namespace boost
251
252#include <boost/log/detail/footer.hpp>
253
254#endif // BOOST_LOG_NO_THREADS
255

source code of boost/libs/log/src/event.cpp