/* * Copyright Andrey Semashev 2007 - 2013. * 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) */ /*! * \file event.cpp * \author Andrey Semashev * \date 24.07.2011 * * \brief This header is the Boost.Log library implementation, see the library documentation * at http://www.boost.org/libs/log/doc/log.html. */ #include #ifndef BOOST_LOG_NO_THREADS #include #include #include #include #include #if defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) #if defined(__GNUC__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) #define BOOST_LOG_EVENT_TRY_SET(ref) (__sync_lock_test_and_set(&ref, 1U) == 0U) #define BOOST_LOG_EVENT_RESET(ref) __sync_lock_release(&ref) #else #error Boost.Log internal error: BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE must only be defined when atomic ops are available #endif #include #include #elif defined(BOOST_LOG_EVENT_USE_WINAPI) #include "windows_version.hpp" #include #include #else #include #endif #include namespace boost { BOOST_LOG_OPEN_NAMESPACE namespace aux { #if defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) //! Default constructor BOOST_LOG_API sem_based_event::sem_based_event() : m_state(0U) { if (sem_init(&m_semaphore, 0, 0) != 0) { BOOST_THROW_EXCEPTION(system::system_error( errno, system::system_category(), "Failed to initialize semaphore")); } } //! Destructor BOOST_LOG_API sem_based_event::~sem_based_event() { sem_destroy(&m_semaphore); } //! Waits for the object to become signalled BOOST_LOG_API void sem_based_event::wait() { while (true) { if (sem_wait(&m_semaphore) != 0) { if (errno != EINTR) { BOOST_THROW_EXCEPTION(system::system_error( errno, system::system_category(), "Failed to block on the semaphore")); } } else break; } BOOST_LOG_EVENT_RESET(m_state); } //! Sets the object to a signalled state BOOST_LOG_API void sem_based_event::set_signalled() { if (BOOST_LOG_EVENT_TRY_SET(m_state)) { if (sem_post(&m_semaphore) != 0) { BOOST_LOG_EVENT_RESET(m_state); BOOST_THROW_EXCEPTION(system::system_error( errno, system::system_category(), "Failed to wake the blocked thread")); } } } #elif defined(BOOST_LOG_EVENT_USE_WINAPI) //! Default constructor BOOST_LOG_API winapi_based_event::winapi_based_event() : m_state(0), m_event(CreateEventA(NULL, false, false, NULL)) { if (!m_event) { BOOST_THROW_EXCEPTION(system::system_error( GetLastError(), system::system_category(), "Failed to create Windows event")); } } //! Destructor BOOST_LOG_API winapi_based_event::~winapi_based_event() { CloseHandle(m_event); } //! 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 (WaitForSingleObject(m_event, INFINITE) != 0) { BOOST_THROW_EXCEPTION(system::system_error( GetLastError(), system::system_category(), "Failed to block on Windows event")); } } 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 (SetEvent(m_event) == 0) { const_cast< volatile boost::uint32_t& >(m_state) = 0; BOOST_THROW_EXCEPTION(system::system_error( GetLastError(), system::system_category(), "Failed to wake the blocked thread")); } } } #else //! Default constructor BOOST_LOG_API generic_event::generic_event() : m_state(false) { } //! Destructor BOOST_LOG_API generic_event::~generic_event() { } //! Waits for the object to become signalled BOOST_LOG_API void generic_event::wait() { boost::unique_lock< boost::mutex > lock(m_mutex); while (!m_state) { m_cond.wait(lock); } m_state = false; } //! Sets the object to a signalled state BOOST_LOG_API void generic_event::set_signalled() { boost::lock_guard< boost::mutex > lock(m_mutex); if (!m_state) { m_state = true; m_cond.notify_one(); } } #endif } // namespace aux BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost #include #endif // BOOST_LOG_NO_THREADS