Chris@16: /* Chris@101: * Copyright Andrey Semashev 2007 - 2015. Chris@16: * Distributed under the Boost Software License, Version 1.0. Chris@16: * (See accompanying file LICENSE_1_0.txt or copy at Chris@16: * http://www.boost.org/LICENSE_1_0.txt) Chris@16: */ Chris@16: /*! Chris@16: * \file once_block.hpp Chris@16: * \author Andrey Semashev Chris@16: * \date 23.06.2010 Chris@16: * Chris@16: * \brief The header defines classes and macros for once-blocks. Chris@16: */ Chris@16: Chris@16: #ifndef BOOST_LOG_UTILITY_ONCE_BLOCK_HPP_INCLUDED_ Chris@16: #define BOOST_LOG_UTILITY_ONCE_BLOCK_HPP_INCLUDED_ Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_HAS_PRAGMA_ONCE Chris@16: #pragma once Chris@16: #endif Chris@16: Chris@16: #ifndef BOOST_LOG_NO_THREADS Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: /*! Chris@16: * \brief A flag to detect if a code block has already been executed. Chris@16: * Chris@16: * This structure should be used in conjunction with the \c BOOST_LOG_ONCE_BLOCK_FLAG Chris@16: * macro. Usage example: Chris@16: * Chris@16: * Chris@16: * once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT; Chris@16: * Chris@16: * void foo() Chris@16: * { Chris@16: * BOOST_LOG_ONCE_BLOCK_FLAG(flag) Chris@16: * { Chris@16: * puts("Hello, world once!"); Chris@16: * } Chris@16: * } Chris@16: * Chris@16: */ Chris@16: struct once_block_flag Chris@16: { Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: // Do not use, implementation detail Chris@16: enum Chris@16: { Chris@16: uninitialized = 0, // this must be zero, so that zero-initialized once_block_flag is equivalent to the one initialized with uninitialized Chris@16: being_initialized, Chris@16: initialized Chris@16: }; Chris@16: unsigned char status; Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: }; Chris@16: Chris@16: /*! Chris@16: * \def BOOST_LOG_ONCE_BLOCK_INIT Chris@16: * Chris@16: * The static initializer for \c once_block_flag. Chris@16: */ Chris@16: #define BOOST_LOG_ONCE_BLOCK_INIT { boost::log::once_block_flag::uninitialized } Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: class once_block_sentry Chris@16: { Chris@16: private: Chris@16: once_block_flag& m_flag; Chris@16: Chris@16: public: Chris@16: explicit once_block_sentry(once_block_flag& f) BOOST_NOEXCEPT : m_flag(f) Chris@16: { Chris@16: } Chris@16: Chris@16: ~once_block_sentry() BOOST_NOEXCEPT Chris@16: { Chris@16: if (m_flag.status != once_block_flag::initialized) Chris@16: rollback(); Chris@16: } Chris@16: Chris@16: bool executed() const BOOST_NOEXCEPT Chris@16: { Chris@16: return (m_flag.status == once_block_flag::initialized || enter_once_block()); Chris@16: } Chris@16: Chris@16: BOOST_LOG_API void commit() BOOST_NOEXCEPT; Chris@16: Chris@16: private: Chris@16: BOOST_LOG_API bool enter_once_block() const BOOST_NOEXCEPT; Chris@16: BOOST_LOG_API void rollback() BOOST_NOEXCEPT; Chris@16: Chris@16: // Non-copyable, non-assignable Chris@16: BOOST_DELETED_FUNCTION(once_block_sentry(once_block_sentry const&)) Chris@16: BOOST_DELETED_FUNCTION(once_block_sentry& operator= (once_block_sentry const&)) Chris@16: }; Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #else // BOOST_LOG_NO_THREADS Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: BOOST_LOG_OPEN_NAMESPACE Chris@16: Chris@16: struct once_block_flag Chris@16: { Chris@16: bool status; Chris@16: }; Chris@16: Chris@16: #define BOOST_LOG_ONCE_BLOCK_INIT { false } Chris@16: Chris@16: namespace aux { Chris@16: Chris@16: class once_block_sentry Chris@16: { Chris@16: private: Chris@16: once_block_flag& m_flag; Chris@16: Chris@16: public: Chris@16: explicit once_block_sentry(once_block_flag& f) BOOST_NOEXCEPT : m_flag(f) Chris@16: { Chris@16: } Chris@16: Chris@16: bool executed() const BOOST_NOEXCEPT Chris@16: { Chris@16: return m_flag.status; Chris@16: } Chris@16: Chris@16: void commit() BOOST_NOEXCEPT Chris@16: { Chris@16: m_flag.status = true; Chris@16: } Chris@16: Chris@16: // Non-copyable, non-assignable Chris@16: BOOST_DELETED_FUNCTION(once_block_sentry(once_block_sentry const&)) Chris@16: BOOST_DELETED_FUNCTION(once_block_sentry& operator= (once_block_sentry const&)) Chris@16: }; Chris@16: Chris@16: } // namespace aux Chris@16: Chris@16: BOOST_LOG_CLOSE_NAMESPACE // namespace log Chris@16: Chris@16: } // namespace boost Chris@16: Chris@16: #endif // BOOST_LOG_NO_THREADS Chris@16: Chris@16: #ifndef BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: #define BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(flag_var, sentry_var)\ Chris@16: for (boost::log::aux::once_block_sentry sentry_var((flag_var));\ Chris@16: BOOST_UNLIKELY(!sentry_var.executed()); sentry_var.commit()) Chris@16: Chris@16: // NOTE: flag_var deliberately doesn't have an initializer so that it is zero-initialized at the static initialization stage Chris@16: #define BOOST_LOG_ONCE_BLOCK_INTERNAL(flag_var, sentry_var)\ Chris@16: static boost::log::once_block_flag flag_var;\ Chris@16: BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(flag_var, sentry_var) Chris@16: Chris@16: #endif // BOOST_LOG_DOXYGEN_PASS Chris@16: Chris@16: /*! Chris@16: * \def BOOST_LOG_ONCE_BLOCK_FLAG(flag_var) Chris@16: * Chris@16: * Begins a code block to be executed only once, with protection against thread concurrency. Chris@16: * User has to provide the flag variable that controls whether the block has already Chris@16: * been executed. Chris@16: */ Chris@16: #define BOOST_LOG_ONCE_BLOCK_FLAG(flag_var)\ Chris@16: BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(\ Chris@16: flag_var,\ Chris@16: BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_once_block_sentry_)) Chris@16: Chris@16: /*! Chris@16: * \def BOOST_LOG_ONCE_BLOCK() Chris@16: * Chris@16: * Begins a code block to be executed only once, with protection against thread concurrency. Chris@16: */ Chris@16: #define BOOST_LOG_ONCE_BLOCK()\ Chris@16: BOOST_LOG_ONCE_BLOCK_INTERNAL(\ Chris@16: BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_once_block_flag_),\ Chris@16: BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_once_block_sentry_)) Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // BOOST_LOG_UTILITY_ONCE_BLOCK_HPP_INCLUDED_