diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index d2c13ec..4919232 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -344,6 +344,7 @@ local BOOST_LOG_SETUP_COMMON_SRC = filter_parser.cpp formatter_parser.cpp default_filter_factory.cpp + default_formatter_factory.cpp ; lib boost_log_setup diff --git a/doc/attributes.qbk b/doc/attributes.qbk index b2b4a4e..8316dbd 100644 --- a/doc/attributes.qbk +++ b/doc/attributes.qbk @@ -296,7 +296,7 @@ Another good use case is attaching the scope stack information to an exception. [note In order this code to compile, the __boost_exception__ support header has to be included.] -[note We do not inject the [class_attributes_named_scope] attribute into the exception. Since scope stacks are maintained globally, throwing an exception will cause stack unwinding and, as a result, will truncate the global stack. Instead we create a copy of the scope stack bu calling [funcref boost::log::current_scope `current_scope`] at the throw site. This copy will be kept intact even if the global stack instance changes during the stack unwinding.] +[note We do not inject the [class_attributes_named_scope] attribute into the exception. Since scope stacks are maintained globally, throwing an exception will cause stack unwinding and, as a result, will truncate the global stack. Instead we create a copy of the scope stack by calling [funcref boost::log::current_scope `current_scope`] at the throw site. This copy will be kept intact even if the global stack instance changes during the stack unwinding.] [endsect] diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 0d04941..f37bc0e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.2, Boost 1.55] + +[*General changes:] + +* Added a new configuration macro `BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`. By defining this macro the user can disable compilation of the default filter and formatter factories used by settings parsers. This can substantially reduce binary sizes while still retaining support for settings parsers. Note that when this macro is defined the user will have to register _all_ attributes in the library. + [heading 2.1, Boost 1.54] [*Breaking changes:] diff --git a/doc/log.qbk b/doc/log.qbk index 5c7630b..f2bb6ad 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -1,6 +1,6 @@ [library Boost.Log [quickbook 1.5] - [version 2.0] + [version v2] [authors [Semashev, Andrey]] [copyright 2007 - 2013 Andrey Semashev] [license @@ -200,6 +200,7 @@ The library supports a number of configuration macros: [[`BOOST_LOG_WITHOUT_WCHAR_T`] [If defined, disables support for wide character logging. Affects the compilation of both the library and users' code.]] [[`BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER`] [This macro is only useful on Windows. It affects the compilation of both the library and users' code. If defined, disables support for the `QueryPerformanceCounter` API in the `timer` attribute. This will result in significantly less accurate time readings. The macro is intended to solve possible problems with earlier revisions of AMD Athlon CPU, described [@http://support.microsoft.com/?scid=kb;en-us;895980 here] and [@http://support.microsoft.com/?id=896256 here]. There are also known chipset hardware failures that may prevent this API from functioning properly (see [@http://support.microsoft.com/kb/274323 here]).]] [[`BOOST_LOG_USE_NATIVE_SYSLOG`] [Affects only the compilation of the library. If for some reason support for the native SysLog API is not detected automatically, define this macro to forcibly enable it]] + [[`BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`] [Affects only the compilation of the library. If defined, the parsers for settings will be built without any default factories for filters and formatters. The user will have to register all attributes in the library before parsing any filters or formatters from strings. This can substantially reduce the binary size.]] [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only the compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.]] [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only the compilation of the library. If defined, the support for debugger output on Windows will not be built.]] [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only the compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.]] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 4f8254e..5d0503b 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -37,7 +37,7 @@ While severity levels can be used for informative purposes, you will normally wa [@boost:/libs/log/example/doc/tutorial_trivial_flt.cpp See the complete code]. -Now, if we run this code sample, the first two log records will be ignored, while the remaining four will pass on to the file. +Now, if we run this code sample, the first two log records will be ignored, while the remaining four will pass on to the console. [important Remember that the streaming expression is only executed if the record passed filtering. Don't specify business-critical calls in the streaming expression, as these calls may not get invoked if the record is filtered away.] @@ -350,7 +350,7 @@ You can try how this works by compiling and running the [@boost:/libs/log/exampl The library supports logging strings containing national characters. There are basically two ways of doing this. On UNIX-like systems typically some multibyte character encoding (e.g. UTF-8) is used to represent national characters. In this case the library can be used just the way it is used for plain ASCII logging, no additional setup is required. -On Windows the common practice is to use wide strings to represent national characters. Also, most of the system API is wide character oriented, which requires Windows-specific sinks to also support wide strings. On the other hand, generic sinks, like [link log.detailed.sink_backends.text_file text file sink, are byte-oriented (because, well, you store bytes in files, not characters). This forces the library to perform character code conversion when needed by the sink. To set up the library for this one has to imbue the sink with a locale with the appropriate `codecvt` facet. __boost_locale__ can be used to generate such a locale. Let's see an example: +On Windows the common practice is to use wide strings to represent national characters. Also, most of the system API is wide character oriented, which requires Windows-specific sinks to also support wide strings. On the other hand, generic sinks, like the [link log.detailed.sink_backends.text_file text file sink], are byte-oriented (because, well, you store bytes in files, not characters). This forces the library to perform character code conversion when needed by the sink. To set up the library for this one has to imbue the sink with a locale with the appropriate `codecvt` facet. __boost_locale__ can be used to generate such a locale. Let's see an example: [example_wide_char_logging_initialization] diff --git a/include/boost/log/detail/malloc_aligned.hpp b/include/boost/log/detail/malloc_aligned.hpp new file mode 100644 index 0000000..0f5f488 --- /dev/null +++ b/include/boost/log/detail/malloc_aligned.hpp @@ -0,0 +1,134 @@ +/* + * 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 malloc_aligned.hpp + * \author Andrey Semashev + * \date 12.07.2013 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/libs/log/doc/log.html. + */ + +#ifndef BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_ +#define BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +// MSVC has its own _aligned_malloc and _aligned_free functions. +// But MinGW doesn't declare these aligned memory allocation routines for MSVC 6 runtime. +#if defined(BOOST_WINDOWS) && !(defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0700) +#include +#define BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC 1 +#endif + +#if defined(BOOST_HAS_UNISTD_H) +#include // _POSIX_VERSION +#endif + +#if defined(__APPLE__) || defined(__APPLE_CC__) || defined(macintosh) +#include +#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) +// Mac OS X 10.6 and later have posix_memalign +#define BOOST_LOG_HAS_POSIX_MEMALIGN 1 +#endif +#elif defined(__ANDROID__) +// Android NDK (up to release 8e, at least) doesn't have posix_memalign despite it defines POSIX macros as if it does. +// But we can use memalign() with free() on this platform. +#include +#define BOOST_LOG_HAS_FREEABLE_MEMALIGN 1 +#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)) || (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)) +// Solaris 10 does not have posix_memalign. Solaris 11 and later seem to have it. +#if !(defined(sun) || defined(__sun)) || defined(__SunOS_5_11) || defined(__SunOS_5_12) +#define BOOST_LOG_HAS_POSIX_MEMALIGN 1 +#endif +#endif + +#include + +#ifdef BOOST_LOG_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifndef BOOST_LOG_CPU_CACHE_LINE_SIZE +//! The macro defines the CPU cache line size for the target architecture. This is mostly used for optimization. +#define BOOST_LOG_CPU_CACHE_LINE_SIZE 64 +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +/*! + * Allocates uninitialized aligned memory. Memory alignment must be a power of 2 and a multiple of sizeof(void*). + * The implementation may impose an upper bound of the alignment as well. + */ +inline void* malloc_aligned(std::size_t size, uint32_t alignment) +{ +#if defined(BOOST_LOG_HAS_POSIX_MEMALIGN) + void* p = NULL; + if (posix_memalign(&p, alignment, size) != 0) + return NULL; + return p; +#elif defined(BOOST_LOG_HAS_FREEABLE_MEMALIGN) + return memalign(alignment, size); +#elif defined(BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC) + return _aligned_malloc(size, alignment); +#else + BOOST_ASSERT(alignment >= sizeof(void*)); + void* p = std::malloc(size + alignment); + if (p) + { + unsigned char* q = static_cast< unsigned char* >(p) + alignment; +#if defined(BOOST_HAS_INTPTR_T) + q = (unsigned char*)((uintptr_t)q & (~(uintptr_t)(alignment - 1u))); +#else + q -= ((std::size_t)q & (std::size_t)(alignment - 1u)); +#endif + // Here we assume that the system allocator aligns to 4 bytes at the very least. + // Therefore we will always have at least 4 bytes before the aligned pointer. + const uint32_t diff = q - static_cast< unsigned char* >(p); + p = q; + *reinterpret_cast< uint32_t* >(q - 4u) = diff; + } + return p; +#endif +} + +/*! + * Frees memory allocated with \c malloc_aligned. + */ +inline void free_aligned(void* p) +{ +#if defined(BOOST_LOG_HAS_POSIX_MEMALIGN) || defined(BOOST_LOG_HAS_FREEABLE_MEMALIGN) + free(p); +#elif defined(BOOST_LOG_HAS_MSVC_ALIGNED_MALLOC) + _aligned_free(p); +#else + if (p) + { + unsigned char* const q = static_cast< unsigned char* >(p); + const uint32_t diff = *reinterpret_cast< uint32_t* >(q - 4u); + std::free(q - diff); + } +#endif +} + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_DETAIL_MALLOC_ALIGNED_HPP_INCLUDED_ diff --git a/include/boost/log/utility/once_block.hpp b/include/boost/log/utility/once_block.hpp index 614215c..f9895dd 100644 --- a/include/boost/log/utility/once_block.hpp +++ b/include/boost/log/utility/once_block.hpp @@ -36,9 +36,10 @@ BOOST_LOG_OPEN_NAMESPACE * macro. Usage example: * * + * once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT; + * * void foo() * { - * static once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT; * BOOST_LOG_ONCE_BLOCK_FLAG(flag) * { * puts("Hello, world once!"); @@ -52,11 +53,11 @@ struct once_block_flag // Do not use, implementation detail enum { - uninitialized = 0, + uninitialized = 0, // this must be zero, so that zero-initialized once_block_flag is equivalent to the one initialized with uninitialized being_initialized, initialized - } - status; + }; + unsigned char status; #endif // BOOST_LOG_DOXYGEN_PASS }; @@ -72,33 +73,33 @@ namespace aux { class once_block_sentry { private: - once_block_flag& m_Flag; + once_block_flag& m_flag; public: - explicit once_block_sentry(once_block_flag& f) : m_Flag(f) + explicit once_block_sentry(once_block_flag& f) BOOST_NOEXCEPT : m_flag(f) { } - ~once_block_sentry() + ~once_block_sentry() BOOST_NOEXCEPT { - if (m_Flag.status != once_block_flag::initialized) + if (m_flag.status != once_block_flag::initialized) rollback(); } - bool executed() const + bool executed() const BOOST_NOEXCEPT { - return (m_Flag.status == once_block_flag::initialized || enter_once_block()); + return (m_flag.status == once_block_flag::initialized || enter_once_block()); } - BOOST_LOG_API void commit(); + BOOST_LOG_API void commit() BOOST_NOEXCEPT; private: - // Non-copyable, non-assignable - once_block_sentry(once_block_sentry const&); - once_block_sentry& operator= (once_block_sentry const&); + BOOST_LOG_API bool enter_once_block() const BOOST_NOEXCEPT; + BOOST_LOG_API void rollback() BOOST_NOEXCEPT; - BOOST_LOG_API bool enter_once_block() const; - BOOST_LOG_API void rollback(); + // Non-copyable, non-assignable + BOOST_LOG_DELETED_FUNCTION(once_block_sentry(once_block_sentry const&)) + BOOST_LOG_DELETED_FUNCTION(once_block_sentry& operator= (once_block_sentry const&)) }; } // namespace aux @@ -125,27 +126,26 @@ namespace aux { class once_block_sentry { private: - once_block_flag& m_Flag; + once_block_flag& m_flag; public: - explicit once_block_sentry(once_block_flag& f) : m_Flag(f) + explicit once_block_sentry(once_block_flag& f) BOOST_NOEXCEPT : m_flag(f) { } - bool executed() const + bool executed() const BOOST_NOEXCEPT { - return m_Flag.status; + return m_flag.status; } - void commit() + void commit() BOOST_NOEXCEPT { - m_Flag.status = true; + m_flag.status = true; } -private: // Non-copyable, non-assignable - once_block_sentry(once_block_sentry const&); - once_block_sentry& operator= (once_block_sentry const&); + BOOST_LOG_DELETED_FUNCTION(once_block_sentry(once_block_sentry const&)) + BOOST_LOG_DELETED_FUNCTION(once_block_sentry& operator= (once_block_sentry const&)) }; } // namespace aux @@ -160,10 +160,11 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #define BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(flag_var, sentry_var)\ for (boost::log::aux::once_block_sentry sentry_var((flag_var));\ - !sentry_var.executed(); sentry_var.commit()) + BOOST_UNLIKELY(!sentry_var.executed()); sentry_var.commit()) +// NOTE: flag_var deliberately doesn't have an initializer so that it is zero-initialized at the static initialization stage #define BOOST_LOG_ONCE_BLOCK_INTERNAL(flag_var, sentry_var)\ - static boost::log::once_block_flag flag_var = BOOST_LOG_ONCE_BLOCK_INIT;\ + static boost::log::once_block_flag flag_var;\ BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(flag_var, sentry_var) #endif // BOOST_LOG_DOXYGEN_PASS @@ -176,7 +177,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log * been executed. */ #define BOOST_LOG_ONCE_BLOCK_FLAG(flag_var)\ - BOOST_LOG_ONCE_BLOCK_INTERNAL(\ + BOOST_LOG_ONCE_BLOCK_FLAG_INTERNAL(\ flag_var,\ BOOST_LOG_UNIQUE_IDENTIFIER_NAME(_boost_log_once_block_sentry_)) diff --git a/src/default_filter_factory.cpp b/src/default_filter_factory.cpp index 2c9c144..3502991 100644 --- a/src/default_filter_factory.cpp +++ b/src/default_filter_factory.cpp @@ -13,6 +13,8 @@ * at http://www.boost.org/libs/log/doc/log.html. */ +#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + #include #include #include @@ -395,3 +397,5 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost #include + +#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) diff --git a/src/default_formatter_factory.cpp b/src/default_formatter_factory.cpp new file mode 100644 index 0000000..ab601be --- /dev/null +++ b/src/default_formatter_factory.cpp @@ -0,0 +1,101 @@ +/* + * 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 default_formatter_factory.hpp + * \author Andrey Semashev + * \date 14.07.2013 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/libs/log/doc/log.html. + */ + +#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + +#undef BOOST_MPL_LIMIT_VECTOR_SIZE +#define BOOST_MPL_LIMIT_VECTOR_SIZE 50 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_LOG_NO_THREADS) +#include +#endif +#include +#include "default_formatter_factory.hpp" +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +//! The callback for equality relation filter +template< typename CharT > +typename default_formatter_factory< CharT >::formatter_type +default_formatter_factory< CharT >::create_formatter(attribute_name const& name, args_map const& args) +{ + // No user-defined factory, shall use the most generic formatter we can ever imagine at this point + typedef mpl::copy< + // We have to exclude std::time_t since it's an integral type and will conflict with one of the standard types + boost_time_period_types, + mpl::back_inserter< + mpl::copy< + boost_time_duration_types, + mpl::back_inserter< boost_date_time_types > + >::type + > + >::type time_related_types; + + typedef mpl::copy< + mpl::copy< + mpl::vector< + attributes::named_scope_list, +#if !defined(BOOST_LOG_NO_THREADS) + log::aux::thread::id, +#endif + log::aux::process::id + >, + mpl::back_inserter< time_related_types > + >::type, + mpl::back_inserter< default_attribute_types > + >::type supported_types; + + return formatter_type(expressions::stream << expressions::attr< supported_types::type >(name)); +} + +// Explicitly instantiate factory implementation +#ifdef BOOST_LOG_USE_CHAR +template class default_formatter_factory< char >; +#endif +#ifdef BOOST_LOG_USE_WCHAR_T +template class default_formatter_factory< wchar_t >; +#endif + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) diff --git a/src/default_formatter_factory.hpp b/src/default_formatter_factory.hpp new file mode 100644 index 0000000..cc9a51a --- /dev/null +++ b/src/default_formatter_factory.hpp @@ -0,0 +1,58 @@ +/* + * 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 default_formatter_factory.hpp + * \author Andrey Semashev + * \date 14.07.2013 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/libs/log/doc/log.html. + */ + +#ifndef BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_ +#define BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_ + +#include +#include +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +//! The default filter factory that supports creating filters for the standard types (see utility/type_dispatch/standard_types.hpp) +template< typename CharT > +class default_formatter_factory : + public formatter_factory< CharT > +{ + //! Base type + typedef formatter_factory< CharT > base_type; + //! Self type + typedef default_formatter_factory< CharT > this_type; + +public: + // Type imports + typedef typename base_type::char_type char_type; + typedef typename base_type::string_type string_type; + typedef typename base_type::formatter_type formatter_type; + typedef typename base_type::args_map args_map; + + //! The function creates a formatter for the specified attribute. + virtual formatter_type create_formatter(attribute_name const& name, args_map const& args); +}; + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_DEFAULT_FORMATTER_FACTORY_HPP_INCLUDED_ diff --git a/src/filter_parser.cpp b/src/filter_parser.cpp index c6512d7..7e324f0 100644 --- a/src/filter_parser.cpp +++ b/src/filter_parser.cpp @@ -48,7 +48,9 @@ #include #endif // !defined(BOOST_LOG_NO_THREADS) #include "parser_utils.hpp" +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) #include "default_filter_factory.hpp" +#endif #include "spirit_encoding.hpp" #include @@ -94,17 +96,27 @@ struct filters_repository : #endif //! The map of filter factories factories_map m_Map; +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) //! Default factory mutable aux::default_filter_factory< char_type > m_DefaultFactory; +#endif //! The method returns the filter factory for the specified attribute name filter_factory_type& get_factory(attribute_name const& name) const { typename factories_map::const_iterator it = m_Map.find(name); if (it != m_Map.end()) + { return *it->second; + } else + { +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) return m_DefaultFactory; +#else + BOOST_LOG_THROW_DESCR(setup_error, "No filter factory registered for attribute " + name.string()); +#endif + } } private: diff --git a/src/formatter_parser.cpp b/src/formatter_parser.cpp index 451e965..5d4b4bf 100644 --- a/src/formatter_parser.cpp +++ b/src/formatter_parser.cpp @@ -15,9 +15,6 @@ #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS -#undef BOOST_MPL_LIMIT_VECTOR_SIZE -#define BOOST_MPL_LIMIT_VECTOR_SIZE 50 - #include #include #include @@ -27,10 +24,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -43,30 +36,24 @@ #include #include #include -#include -#include -#include -#include #include #include #include -#include #include #include -#include #include #include #include #include -#include -#include #if !defined(BOOST_LOG_NO_THREADS) -#include #include #include #endif #include "parser_utils.hpp" #include "spirit_encoding.hpp" +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) +#include "default_formatter_factory.hpp" +#endif #include namespace qi = boost::spirit::qi; @@ -91,7 +78,8 @@ struct formatters_repository : friend class base_type; #endif - typedef formatter_factory< CharT > formatter_factory_type; + typedef CharT char_type; + typedef formatter_factory< char_type > formatter_factory_type; //! Attribute name ordering predicate struct attribute_name_order @@ -113,6 +101,28 @@ struct formatters_repository : #endif //! The map of formatter factories factories_map m_Map; +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + //! Default factory + mutable aux::default_formatter_factory< char_type > m_DefaultFactory; +#endif + + //! The method returns the filter factory for the specified attribute name + formatter_factory_type& get_factory(attribute_name const& name) const + { + typename factories_map::const_iterator it = m_Map.find(name); + if (it != m_Map.end()) + { + return *it->second; + } + else + { +#if !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + return m_DefaultFactory; +#else + BOOST_LOG_THROW_DESCR(setup_error, "No formatter factory registered for attribute " + name.string()); +#endif + } + } private: formatters_repository() @@ -326,43 +336,10 @@ private: } else { + // Use the factory to create the formatter formatters_repository< char_type > const& repo = formatters_repository< char_type >::get(); - typename formatters_repository< char_type >::factories_map::const_iterator it = repo.m_Map.find(m_AttrName); - if (it != repo.m_Map.end()) - { - // We've found a user-defined factory for this attribute - append_formatter(it->second->create_formatter(m_AttrName, m_FactoryArgs)); - } - else - { - // No user-defined factory, shall use the most generic formatter we can ever imagine at this point - typedef mpl::copy< - // We have to exclude std::time_t since it's an integral type and will conflict with one of the standard types - boost_time_period_types, - mpl::back_inserter< - mpl::copy< - boost_time_duration_types, - mpl::back_inserter< boost_date_time_types > - >::type - > - >::type time_related_types; - - typedef mpl::copy< - mpl::copy< - mpl::vector< - attributes::named_scope_list, -#if !defined(BOOST_LOG_NO_THREADS) - log::aux::thread::id, -#endif - log::aux::process::id - >, - mpl::back_inserter< time_related_types > - >::type, - mpl::back_inserter< default_attribute_types > - >::type supported_types; - - append_formatter(expressions::stream << expressions::attr< supported_types::type >(m_AttrName)); - } + formatter_factory_type& factory = repo.get_factory(m_AttrName); + append_formatter(factory.create_formatter(m_AttrName, m_FactoryArgs)); } // Eventually, clear all the auxiliary data diff --git a/src/light_rw_mutex.cpp b/src/light_rw_mutex.cpp index 84561c1..0567cf6 100644 --- a/src/light_rw_mutex.cpp +++ b/src/light_rw_mutex.cpp @@ -25,20 +25,13 @@ #include #include #include +#include #include "windows_version.hpp" #include -#include #include -#if defined(__MINGW32__) && __MSVCRT_VERSION__ < 0x0700 -// MinGW doesn't declare aligned memory allocation routines for MSVC 6 runtime -inline void* _aligned_malloc(size_t size, size_t) { return malloc(size); } -inline void _aligned_free(void* p) { free(p); } -#endif - - namespace boost { BOOST_LOG_OPEN_NAMESPACE @@ -67,17 +60,15 @@ void __stdcall InitializeSharedMutex(mutex_impl* mtx) // To avoid cache line aliasing we do aligned memory allocation here enum { - // Cache line size on x86 - cache_line_size = 64, // Allocation size is the minimum number of cache lines to accommodate shared_mutex size = ( - sizeof(shared_mutex) / cache_line_size - + ((sizeof(shared_mutex) % cache_line_size) != 0) + sizeof(shared_mutex) / BOOST_LOG_CPU_CACHE_LINE_SIZE + + ((sizeof(shared_mutex) % BOOST_LOG_CPU_CACHE_LINE_SIZE) != 0) ) - * cache_line_size + * BOOST_LOG_CPU_CACHE_LINE_SIZE }; - mtx->p = _aligned_malloc(size, cache_line_size); + mtx->p = malloc_aligned(size, BOOST_LOG_CPU_CACHE_LINE_SIZE); BOOST_ASSERT(mtx->p != NULL); new (mtx->p) shared_mutex(); } @@ -85,7 +76,7 @@ void __stdcall InitializeSharedMutex(mutex_impl* mtx) void __stdcall DeinitializeSharedMutex(mutex_impl* mtx) { static_cast< shared_mutex* >(mtx->p)->~shared_mutex(); - _aligned_free(mtx->p); + free_aligned(mtx->p); mtx->p = NULL; } diff --git a/src/once_block.cpp b/src/once_block.cpp index d591837..f8bd64f 100644 --- a/src/once_block.cpp +++ b/src/once_block.cpp @@ -18,6 +18,7 @@ #include #ifndef BOOST_LOG_NO_THREADS +#include #include #if defined(BOOST_THREAD_PLATFORM_WIN32) @@ -42,11 +43,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } // namespace -BOOST_LOG_API bool once_block_sentry::enter_once_block() const +BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT { AcquireSRWLockExclusive(&g_OnceBlockMutex); - once_block_flag volatile& flag = m_Flag; + once_block_flag volatile& flag = m_flag; while (flag.status != once_block_flag::initialized) { if (flag.status == once_block_flag::uninitialized) @@ -72,23 +73,23 @@ BOOST_LOG_API bool once_block_sentry::enter_once_block() const return true; } -BOOST_LOG_API void once_block_sentry::commit() +BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT { AcquireSRWLockExclusive(&g_OnceBlockMutex); // The initializer executed successfully - m_Flag.status = once_block_flag::initialized; + m_flag.status = once_block_flag::initialized; ReleaseSRWLockExclusive(&g_OnceBlockMutex); WakeAllConditionVariable(&g_OnceBlockCond); } -BOOST_LOG_API void once_block_sentry::rollback() +BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT { AcquireSRWLockExclusive(&g_OnceBlockMutex); // The initializer failed, marking the flag as if it hasn't run at all - m_Flag.status = once_block_flag::uninitialized; + m_flag.status = once_block_flag::uninitialized; ReleaseSRWLockExclusive(&g_OnceBlockMutex); WakeAllConditionVariable(&g_OnceBlockCond); @@ -328,10 +329,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { delete impl; } - once_block_impl_base* get_once_block_impl() + once_block_impl_base* get_once_block_impl() BOOST_NOEXCEPT { once_block_impl_base* impl = g_pOnceBlockImpl; - if (!impl) + if (!impl) try { once_block_impl_base* new_impl = create_once_block_impl(); impl = (once_block_impl_base*) @@ -346,25 +347,30 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { return new_impl; } } + catch (...) + { + BOOST_ASSERT_MSG(false, "Boost.Log: Failed to initialize the once block thread synchronization structures"); + std::abort(); + } return impl; } } // namespace -BOOST_LOG_API bool once_block_sentry::enter_once_block() const +BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT { - return get_once_block_impl()->enter_once_block(m_Flag); + return get_once_block_impl()->enter_once_block(m_flag); } -BOOST_LOG_API void once_block_sentry::commit() +BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT { - get_once_block_impl()->commit(m_Flag); + get_once_block_impl()->commit(m_flag); } -BOOST_LOG_API void once_block_sentry::rollback() +BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT { - get_once_block_impl()->rollback(m_Flag); + get_once_block_impl()->rollback(m_flag); } } // namespace aux @@ -395,11 +401,11 @@ static pthread_cond_t g_OnceBlockCond = PTHREAD_COND_INITIALIZER; } // namespace -BOOST_LOG_API bool once_block_sentry::enter_once_block() const +BOOST_LOG_API bool once_block_sentry::enter_once_block() const BOOST_NOEXCEPT { BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex)); - once_block_flag volatile& flag = m_Flag; + once_block_flag volatile& flag = m_flag; while (flag.status != once_block_flag::initialized) { if (flag.status == once_block_flag::uninitialized) @@ -424,23 +430,23 @@ BOOST_LOG_API bool once_block_sentry::enter_once_block() const return true; } -BOOST_LOG_API void once_block_sentry::commit() +BOOST_LOG_API void once_block_sentry::commit() BOOST_NOEXCEPT { BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex)); // The initializer executed successfully - m_Flag.status = once_block_flag::initialized; + m_flag.status = once_block_flag::initialized; BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex)); BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond)); } -BOOST_LOG_API void once_block_sentry::rollback() +BOOST_LOG_API void once_block_sentry::rollback() BOOST_NOEXCEPT { BOOST_VERIFY(!pthread_mutex_lock(&g_OnceBlockMutex)); // The initializer failed, marking the flag as if it hasn't run at all - m_Flag.status = once_block_flag::uninitialized; + m_flag.status = once_block_flag::uninitialized; BOOST_VERIFY(!pthread_mutex_unlock(&g_OnceBlockMutex)); BOOST_VERIFY(!pthread_cond_broadcast(&g_OnceBlockCond)); diff --git a/src/threadsafe_queue.cpp b/src/threadsafe_queue.cpp index a63baff..9734261 100644 --- a/src/threadsafe_queue.cpp +++ b/src/threadsafe_queue.cpp @@ -25,44 +25,14 @@ #ifndef BOOST_LOG_NO_THREADS -#include #include #include -#include #include #include #include #include #include - -#if defined(BOOST_HAS_UNISTD_H) -#include // _POSIX_VERSION -#endif - -#if defined(BOOST_HAS_STDINT_H) -#include // uintptr_t -#else -// MSVC defines integer types here -#include // uintptr_t -#endif - -#if defined(__APPLE__) || defined(__APPLE_CC__) || defined(macintosh) -#include -#if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && (MAC_OS_X_VERSION_MIN_REQUIRED >= 1060) -// Mac OS X 10.6 and later have posix_memalign -#define BOOST_LOG_HAS_POSIX_MEMALIGN 1 -#endif -#elif (defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)) || (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600)) -// Solaris 10 does not have posix_memalign. Solaris 11 and later seem to have it. -#if !(defined(sun) || defined(__sun)) || defined(__SunOS_5_11) || defined(__SunOS_5_12) -#define BOOST_LOG_HAS_POSIX_MEMALIGN 1 -#endif -#endif - -#if defined(BOOST_WINDOWS) -#include // _aligned_malloc, _aligned_free -#endif - +#include #include namespace boost { @@ -81,9 +51,9 @@ private: /*! * A structure that contains a pointer to the node and the associated mutex. - * The alignment below allows to eliminate false sharing, it should be not less than CPU cache line size (which is assumed to be 64 bytes in most cases). + * The alignment below allows to eliminate false sharing, it should not be less than CPU cache line size. */ - struct BOOST_LOG_ALIGNAS(64) pointer + struct BOOST_LOG_ALIGNAS(BOOST_LOG_CPU_CACHE_LINE_SIZE) pointer { //! Pointer to the either end of the queue node_base* node; @@ -168,41 +138,15 @@ BOOST_LOG_API threadsafe_queue_impl* threadsafe_queue_impl::create(node_base* fi BOOST_LOG_API void* threadsafe_queue_impl::operator new (std::size_t size) { - void* p = NULL; - -#if defined(BOOST_LOG_HAS_POSIX_MEMALIGN) - if (posix_memalign(&p, 64, size) || !p) - BOOST_THROW_EXCEPTION(std::bad_alloc()); - return p; -#elif defined(BOOST_WINDOWS) - p = _aligned_malloc(size, 64); + void* p = malloc_aligned(size, BOOST_LOG_CPU_CACHE_LINE_SIZE); if (!p) BOOST_THROW_EXCEPTION(std::bad_alloc()); -#else - p = malloc(size + 64); - if (!p) - BOOST_THROW_EXCEPTION(std::bad_alloc()); - unsigned char* q = static_cast< unsigned char* >(p) + 64; - q = (unsigned char*)((uintptr_t)q & (~(uintptr_t)63)); - const unsigned char diff = q - static_cast< unsigned char* >(p); - p = q; - *--q = diff; -#endif - return p; } BOOST_LOG_API void threadsafe_queue_impl::operator delete (void* p, std::size_t) { -#if defined(BOOST_LOG_HAS_POSIX_MEMALIGN) - free(p); -#elif defined(BOOST_WINDOWS) - _aligned_free(p); -#else - unsigned char* q = static_cast< unsigned char* >(p); - const unsigned char diff = *--q; - free(static_cast< unsigned char* >(p) - diff); -#endif + free_aligned(p); } } // namespace aux diff --git a/src/timestamp.cpp b/src/timestamp.cpp index 9e9f9a6..4365da2 100644 --- a/src/timestamp.cpp +++ b/src/timestamp.cpp @@ -20,12 +20,6 @@ #include #include "windows_version.hpp" #include -#if (defined(_MSC_VER) && defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2) || (defined(__GNUC__) && defined(__i386__) && defined(__SSE2__)) -#include -#if defined(_MSC_VER) -#include -#endif -#endif #else #include // for config macros #if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) @@ -65,7 +59,13 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Atomically loads and stores the 64-bit value through SSE2 instructions BOOST_LOG_FORCEINLINE void move64(const uint64_t* from, uint64_t* to) { - _mm_storel_epi64(reinterpret_cast< __m128i* >(to), _mm_loadl_epi64(reinterpret_cast< const __m128i* >(from))); + __asm + { + mov eax, from + mov edx, to + movq xmm4, qword ptr [eax] + movq qword ptr [edx], xmm4 + }; } # else // defined(_M_IX86_FP) && _M_IX86_FP >= 2 //! Atomically loads and stores the 64-bit value through FPU instructions @@ -97,7 +97,14 @@ BOOST_LOG_FORCEINLINE void move64(const uint64_t* from, uint64_t* to) //! Atomically loads and stores the 64-bit value through SSE2 instructions BOOST_LOG_FORCEINLINE void move64(const uint64_t* from, uint64_t* to) { - _mm_storel_epi64(reinterpret_cast< __m128i* >(to), _mm_loadl_epi64(reinterpret_cast< const __m128i* >(from))); + __asm__ __volatile__ + ( + "movq %1, %%xmm4\n\t" + "movq %%xmm4, %0\n\t" + : "=m" (*to) + : "m" (*from) + : "memory", "xmm4" + ); } # else // defined(__SSE2__) //! Atomically loads and stores the 64-bit value through FPU instructions diff --git a/test/run/util_once_block.cpp b/test/run/util_once_block.cpp index 760b474..13d323e 100644 --- a/test/run/util_once_block.cpp +++ b/test/run/util_once_block.cpp @@ -21,9 +21,12 @@ #if !defined(BOOST_LOG_NO_THREADS) +#include +#include #include #include #include +#include namespace logging = boost::log; @@ -47,9 +50,10 @@ void initialize_variable() } -void once_block_flag_thread() +void once_block_flag_thread(boost::barrier& barrier) { int my_once_value = 0; + barrier.wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK_FLAG(flag) @@ -71,12 +75,13 @@ void once_block_flag_thread() BOOST_AUTO_TEST_CASE(once_block_flag) { boost::thread_group group; + boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) { - group.create_thread(&once_block_flag_thread); + group.create_thread(boost::bind(&once_block_flag_thread, boost::ref(barrier))); } group.join_all(); } @@ -92,9 +97,10 @@ BOOST_AUTO_TEST_CASE(once_block_flag) int var_to_init_once = 0; -void once_block_thread() +void once_block_thread(boost::barrier& barrier) { int my_once_value = 0; + barrier.wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK() @@ -118,12 +124,13 @@ void once_block_thread() BOOST_AUTO_TEST_CASE(once_block) { boost::thread_group group; + boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) { - group.create_thread(&once_block_thread); + group.create_thread(boost::bind(&once_block_thread, boost::ref(barrier))); } group.join_all(); } @@ -145,8 +152,9 @@ struct my_exception unsigned int pass_counter = 0; unsigned int exception_counter = 0; -void once_block_with_exception_thread() +void once_block_with_exception_thread(boost::barrier& barrier) { + barrier.wait(); try { BOOST_LOG_ONCE_BLOCK() @@ -170,12 +178,13 @@ void once_block_with_exception_thread() BOOST_AUTO_TEST_CASE(once_block_retried_on_exception) { boost::thread_group group; + boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) { - group.create_thread(&once_block_with_exception_thread); + group.create_thread(boost::bind(&once_block_with_exception_thread, boost::ref(barrier))); } group.join_all(); }