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)
9 * \author Andrey Semashev
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.
16 #include <boost/log/detail/config.hpp>
18 #ifndef BOOST_LOG_NO_THREADS
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>
26 #if defined(BOOST_LOG_EVENT_USE_ATOMIC)
28 #include <boost/memory_order.hpp>
29 #include <boost/atomic/atomic.hpp>
30 #include <boost/atomic/fences.hpp>
32 #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
35 #include <semaphore.h>
36 #include <boost/memory_order.hpp>
37 #include <boost/atomic/fences.hpp>
39 #elif defined(BOOST_LOG_EVENT_USE_WINAPI)
42 #include <boost/memory_order.hpp>
43 #include <boost/atomic/atomic.hpp>
44 #include <boost/atomic/fences.hpp>
48 #include <boost/thread/locks.hpp>
52 #include <boost/log/detail/header.hpp>
56 BOOST_LOG_OPEN_NAMESPACE
60 #if defined(BOOST_LOG_EVENT_USE_ATOMIC)
62 //! Waits for the object to become signalled
63 BOOST_LOG_API
void atomic_based_event::wait()
65 while (m_state
.exchange(0u, boost::memory_order_acq_rel
) == 0u)
67 m_state
.wait(0u, boost::memory_order_relaxed
);
71 //! Sets the object to a signalled state
72 BOOST_LOG_API
void atomic_based_event::set_signalled()
74 if (m_state
.load(boost::memory_order_relaxed
) != 0u)
76 boost::atomic_thread_fence(boost::memory_order_release
);
78 else if (m_state
.exchange(1u, boost::memory_order_release
) == 0u)
84 #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
86 //! Default constructor
87 BOOST_LOG_API
sem_based_event::sem_based_event() : m_state()
89 if (BOOST_UNLIKELY(sem_init(&m_semaphore
, 0, 0) != 0))
91 const int err
= errno
;
92 BOOST_LOG_THROW_DESCR_PARAMS(system_error
, "Failed to initialize semaphore", (err
));
97 BOOST_LOG_API
sem_based_event::~sem_based_event()
99 BOOST_VERIFY(sem_destroy(&m_semaphore
) == 0);
102 //! Waits for the object to become signalled
103 BOOST_LOG_API
void sem_based_event::wait()
105 boost::atomic_thread_fence(boost::memory_order_acq_rel
);
108 if (sem_wait(&m_semaphore
) != 0)
110 const int err
= errno
;
111 if (BOOST_UNLIKELY(err
!= EINTR
))
113 BOOST_LOG_THROW_DESCR_PARAMS(system_error
, "Failed to block on the semaphore", (err
));
119 m_state
.clear(boost::memory_order_relaxed
);
122 //! Sets the object to a signalled state
123 BOOST_LOG_API
void sem_based_event::set_signalled()
125 if (!m_state
.test_and_set(boost::memory_order_release
))
127 if (BOOST_UNLIKELY(sem_post(&m_semaphore
) != 0))
129 const int err
= errno
;
130 BOOST_LOG_THROW_DESCR_PARAMS(system_error
, "Failed to wake the blocked thread", (err
));
135 #elif defined(BOOST_LOG_EVENT_USE_WINAPI)
137 //! Default constructor
138 BOOST_LOG_API
winapi_based_event::winapi_based_event() :
142 if (!m_state
.has_native_wait_notify())
144 m_event
= CreateEventA(NULL
, false, false, NULL
);
145 if (BOOST_UNLIKELY(!m_event
))
147 const DWORD err
= GetLastError();
148 BOOST_LOG_THROW_DESCR_PARAMS(system_error
, "Failed to create Windows event", (err
));
154 BOOST_LOG_API
winapi_based_event::~winapi_based_event()
158 BOOST_VERIFY(CloseHandle(m_event
) != 0);
162 //! Waits for the object to become signalled
163 BOOST_LOG_API
void winapi_based_event::wait()
167 while (m_state
.exchange(0u, boost::memory_order_acq_rel
) == 0u)
169 m_state
.wait(0u, boost::memory_order_relaxed
);
174 while (m_state
.exchange(0u, boost::memory_order_acq_rel
) == 0u)
176 if (BOOST_UNLIKELY(WaitForSingleObject(m_event
, INFINITE
) != 0))
178 const DWORD err
= GetLastError();
179 BOOST_LOG_THROW_DESCR_PARAMS(system_error
, "Failed to block on Windows event", (err
));
185 //! Sets the object to a signalled state
186 BOOST_LOG_API
void winapi_based_event::set_signalled()
188 if (m_state
.load(boost::memory_order_relaxed
) != 0u)
190 boost::atomic_thread_fence(boost::memory_order_release
);
192 else if (m_state
.exchange(1u, boost::memory_order_release
) == 0u)
196 m_state
.notify_one();
200 if (BOOST_UNLIKELY(SetEvent(m_event
) == 0))
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
));
212 //! Default constructor
213 BOOST_LOG_API
generic_event::generic_event() : m_state(false)
218 BOOST_LOG_API
generic_event::~generic_event()
222 //! Waits for the object to become signalled
223 BOOST_LOG_API
void generic_event::wait()
225 boost::unique_lock
< boost::mutex
> lock(m_mutex
);
233 //! Sets the object to a signalled state
234 BOOST_LOG_API
void generic_event::set_signalled()
236 boost::lock_guard
< boost::mutex
> lock(m_mutex
);
248 BOOST_LOG_CLOSE_NAMESPACE
// namespace log
252 #include <boost/log/detail/footer.hpp>
254 #endif // BOOST_LOG_NO_THREADS