/*
- * Copyright Andrey Semashev 2007 - 2015.
+ * Copyright Andrey Semashev 2007 - 2021.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
#include <boost/log/detail/event.hpp>
#include <boost/log/exceptions.hpp>
-#if defined(BOOST_LOG_EVENT_USE_FUTEX)
+#if defined(BOOST_LOG_EVENT_USE_ATOMIC)
-#include <stddef.h>
-#include <errno.h>
-#include <sys/syscall.h>
-#include <linux/futex.h>
#include <boost/memory_order.hpp>
-
-// Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex
-#if defined(SYS_futex)
-#define BOOST_LOG_SYS_FUTEX SYS_futex
-#else
-#define BOOST_LOG_SYS_FUTEX __NR_futex
-#endif
-
-#if defined(FUTEX_WAIT_PRIVATE)
-#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT_PRIVATE
-#else
-#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT
-#endif
-
-#if defined(FUTEX_WAKE_PRIVATE)
-#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE_PRIVATE
-#else
-#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE
-#endif
+#include <boost/atomic/atomic.hpp>
+#include <boost/atomic/fences.hpp>
#elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE)
#elif defined(BOOST_LOG_EVENT_USE_WINAPI)
#include <windows.h>
-#include <boost/detail/interlocked.hpp>
+#include <boost/memory_order.hpp>
+#include <boost/atomic/atomic.hpp>
+#include <boost/atomic/fences.hpp>
#else
namespace aux {
-#if defined(BOOST_LOG_EVENT_USE_FUTEX)
-
-//! Default constructor
-BOOST_LOG_API futex_based_event::futex_based_event() : m_state(0)
-{
-}
-
-//! Destructor
-BOOST_LOG_API futex_based_event::~futex_based_event()
-{
-}
+#if defined(BOOST_LOG_EVENT_USE_ATOMIC)
//! Waits for the object to become signalled
-BOOST_LOG_API void futex_based_event::wait()
+BOOST_LOG_API void atomic_based_event::wait()
{
- if (m_state.exchange(0, boost::memory_order_acq_rel) == 0)
+ while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u)
{
- while (true)
- {
- if (::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAIT, 0, NULL, NULL, 0) == 0)
- {
- // Another thread has set the event while sleeping
- break;
- }
-
- const int err = errno;
- if (err == EWOULDBLOCK)
- {
- // Another thread has set the event before sleeping
- break;
- }
- else if (BOOST_UNLIKELY(err != EINTR))
- {
- BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the futex", (err));
- }
- }
-
- m_state.store(0, boost::memory_order_relaxed);
+ m_state.wait(0u, boost::memory_order_relaxed);
}
}
//! Sets the object to a signalled state
-BOOST_LOG_API void futex_based_event::set_signalled()
+BOOST_LOG_API void atomic_based_event::set_signalled()
{
- if (m_state.exchange(1, boost::memory_order_release) == 0)
+ if (m_state.load(boost::memory_order_relaxed) != 0u)
{
- if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0))
- {
- const int err = errno;
- BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake threads blocked on the futex", (err));
- }
+ boost::atomic_thread_fence(boost::memory_order_release);
+ }
+ else if (m_state.exchange(1u, boost::memory_order_release) == 0u)
+ {
+ m_state.notify_one();
}
}
//! Default constructor
BOOST_LOG_API winapi_based_event::winapi_based_event() :
- m_state(0),
- m_event(CreateEventA(NULL, false, false, NULL))
+ m_state(0u),
+ m_event(NULL)
{
- if (BOOST_UNLIKELY(!m_event))
+ if (!m_state.has_native_wait_notify())
{
- const DWORD err = GetLastError();
- BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err));
+ m_event = CreateEventA(NULL, false, false, NULL);
+ if (BOOST_UNLIKELY(!m_event))
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err));
+ }
}
}
//! Destructor
BOOST_LOG_API winapi_based_event::~winapi_based_event()
{
- BOOST_VERIFY(CloseHandle(m_event) != 0);
+ if (!!m_event)
+ {
+ BOOST_VERIFY(CloseHandle(m_event) != 0);
+ }
}
//! Waits for the object to become signalled
BOOST_LOG_API void winapi_based_event::wait()
{
- // On Windows we assume that memory view is always actual (Intel x86 and x86_64 arch)
- if (const_cast< volatile boost::uint32_t& >(m_state) == 0)
+ if (!m_event)
{
- if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0))
+ while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u)
{
- const DWORD err = GetLastError();
- BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err));
+ m_state.wait(0u, boost::memory_order_relaxed);
+ }
+ }
+ else
+ {
+ while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u)
+ {
+ if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0))
+ {
+ const DWORD err = GetLastError();
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err));
+ }
}
}
- const_cast< volatile boost::uint32_t& >(m_state) = 0;
}
//! Sets the object to a signalled state
BOOST_LOG_API void winapi_based_event::set_signalled()
{
- if (BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast< long* >(&m_state), 1, 0) == 0)
+ if (m_state.load(boost::memory_order_relaxed) != 0u)
+ {
+ boost::atomic_thread_fence(boost::memory_order_release);
+ }
+ else if (m_state.exchange(1u, boost::memory_order_release) == 0u)
{
- if (BOOST_UNLIKELY(SetEvent(m_event) == 0))
+ if (!m_event)
{
- const DWORD err = GetLastError();
- const_cast< volatile boost::uint32_t& >(m_state) = 0;
- BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err));
+ m_state.notify_one();
+ }
+ else
+ {
+ if (BOOST_UNLIKELY(SetEvent(m_event) == 0))
+ {
+ const DWORD err = GetLastError();
+ m_state.store(0u, boost::memory_order_relaxed);
+ BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err));
+ }
}
}
}