blob: ce2a9bb44ee02c07b47314145e771dcf7b2b602f [file] [log] [blame] [edit]
/*
* Copyright Andrey Semashev 2007 - 2015.
* 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/doc/libs/release/libs/log/doc/html/index.html.
*/
#include <boost/log/detail/config.hpp>
#ifndef BOOST_LOG_NO_THREADS
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/throw_exception.hpp>
#include <boost/system/error_code.hpp>
#include <boost/system/system_error.hpp>
#include <boost/log/detail/event.hpp>
#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 <errno.h>
#include <semaphore.h>
#elif defined(BOOST_LOG_EVENT_USE_WINAPI)
#include "windows_version.hpp"
#include <windows.h>
#include <boost/detail/interlocked.hpp>
#else
#include <boost/thread/locks.hpp>
#endif
#include <boost/log/detail/header.hpp>
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)
{
const int err = errno;
BOOST_THROW_EXCEPTION(system::system_error(
err, system::system_category(), "Failed to initialize semaphore"));
}
}
//! Destructor
BOOST_LOG_API sem_based_event::~sem_based_event()
{
BOOST_VERIFY(sem_destroy(&m_semaphore) == 0);
}
//! Waits for the object to become signalled
BOOST_LOG_API void sem_based_event::wait()
{
while (true)
{
if (sem_wait(&m_semaphore) != 0)
{
const int err = errno;
if (err != EINTR)
{
BOOST_THROW_EXCEPTION(system::system_error(
err, 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)
{
const int err = errno;
BOOST_LOG_EVENT_RESET(m_state);
BOOST_THROW_EXCEPTION(system::system_error(
err, 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)
{
const DWORD err = GetLastError();
BOOST_THROW_EXCEPTION(system::system_error(
err, system::system_category(), "Failed to create Windows event"));
}
}
//! Destructor
BOOST_LOG_API winapi_based_event::~winapi_based_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 (WaitForSingleObject(m_event, INFINITE) != 0)
{
const DWORD err = GetLastError();
BOOST_THROW_EXCEPTION(system::system_error(
err, 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 DWORD err = GetLastError();
const_cast< volatile boost::uint32_t& >(m_state) = 0;
BOOST_THROW_EXCEPTION(system::system_error(
err, 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 <boost/log/detail/footer.hpp>
#endif // BOOST_LOG_NO_THREADS