diff --git a/include/boost/log/exceptions.hpp b/include/boost/log/exceptions.hpp index 8f305fa..1c748d3 100644 --- a/include/boost/log/exceptions.hpp +++ b/include/boost/log/exceptions.hpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -58,6 +60,50 @@ BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const } // namespace aux +/*! + * \brief Base class for memory allocation errors + * + * Exceptions derived from this class indicate problems with memory allocation. + */ +class BOOST_LOG_API bad_alloc : + public std::bad_alloc +{ +private: + std::string m_message; + +public: + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit bad_alloc(std::string const& descr); + /*! + * Destructor + */ + ~bad_alloc() throw(); + + /*! + * Error message accessor. + */ + const char* what() const throw(); +}; + +/*! + * \brief The exception is used to indicate reaching a storage capacity limit + */ +class BOOST_LOG_API capacity_limit_reached : + public bad_alloc +{ +public: + /*! + * Initializing constructor. Creates an exception with the specified error message. + */ + explicit capacity_limit_reached(std::string const& descr); + /*! + * Destructor + */ + ~capacity_limit_reached() throw(); +}; + /*! * \brief Base class for runtime exceptions from the logging library * @@ -68,7 +114,7 @@ BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const class BOOST_LOG_API runtime_error : public std::runtime_error { -protected: +public: /*! * Initializing constructor. Creates an exception with the specified error message. */ @@ -219,25 +265,21 @@ public: * \brief Exception class that is used to indicate underlying OS API errors */ class BOOST_LOG_API system_error : - public runtime_error + public boost::system::system_error { public: - /*! - * Default constructor. Creates an exception with the default error message. - */ - system_error(); /*! * Initializing constructor. Creates an exception with the specified error message. */ - explicit system_error(std::string const& descr); + system_error(boost::system::error_code code, std::string const& descr); /*! * Destructor */ ~system_error() throw(); #ifndef BOOST_LOG_DOXYGEN_PASS - static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); - static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, int system_error_code); + static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, std::string const& descr, boost::system::error_code code); #endif }; @@ -250,7 +292,7 @@ public: class BOOST_LOG_API logic_error : public std::logic_error { -protected: +public: /*! * Initializing constructor. Creates an exception with the specified error message. */ diff --git a/include/boost/log/sinks/text_ipc_message_queue_backend.hpp b/include/boost/log/sinks/text_ipc_message_queue_backend.hpp index e4ba2d4..1c58cc2 100644 --- a/include/boost/log/sinks/text_ipc_message_queue_backend.hpp +++ b/include/boost/log/sinks/text_ipc_message_queue_backend.hpp @@ -19,20 +19,10 @@ #define BOOST_LOG_SINKS_TEXT_IPC_MESSAGE_QUEUE_BACKEND_HPP_INCLUDED_ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include #include #include -#include +#include #include #include #include @@ -47,21 +37,6 @@ BOOST_LOG_OPEN_NAMESPACE namespace sinks { -namespace ipc { - -//! Interprocess queue overflow policies -enum queue_overflow_policy -{ - //! Drop the message when the queue is full - drop_on_overflow, - //! Throw an exception when the queue is full - throw_on_overflow, - //! Block the send operation when the queue is full - block_on_overflow -}; - -} // namespace ipc - /*! * \brief An implementation of a text interprocess message queue sink backend and * a supporting interprocess message queue. @@ -70,7 +45,7 @@ enum queue_overflow_policy * which can be extracted by a viewer process. Methods of this class are not * thread-safe, unless otherwise specified. */ -template< typename QueueT, ipc::queue_overflow_policy OverflowPolicyV = ipc::drop_on_overflow > +template< typename QueueT > class text_ipc_message_queue_backend : public basic_formatted_sink_backend< char, concurrent_feeding > { @@ -91,55 +66,22 @@ private: public: /*! - * Default constructor. The method constructs the backend using default values - * of all the parameters. + * Default constructor. The method constructs the backend using the default-constructed + * interprocess message queue. The queue may need additional setup in order to be able + * to send messages. */ text_ipc_message_queue_backend() BOOST_NOEXCEPT { } /*! - * Constructor. The method creates a backend that sends messages to an associated - * message queue. After the call, the backend will be in running state if a message - * queue is successfully associated. - * - * The following named parameters are supported: - * - * \li \c message_queue_name - Specifies the name of the queue. The name is given as a C-style string. - * A valid name is one that can be used as a C++ identifier or is a keyword. - * If an empty string is passed, the backend has no associated message queue, - * and does not send any message. Default is an empty string. On Windows - * platforms, the name is used to compose kernel object names, and you may - * need to add the "Global\" prefix to the name in certain cases. - * \li \c open_mode - Specifies the open mode which is given as a \c open_mode value. If a new message queue - * is created, the specified message queue settings are applied. If an existing message queue - * is opened, the specified settings are ignored. The default is \c open_only. For - * \c open_or_create, users can query whether the message queue is actually opened or created - * by checking the value of \c errno. It would be \c EEXIST when opened, and \c ENOENT when - * created. The \c errno is set to \c 0 before doing any operation. For \c create_only, the - * operation may fail with \c errno \c EEXIST. For \c open_only, the operation may fail with - * \c errno \c ENOENT. For any other error, a boost::system::system_error exception - * is thrown. - * \li \c max_queue_size - Specifies the maximum number of messages the message queue can hold. The parameter - * is given as an unsigned int value, with the default being \c 10. - * \li \c max_message_size - Specifies the maximum size in bytes of each message allowed by the message - * queue. The parameter is given as an unsigned int value, with the default - * being \c 1000. - * \li \c queue_policy - Specifies the policy to use when sending to a full message queue. The parameter is - * given as a \c queue_policy_type value, with the default being \c drop_when_full. - * \li \c message_policy - Specifies the policy to use when the message to send is too long for the associated - * message queue. The parameter is given as a \c message_policy_type value, with the - * default being \c throw_when_too_long. - * \li \c permissions - Specifies access permissions for the associated message queue if it is created by this - * object. The parameter is ignored otherwise. The parameter is of type \c permissions with - * the default being a default-constructed \c permissions object. + * Initializing constructor. The method constructs the backend using the provided + * interprocess message queue. The constructor moves from the provided queue. */ -#ifndef BOOST_LOG_DOXYGEN_PASS - BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(text_ipc_message_queue_backend, construct) -#else - template< typename... ArgsT > - explicit text_ipc_message_queue_backend(ArgsT... const& args); -#endif + explicit text_ipc_message_queue_backend(BOOST_RV_REF(queue_type) queue) BOOST_NOEXCEPT : + m_queue(static_cast< BOOST_RV_REF(queue_type) >(queue)) + { + } /*! * The method returns a reference to the managed \c queue_type object. @@ -149,46 +91,12 @@ public: queue_type& message_queue() BOOST_NOEXCEPT { return m_queue; } /*! - * The method returns a const reference to the managed \c queue_type object. + * The method returns a constant reference to the managed \c queue_type object. * - * \return A const reference to the managed \c queue_type object. + * \return A constant reference to the managed \c queue_type object. */ queue_type const& message_queue() const BOOST_NOEXCEPT { return m_queue; } - /*! - * The method sets the message queue to be associated with the object. If the object is - * associated with a message queue, close() is first called and the precondition - * to calling close() applies. After the call, the object will be in running state - * if a message queue is successfully associated. If no message queue is associated after - * the call, the backend does not send any message. - * - * \param name Name of the message queue to be associated with. A valid name is one - * that can be used as a C++ identifier or is a keyword. Passing an empty - * string is equivalent to calling close(). On Windows platforms, - * the name is used to compose kernel object names, and you may need to - * add the "Global\" prefix to the name in certain cases. - * \param mode Open mode. If a new message queue is created, the specified settings, as indicated - * by the remaining parameters, are applied. If an existing message queue is opened, - * the specified settings are ignored. For \c open_or_create, users can query whether - * the message queue is actually opened or created by checking the value of \c errno. - * It would be \c EEXIST when opened, and \c ENOENT when created. The \c errno is set - * to \c 0 before doing any operation. For \c create_only, the operation may fail - * with \c errno \c EEXIST. For \c open_only, the operation may fail with \c errno - * \c ENOENT. For any other error, a boost::system::system_error exception - * is thrown. - * \param max_queue_size Maximum number of messages the queue can hold. - * \param max_message_size Maximum size in bytes of each message allowed by the queue. - * \param perms Access permissions for the associated message queue if it is - * created by this object. The parameter is ignored otherwise. - * - * \return \c true if the operation is successful, and \c false otherwise. - */ - void create( - char const* name, - uint32_t capacity, - uint32_t max_message_size = 1000, - permissions const& perms = permissions()); - /*! * Tests whether the object is associated with any message queue. Only when the backend has * an associated message queue, will any message be sent. @@ -197,49 +105,6 @@ public: */ bool is_open() const BOOST_NOEXCEPT { return m_queue.is_open(); } - /*! - * The method wakes up all threads that are blocking on calls to consume(). - * Those calls would then return, dropping the messages they are trying to send. - * Note that, the method does not block until the woke-up threads have actually - * returned from consume(). Other means is needed to ensure that calls to - * consume() have returned. The method also puts the object in stopped - * state. When in stopped state, calls to consume() will return immediately, - * dropping the messages they are trying to send, when they would otherwise block in - * running state. Concurrent calls to this method and consume() are OK. - */ - void stop() - { - m_queue.stop(); - } - - /*! - * The method puts the object in running state where calls to consume() - * may block. - */ - void reset() - { - m_queue.reset(); - } - - /*! - * The method disassociates the associated message queue, if any. No other threads - * should be using this object before calling this method. The stop() method - * could be used to have any threads currently blocking on consume() return, - * and prevent further calls to consume() from blocking. The associated message - * queue is destroyed, if the object represents the last outstanding reference to it. - */ - void close() - { - m_queue.close(); - } - - /*! - * The method queries the current queue policy. - * - * \return Current queue policy. - */ - ipc::queue_overflow_policy queue_overflow_policy() const BOOST_NOEXCEPT { return OverflowPolicyV; } - /*! * The method writes the message to the backend. Concurrent calls to this method * are OK. Therefore, the backend may be used with unlocked frontend. stop() @@ -249,47 +114,8 @@ public: void consume(record_view const&, string_type const& formatted_message) { if (m_queue.is_open()) - { - if (OverflowPolicyV == ipc::block_when_full) - { - m_queue.send(formatted_message.data(), formatted_message.size()); - } - else - { - if (!m_queue.try_send(formatted_message.data(), formatted_message.size())) - { - if (OverflowPolicyV == ipc::throw_when_full) - BOOST_THROW_EXCEPTION(runtime_error("Interprocess message queue is full")); - } - } - } + m_queue.send(formatted_message.data(), formatted_message.size()); } - -private: -#ifndef BOOST_LOG_DOXYGEN_PASS - //! Constructor implementation - template< typename ArgsT > - void construct(ArgsT const& args) - { - construct( - args[keywords::message_queue_name | ""], - args[keywords::open_mode | open_only], - args[keywords::max_queue_size | 10], - args[keywords::max_message_size | 1000], - args[keywords::queue_policy | drop_when_full], - args[keywords::message_policy | throw_when_too_long], - args[keywords::permissions | permissions()]); - } - //! Constructor implementation - BOOST_LOG_API void construct( - char const* message_queue_name, - open_mode mode, - unsigned int max_queue_size, - unsigned int max_message_size, - queue_policy_type queue_policy_val, - message_policy_type message_policy_val, - permissions const& perms); -#endif // BOOST_LOG_DOXYGEN_PASS }; } // namespace sinks diff --git a/include/boost/log/utility/ipc/reliable_message_queue.hpp b/include/boost/log/utility/ipc/reliable_message_queue.hpp index c6c17f8..91450eb 100644 --- a/include/boost/log/utility/ipc/reliable_message_queue.hpp +++ b/include/boost/log/utility/ipc/reliable_message_queue.hpp @@ -63,6 +63,15 @@ public: aborted //!< The operation has been aborted because the queue method stop() has been called }; + //! Interprocess queue overflow policies + enum overflow_policy + { + //! Block the send operation when the queue is full + block_on_overflow, + //! Throw an exception when the queue is full + throw_on_overflow + }; + #if !defined(BOOST_LOG_DOXYGEN_PASS) BOOST_MOVABLE_BUT_NOT_COPYABLE(reliable_message_queue) @@ -106,6 +115,7 @@ public: * \param capacity Maximum number of allocation blocks the queue can hold. * \param block_size Size in bytes of allocation block. Must be a power of 2. * \param perms Access permissions for the associated message queue. + * \param oflow_policy Queue behavior policy in case of overflow. */ reliable_message_queue ( @@ -113,11 +123,12 @@ public: char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms = permissions() + permissions const& perms = permissions(), + overflow_policy oflow_policy = block_on_overflow ) : m_impl(NULL) { - this->create(name, capacity, block_size, perms); + this->create(name, capacity, block_size, perms, oflow_policy); } /*! @@ -136,6 +147,7 @@ public: * \param capacity Maximum number of allocation blocks the queue can hold. * \param block_size Size in bytes of allocation block. Must be a power of 2. * \param perms Access permissions for the associated message queue. + * \param oflow_policy Queue behavior policy in case of overflow. */ reliable_message_queue ( @@ -143,11 +155,12 @@ public: char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms = permissions() + permissions const& perms = permissions(), + overflow_policy oflow_policy = block_on_overflow ) : m_impl(NULL) { - this->open_or_create(name, capacity, block_size, perms); + this->open_or_create(name, capacity, block_size, perms, oflow_policy); } /*! @@ -158,11 +171,12 @@ public: * \post is_open() == true * * \param name Name of the message queue to be associated with. + * \param oflow_policy Queue behavior policy in case of overflow. */ - reliable_message_queue(open_mode::open_only_tag, char const* name) : + reliable_message_queue(open_mode::open_only_tag, char const* name, overflow_policy oflow_policy = block_on_overflow) : m_impl(NULL) { - this->open(name); + this->open(name, oflow_policy); } /*! @@ -235,13 +249,15 @@ public: * \param capacity Maximum number of allocation blocks the queue can hold. * \param block_size Size in bytes of allocation block. Must be a power of 2. * \param perms Access permissions for the associated message queue. + * \param oflow_policy Queue behavior policy in case of overflow. */ BOOST_LOG_API void create ( char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms = permissions() + permissions const& perms = permissions(), + overflow_policy oflow_policy = block_on_overflow ); /*! @@ -261,13 +277,15 @@ public: * \param capacity Maximum number of allocation blocks the queue can hold. * \param block_size Size in bytes of allocation block. Must be a power of 2. * \param perms Access permissions for the associated message queue. + * \param oflow_policy Queue behavior policy in case of overflow. */ BOOST_LOG_API void open_or_create ( char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms = permissions() + permissions const& perms = permissions(), + overflow_policy oflow_policy = block_on_overflow ); /*! @@ -279,8 +297,9 @@ public: * \post is_open() == true * * \param name Name of the message queue to be associated with. + * \param oflow_policy Queue behavior policy in case of overflow. */ - BOOST_LOG_API void open(char const* name); + BOOST_LOG_API void open(char const* name, overflow_policy oflow_policy = block_on_overflow); /*! * Tests whether the object is associated with any message queue. @@ -382,10 +401,12 @@ public: /*! * The method sends a message to the associated message queue. When the object is in - * running state and the queue has no free space for the message, the method blocks. - * The blocking is interrupted when stop() is called, in which case the method - * returns \c operation_result::aborted. When the object is already in the stopped state, - * the method does not block but returns immediately with return value \c operation_result::aborted. + * running state and the queue has no free space for the message, the method either blocks + * or throws an exception, depending on the overflow policy that was specified on the queue + * opening/creation. If blocking policy is in effect, the blocking can be interrupted by + * calling stop(), in which case the method returns \c operation_result::aborted. + * When the object is already in the stopped state, the method does not block but returns + * immediately with return value \c operation_result::aborted. * * It is possible to send an empty message by passing \c 0 to the parameter \c message_size. * diff --git a/src/event.cpp b/src/event.cpp index 224a850..ea9eee2 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -20,9 +20,8 @@ #include #include #include -#include -#include #include +#include #if defined(BOOST_LOG_EVENT_USE_FUTEX) @@ -110,8 +109,7 @@ BOOST_LOG_API void futex_based_event::wait() } else if (BOOST_UNLIKELY(err != EINTR)) { - BOOST_THROW_EXCEPTION(system::system_error( - err, system::system_category(), "Failed to block on the futex")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the futex", (err)); } } @@ -127,8 +125,7 @@ BOOST_LOG_API void futex_based_event::set_signalled() if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.storage(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0)) { const int err = errno; - BOOST_THROW_EXCEPTION(system::system_error( - err, system::system_category(), "Failed to wake threads blocked on the futex")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake threads blocked on the futex", (err)); } } } @@ -141,8 +138,7 @@ BOOST_LOG_API sem_based_event::sem_based_event() : m_state() if (BOOST_UNLIKELY(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")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize semaphore", (err)); } } @@ -163,8 +159,7 @@ BOOST_LOG_API void sem_based_event::wait() const int err = errno; if (BOOST_UNLIKELY(err != EINTR)) { - BOOST_THROW_EXCEPTION(system::system_error( - err, system::system_category(), "Failed to block on the semaphore")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the semaphore", (err)); } } else @@ -181,8 +176,7 @@ BOOST_LOG_API void sem_based_event::set_signalled() if (BOOST_UNLIKELY(sem_post(&m_semaphore) != 0)) { const int err = errno; - BOOST_THROW_EXCEPTION(system::system_error( - err, system::system_category(), "Failed to wake the blocked thread")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); } } } @@ -197,8 +191,7 @@ BOOST_LOG_API winapi_based_event::winapi_based_event() : if (BOOST_UNLIKELY(!m_event)) { const DWORD err = GetLastError(); - BOOST_THROW_EXCEPTION(system::system_error( - err, system::system_category(), "Failed to create Windows event")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err)); } } @@ -217,8 +210,7 @@ BOOST_LOG_API void winapi_based_event::wait() if (BOOST_UNLIKELY(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")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err)); } } const_cast< volatile boost::uint32_t& >(m_state) = 0; @@ -233,8 +225,7 @@ BOOST_LOG_API void winapi_based_event::set_signalled() { 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")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); } } } diff --git a/src/event_log_backend.cpp b/src/event_log_backend.cpp index a2edb24..dac023d 100644 --- a/src/event_log_backend.cpp +++ b/src/event_log_backend.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -155,7 +156,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { module_count /= sizeof(HMODULE); if (!res) - BOOST_LOG_THROW_DESCR(system_error, "Could not enumerate process modules"); + { + DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not enumerate process modules", (err)); + } } while (module_count > modules.size()); modules.resize(module_count, HMODULE(0)); @@ -166,7 +170,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { MODULEINFO info; if (!GetModuleInformation(hProcess, modules[i], &info, sizeof(info))) - BOOST_LOG_THROW_DESCR(system_error, "Could not acquire module information"); + { + DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not acquire module information", (err)); + } if (info.lpBaseOfDll <= p && (static_cast< unsigned char* >(info.lpBaseOfDll) + info.SizeOfImage) > p) { @@ -177,7 +184,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } if (!handle) - BOOST_LOG_THROW_DESCR(system_error, "Could not find self module information"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not find self module information", (boost::system::windows_error::invalid_handle)); } //! Retrieves the full name of the current module (be that dll or exe) @@ -195,7 +202,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { CharT buf[MAX_PATH]; DWORD size = get_module_file_name(hSelfModule, buf, sizeof(buf) / sizeof(*buf)); if (size == 0) - BOOST_LOG_THROW_DESCR(system_error, "Could not get module file name"); + { + DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not get module file name", (err)); + } return std::basic_string< CharT >(buf, buf + size); } diff --git a/src/event_log_registry.hpp b/src/event_log_registry.hpp index e38d200..75191ef 100644 --- a/src/event_log_registry.hpp +++ b/src/event_log_registry.hpp @@ -397,7 +397,7 @@ namespace aux { &hkey, &disposition); if (res != ERROR_SUCCESS) - BOOST_LOG_THROW_DESCR(system_error, "Could not create registry key for the event log"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Could not create registry key for the event log", (res)); auto_hkey_close hkey_guard(hkey); diff --git a/src/exceptions.cpp b/src/exceptions.cpp index a7915b7..e7819a4 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp @@ -43,6 +43,29 @@ BOOST_LOG_API void attach_attribute_name_info(exception& e, attribute_name const } // namespace aux +bad_alloc::bad_alloc(std::string const& descr) : + m_message(descr) +{ +} + +bad_alloc::~bad_alloc() throw() +{ +} + +const char* bad_alloc::what() const throw() +{ + return m_message.c_str(); +} + +capacity_limit_reached::capacity_limit_reached(std::string const& descr) : + bad_alloc(descr) +{ +} + +capacity_limit_reached::~capacity_limit_reached() throw() +{ +} + runtime_error::runtime_error(std::string const& descr) : std::runtime_error(descr) { @@ -257,13 +280,8 @@ void conversion_error::throw_(const char* file, std::size_t line, std::string co ); } -system_error::system_error() : - runtime_error("Underlying API operation failed") -{ -} - -system_error::system_error(std::string const& descr) : - runtime_error(descr) +system_error::system_error(boost::system::error_code code, std::string const& descr) : + boost::system::system_error(code, descr) { } @@ -271,17 +289,17 @@ system_error::~system_error() throw() { } -void system_error::throw_(const char* file, std::size_t line) +void system_error::throw_(const char* file, std::size_t line, std::string const& descr, int system_error_code) { - boost::throw_exception(boost::enable_error_info(system_error()) + boost::throw_exception(boost::enable_error_info(system_error(boost::system::error_code(system_error_code, boost::system::system_category()), descr)) << boost::throw_file(file) << boost::throw_line(line) ); } -void system_error::throw_(const char* file, std::size_t line, std::string const& descr) +void system_error::throw_(const char* file, std::size_t line, std::string const& descr, boost::system::error_code code) { - boost::throw_exception(boost::enable_error_info(system_error(descr)) + boost::throw_exception(boost::enable_error_info(system_error(code, descr)) << boost::throw_file(file) << boost::throw_line(line) ); diff --git a/src/ipc_reliable_message_queue_posix.cpp b/src/ipc_reliable_message_queue_posix.cpp index 7ee076c..3de7dc4 100644 --- a/src/ipc_reliable_message_queue_posix.cpp +++ b/src/ipc_reliable_message_queue_posix.cpp @@ -185,11 +185,11 @@ private: //! Size of an allocation block, in bytes. const uint32_t m_block_size; //! Mutex for protecting queue data structures. - boost::log::aux::interprocess_mutex m_mutex; + boost::log::ipc::aux::interprocess_mutex m_mutex; //! Condition variable used to block readers when the queue is empty. - boost::log::aux::interprocess_condition_variable m_nonempty_queue; + boost::log::ipc::aux::interprocess_condition_variable m_nonempty_queue; //! Condition variable used to block writers when the queue is full. - boost::log::aux::interprocess_condition_variable m_nonfull_queue; + boost::log::ipc::aux::interprocess_condition_variable m_nonfull_queue; //! The current number of allocated blocks in the queue. uint32_t m_size; //! The current writing position (allocation block index). @@ -235,7 +235,7 @@ private: BOOST_LOG_MIX_HEADER_MEMBER(m_mutex); BOOST_LOG_MIX_HEADER_MEMBER(m_nonempty_queue); BOOST_LOG_MIX_HEADER_MEMBER(m_nonfull_queue); - BOOST_LOG_MIX_HEADER_MEMBER(m_queue_size); + BOOST_LOG_MIX_HEADER_MEMBER(m_size); BOOST_LOG_MIX_HEADER_MEMBER(m_put_pos); BOOST_LOG_MIX_HEADER_MEMBER(m_get_pos); @@ -260,6 +260,7 @@ private: private: boost::interprocess::shared_memory_object m_shared_memory; boost::interprocess::mapped_region m_region; + const overflow_policy m_overflow_policy; uint32_t m_block_size_mask; uint32_t m_block_size_log2; bool m_stop; @@ -272,10 +273,12 @@ public: char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms + permissions const& perms, + overflow_policy oflow_policy ) : m_shared_memory(boost::interprocess::create_only, name, boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), m_region(), + m_overflow_policy(oflow_policy), m_block_size_mask(0u), m_block_size_log2(0u), m_stop(false) @@ -290,10 +293,14 @@ public: char const* name, uint32_t capacity, uint32_t block_size, - permissions const& perms + permissions const& perms, + overflow_policy oflow_policy ) : m_shared_memory(boost::interprocess::open_or_create, name, boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), m_region(), + m_overflow_policy(oflow_policy), + m_block_size_mask(0u), + m_block_size_log2(0u), m_stop(false) { boost::interprocess::offset_t shmem_size = 0; @@ -307,10 +314,14 @@ public: implementation ( open_mode::open_only_tag, - char const* name + char const* name, + overflow_policy oflow_policy ) : m_shared_memory(boost::interprocess::open_only, name, boost::interprocess::read_write), m_region(), + m_overflow_policy(oflow_policy), + m_block_size_mask(0u), + m_block_size_log2(0u), m_stop(false) { boost::interprocess::offset_t shmem_size = 0; @@ -358,7 +369,7 @@ public: return aborted; lock_queue(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); while (true) { @@ -368,6 +379,9 @@ public: if ((hdr->m_capacity - hdr->m_size) >= block_count) break; + if (BOOST_UNLIKELY(m_overflow_policy == throw_on_overflow)) + BOOST_THROW_EXCEPTION(capacity_limit_reached("Interprocess queue is full")); + hdr->m_nonfull_queue.wait(hdr->m_mutex); } @@ -389,7 +403,7 @@ public: return false; lock_queue(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); if (m_stop) return false; @@ -409,7 +423,7 @@ public: lock_queue(); header* const hdr = get_header(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); while (true) { @@ -434,7 +448,7 @@ public: lock_queue(); header* const hdr = get_header(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); if (hdr->m_size == 0u) return false; @@ -451,7 +465,7 @@ public: lock_queue(); header* const hdr = get_header(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); m_stop = true; @@ -463,7 +477,7 @@ public: { lock_queue(); header* const hdr = get_header(); - interprocess_mutex::auto_unlock unlock(hdr->m_mutex); + boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); clear_queue(); } @@ -614,7 +628,7 @@ private: hdr->m_mutex.lock(); #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST) } - catch (boost::log::aux::lock_owner_dead&) + catch (boost::log::ipc::aux::lock_owner_dead&) { // The mutex is locked by the current thread, but the previous owner terminated without releasing the lock try @@ -667,7 +681,7 @@ private: { // Write the rest of the message at the beginning of the queue pos -= capacity; - message_data += write_size; + message_data = static_cast< const uint8_t* >(message_data) + write_size; write_size = message_size - write_size; if (write_size > 0u) std::memcpy(hdr->get_block(0u), message_data, write_size); @@ -694,7 +708,7 @@ private: uint32_t message_size = block->m_size; uint32_t block_count = estimate_block_count(message_size); - BOOST_ASSERT(block_count < hdr->m_size) + BOOST_ASSERT(block_count < hdr->m_size); uint32_t read_size = (std::min)((capacity - pos) * block_size - block_header::get_header_overhead(), message_size); handler(state, block->get_data(), read_size); @@ -716,14 +730,14 @@ private: } }; -BOOST_LOG_API void reliable_message_queue::create(char const* name, uint32_t capacity, uint32_t block_size, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::create(char const* name, uint32_t capacity, uint32_t block_size, permissions const& perms, overflow_policy oflow_policy) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2")); try { - m_impl = new implementation(open_mode::create_only, name, capacity, boost::log::aux::align_size(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE), perms); + m_impl = new implementation(open_mode::create_only, name, capacity, boost::log::aux::align_size(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE), perms, oflow_policy); } catch (boost::exception& e) { @@ -732,18 +746,18 @@ BOOST_LOG_API void reliable_message_queue::create(char const* name, uint32_t cap } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); } } -BOOST_LOG_API void reliable_message_queue::open_or_create(char const* name, uint32_t capacity, uint32_t block_size, permissions const& perms) +BOOST_LOG_API void reliable_message_queue::open_or_create(char const* name, uint32_t capacity, uint32_t block_size, permissions const& perms, overflow_policy oflow_policy) { BOOST_ASSERT(m_impl == NULL); if (!boost::log::aux::is_power_of_2(block_size)) BOOST_THROW_EXCEPTION(std::invalid_argument("Interprocess message queue block size is not a power of 2")); try { - m_impl = new implementation(open_mode::open_or_create, name, capacity, boost::log::aux::align_size(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE), perms); + m_impl = new implementation(open_mode::open_or_create, name, capacity, boost::log::aux::align_size(block_size, BOOST_LOG_CPU_CACHE_LINE_SIZE), perms, oflow_policy); } catch (boost::exception& e) { @@ -752,16 +766,16 @@ BOOST_LOG_API void reliable_message_queue::open_or_create(char const* name, uint } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); } } -BOOST_LOG_API void reliable_message_queue::open(char const* name) +BOOST_LOG_API void reliable_message_queue::open(char const* name, overflow_policy oflow_policy) { BOOST_ASSERT(m_impl == NULL); try { - m_impl = new implementation(open_mode::open_only, name); + m_impl = new implementation(open_mode::open_only, name, oflow_policy); } catch (boost::exception& e) { @@ -770,7 +784,7 @@ BOOST_LOG_API void reliable_message_queue::open(char const* name) } catch (boost::interprocess::interprocess_exception& e) { - BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(e.what())) << boost::log::resource_name_info(name)); + BOOST_THROW_EXCEPTION(boost::enable_error_info(system_error(boost::system::error_code(e.get_native_error(), boost::system::system_category()), e.what())) << boost::log::resource_name_info(name)); } } @@ -901,7 +915,7 @@ BOOST_LOG_API void reliable_message_queue::fixed_buffer_receive_handler(void* st { fixed_buffer_state* p = static_cast< fixed_buffer_state* >(state); if (BOOST_UNLIKELY(size > p->size)) - BOOST_THROW_EXCEPTION(std::runtime_error("Buffer too small to receive the message")); + BOOST_THROW_EXCEPTION(bad_alloc("Buffer too small to receive the message")); std::memcpy(p->data, data, size); p->data += size; diff --git a/src/permissions.cpp b/src/permissions.cpp index 263db2f..9bf8096 100644 --- a/src/permissions.cpp +++ b/src/permissions.cpp @@ -41,10 +41,16 @@ BOOST_LOG_API permissions::native_type permissions::get_unrestricted_security_at BOOST_LOG_ONCE_BLOCK() { if (!InitializeSecurityDescriptor(&g_unrestricted_security_descriptor, SECURITY_DESCRIPTOR_REVISION)) - BOOST_LOG_THROW_DESCR(system_error, "Failed to initialize security descriptor"); + { + DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize security descriptor", (err)); + } if (!SetSecurityDescriptorDacl(&g_unrestricted_security_descriptor, TRUE, NULL, FALSE)) - BOOST_LOG_THROW_DESCR(system_error, "Failed to set null DACL to a security descriptor"); + { + DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to set null DACL to a security descriptor", (err)); + } g_unrestricted_security_attributes.nLength = sizeof(g_unrestricted_security_attributes); g_unrestricted_security_attributes.lpSecurityDescriptor = &g_unrestricted_security_descriptor; diff --git a/src/posix_wrapper.hpp b/src/posix_wrapper.hpp deleted file mode 100644 index 4879249..0000000 --- a/src/posix_wrapper.hpp +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright Lingxi Li 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 posix_wrapper.hpp - * \author Lingxi Li - * \date 17.11.2015 - * - * \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. - * - * This file provides checked POSIX. - */ - -#ifndef BOOST_LOG_POSIX_WRAPPER_HPP_INCLUDED_ -#define BOOST_LOG_POSIX_WRAPPER_HPP_INCLUDED_ - -#include -#include -#include -#include -#include - -#ifndef BOOST_WINDOWS - -#include -#include -#include -#include - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace aux { - -namespace { - -inline system::error_code make_error_code( - int value = errno, - system::error_category const& category = system::system_category()) -{ - return system::error_code(value, category); -} - -inline system::system_error make_system_error( - char const* api_name, - int value = errno, - system::error_category const& category = system::system_category()) -{ - return system::system_error(value, category, api_name); -} - -// general file operations -inline void close(int fd) -{ - if (::close(fd) != 0) throw make_system_error("close"); -} - -inline void safe_close(int& fd) -{ - if (fd >= 0) { - close(fd); - fd = -1; - } -} - -inline void ftruncate(int fd, off_t size) -{ - if (::ftruncate(fd, size) != 0) throw make_system_error("ftruncate"); -} - -inline void fstat(int fd, struct stat* p_stat) -{ - if (::fstat(fd, p_stat) != 0) throw make_system_error("fstat"); -} - -// shared memory -inline int shm_open(char const* name, int oflag, mode_t permission) -{ - int shm_fd = ::shm_open(name, oflag, permission); - return shm_fd >= 0 ? shm_fd : throw make_system_error("shm_open"); -} - -inline void shm_unlink(char const* name) -{ - if (::shm_unlink(name) != 0) throw make_system_error("shm_unlink"); -} - -inline void* mmap( - void* addr, size_t size, int protection, int flag, int fd, off_t offset) -{ - void* memory = ::mmap(addr, size, protection, flag, fd, offset); - return memory != MAP_FAILED ? memory : throw make_system_error("mmap"); -} - -template < typename Ptr > -inline Ptr typed_mmap( - void* addr, size_t size, int protection, int flag, int fd, off_t offset) -{ - return static_cast(mmap(addr, size, protection, flag, fd, offset)); -} - -inline void munmap(void* memory, size_t size) -{ - if (::munmap(memory, size) != 0) throw make_system_error("munmap"); -} - -template < typename T > -inline void safe_munmap(T*& memory, size_t size) -{ - if (memory) - { - munmap(memory, size); - memory = NULL; - } -} - -// pthread mutex -inline void pthread_mutexattr_init(pthread_mutexattr_t* p_attr) -{ - int err = ::pthread_mutexattr_init(p_attr); - if (err != 0) throw make_system_error("pthread_mutexattr_init", err); -} - -inline void pthread_mutexattr_destroy(pthread_mutexattr_t* p_attr) -{ - int err = ::pthread_mutexattr_destroy(p_attr); - if (err != 0) throw make_system_error("pthread_mutexattr_destroy", err); -} - -inline void pthread_mutexattr_setpshared(pthread_mutexattr_t* p_attr, int val) -{ - int err = ::pthread_mutexattr_setpshared(p_attr, val); - if (err != 0) throw make_system_error("pthread_mutexattr_setpshared", err); -} - -inline void pthread_mutexattr_setrobust(pthread_mutexattr_t* p_attr, int val) -{ - int err = ::pthread_mutexattr_setrobust(p_attr, val); - if (err != 0) throw make_system_error("pthread_mutexattr_setrobust", err); -} - -inline void pthread_mutexattr_settype(pthread_mutexattr_t* p_attr, int val) -{ - int err = ::pthread_mutexattr_settype(p_attr, val); - if (err != 0) throw make_system_error("pthread_mutexattr_settype", err); -} - -inline void pthread_mutex_init( - pthread_mutex_t* p_mutex, pthread_mutexattr_t const* p_attr) -{ - int err = ::pthread_mutex_init(p_mutex, p_attr); - if (err != 0) throw make_system_error("pthread_mutex_init", err); -} - -inline void pthread_mutex_destroy(pthread_mutex_t* p_mutex) -{ - int err = ::pthread_mutex_destroy(p_mutex); - if (err != 0) throw make_system_error("pthread_mutex_destroy", err); -} - -inline void pthread_mutex_consistent(pthread_mutex_t* p_mutex) -{ - int err = ::pthread_mutex_consistent(p_mutex); - if (err != 0) throw make_system_error("pthread_mutex_consistent", err); -} - -inline int pthread_mutex_lock(pthread_mutex_t* p_mutex) -{ - int err = ::pthread_mutex_lock(p_mutex); - return (err == 0 || err == EOWNERDEAD) ? err : - throw make_system_error("pthread_mutex_lock", err); -} - -inline void pthread_mutex_unlock(pthread_mutex_t* p_mutex) -{ - int err = ::pthread_mutex_unlock(p_mutex); - if (err != 0) throw make_system_error("pthread_mutex_unlock", err); -} - -// pthread condition variable -inline void pthread_condattr_init(pthread_condattr_t* p_attr) -{ - int err = ::pthread_condattr_init(p_attr); - if (err != 0) throw make_system_error("pthread_condattr_init", err); -} - -inline void pthread_condattr_destroy(pthread_condattr_t* p_attr) -{ - int err = ::pthread_condattr_destroy(p_attr); - if (err != 0) throw make_system_error("pthread_condattr_destroy", err); -} - -inline void pthread_condattr_setpshared(pthread_condattr_t* p_attr, int val) -{ - int err = ::pthread_condattr_setpshared(p_attr, val); - if (err != 0) throw make_system_error("pthread_condattr_setpshared", err); -} - -inline void pthread_cond_init( - pthread_cond_t* p_cond, pthread_condattr_t const* p_attr) -{ - int err = ::pthread_cond_init(p_cond, p_attr); - if (err != 0) throw make_system_error("pthread_cond_init", err); -} - -inline void pthread_cond_destroy(pthread_cond_t* p_cond) -{ - int err = ::pthread_cond_destroy(p_cond); - if (err != 0) throw make_system_error("pthread_cond_destroy", err); -} - -inline int pthread_cond_wait(pthread_cond_t* p_cond, pthread_mutex_t* p_mutex) -{ - int err = ::pthread_cond_wait(p_cond, p_mutex); - return (err == 0 || err == EOWNERDEAD) ? err : - throw make_system_error("pthread_cond_wait", err); -} - -inline void pthread_cond_signal(pthread_cond_t* p_cond) -{ - int err = ::pthread_cond_signal(p_cond); - if (err != 0) throw make_system_error("pthread_cond_signal", err); -} - -inline void pthread_cond_broadcast(pthread_cond_t* p_cond) -{ - int err = ::pthread_cond_broadcast(p_cond); - if (err != 0) throw make_system_error("pthread_cond_broadcast", err); -} - -} // unnamed namespace - -} // namespace aux - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#endif // BOOST_WINDOWS - -#include - -#endif // BOOST_LOG_POSIX_WRAPPER_HPP_INCLUDED_ diff --git a/src/pthread_wrappers.hpp b/src/pthread_wrappers.hpp index 3075ca1..c5c3cf6 100644 --- a/src/pthread_wrappers.hpp +++ b/src/pthread_wrappers.hpp @@ -29,6 +29,8 @@ namespace boost { BOOST_LOG_OPEN_NAMESPACE +namespace ipc { + namespace aux { #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST) @@ -46,7 +48,7 @@ struct pthread_mutex_attributes { int err = pthread_mutexattr_init(&this->attrs); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to initialize pthread mutex attributes"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex attributes", (err)); } ~pthread_mutex_attributes() @@ -67,7 +69,7 @@ struct pthread_condition_variable_attributes { int err = pthread_condattr_init(&this->attrs); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to initialize pthread condition variable attributes"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable attributes", (err)); } ~pthread_condition_variable_attributes() @@ -101,19 +103,19 @@ struct interprocess_mutex pthread_mutex_attributes attrs; int err = pthread_mutexattr_settype(&attrs.attrs, PTHREAD_MUTEX_NORMAL); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to set pthread mutex type"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to set pthread mutex type", (err)); err = pthread_mutexattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to make pthread mutex process-shared"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex process-shared", (err)); #if defined(BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST) err = pthread_mutexattr_setrobust(&attrs.attrs, PTHREAD_MUTEX_ROBUST); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to make pthread mutex robust"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread mutex robust", (err)); #endif err = pthread_mutex_init(&this->mutex, &attrs.attrs); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to initialize pthread mutex"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread mutex", (err)); } ~interprocess_mutex() @@ -129,7 +131,7 @@ struct interprocess_mutex throw lock_owner_dead(); #endif if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to lock pthread mutex"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to lock pthread mutex", (err)); } void unlock() BOOST_NOEXCEPT @@ -142,7 +144,7 @@ struct interprocess_mutex { int err = pthread_mutex_consistent(&this->mutex); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to recover pthread mutex from a crashed thread"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to recover pthread mutex from a crashed thread", (err)); } #endif @@ -160,11 +162,11 @@ struct interprocess_condition_variable pthread_condition_variable_attributes attrs; int err = pthread_condattr_setpshared(&attrs.attrs, PTHREAD_PROCESS_SHARED); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to make pthread condition variable process-shared"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to make pthread condition variable process-shared", (err)); err = pthread_cond_init(&this->cond, &attrs.attrs); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to initialize pthread condition variable"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to initialize pthread condition variable", (err)); } ~interprocess_condition_variable() @@ -176,21 +178,21 @@ struct interprocess_condition_variable { int err = pthread_cond_signal(&this->cond); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to notify one thread on a pthread condition variable"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify one thread on a pthread condition variable", (err)); } void notify_all() { int err = pthread_cond_broadcast(&this->cond); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to notify all threads on a pthread condition variable"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to notify all threads on a pthread condition variable", (err)); } void wait(interprocess_mutex& mutex) { int err = pthread_cond_wait(&this->cond, &mutex.mutex); if (BOOST_UNLIKELY(err != 0)) - BOOST_LOG_THROW_DESCR(boost::log::system_error, "Failed to wait on a pthread condition variable"); + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, "Failed to wait on a pthread condition variable", (err)); } BOOST_DELETED_FUNCTION(interprocess_condition_variable(interprocess_condition_variable const&)) @@ -201,6 +203,8 @@ struct interprocess_condition_variable } // namespace aux +} // namespace ipc + BOOST_LOG_CLOSE_NAMESPACE // namespace log } // namespace boost diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index fae0e4c..7650004 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1220,11 +1220,10 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ m_pImpl->m_File.open(m_pImpl->m_FileName, m_pImpl->m_FileOpenMode); if (!m_pImpl->m_File.is_open()) { - filesystem_error err( + BOOST_THROW_EXCEPTION(filesystem_error( "Failed to open file for writing", m_pImpl->m_FileName, - system::error_code(system::errc::io_error, system::generic_category())); - BOOST_THROW_EXCEPTION(err); + system::error_code(system::errc::io_error, system::generic_category()))); } if (!m_pImpl->m_OpenHandler.empty()) diff --git a/src/text_ipc_message_queue_backend.cpp b/src/text_ipc_message_queue_backend.cpp deleted file mode 100644 index 2592d6c..0000000 --- a/src/text_ipc_message_queue_backend.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright Lingxi Li 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 text_ipc_message_queue_backend.cpp - * \author Lingxi Li - * \date 18.10.2015 - * - * \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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ipc_message_queue_posix.hpp" -#include "ipc_message_queue_win.hpp" -#include - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace sinks { - -//////////////////////////////////////////////////////////////////////////////// -// Interprocess message queue sink backend implementation -//////////////////////////////////////////////////////////////////////////////// -//! Sink implementation data -template < typename CharT > -struct basic_text_ipc_message_queue_backend< CharT >::implementation -{ - message_queue_type m_MessageQueue; - queue_policy_type m_QueuePolicy; - message_policy_type m_MessagePolicy; -}; - -template < typename CharT > -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::open_mode const - basic_text_ipc_message_queue_backend< CharT >::create_only; - -template < typename CharT > -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::open_mode const - basic_text_ipc_message_queue_backend< CharT >::open_only; - -template < typename CharT > -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::open_mode const - basic_text_ipc_message_queue_backend< CharT >::open_or_create; - -template < typename CharT > -BOOST_LOG_API basic_text_ipc_message_queue_backend< CharT >::basic_text_ipc_message_queue_backend() -{ - construct(log::aux::empty_arg_list()); -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::construct( - char const* message_queue_name, - open_mode mode, - unsigned int max_queue_size, - unsigned int max_message_size, - queue_policy_type queue_policy_val, - message_policy_type message_policy_val, - permissions const& perms) -{ - m_pImpl = new implementation(); - m_pImpl->m_MessageQueue.open(message_queue_name, mode, max_queue_size, - max_message_size, perms); - m_pImpl->m_QueuePolicy = queue_policy_val; - m_pImpl->m_MessagePolicy = message_policy_val; -} - -template < typename CharT > -BOOST_LOG_API basic_text_ipc_message_queue_backend< CharT >::~basic_text_ipc_message_queue_backend() -{ - delete m_pImpl; -} - -template < typename CharT> -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::message_queue_type& -basic_text_ipc_message_queue_backend< CharT >::message_queue() -{ - return m_pImpl->m_MessageQueue; -} - -template < typename CharT> -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::message_queue_type const& -basic_text_ipc_message_queue_backend< CharT >::message_queue() const -{ - return m_pImpl->m_MessageQueue; -} - -template < typename CharT > -BOOST_LOG_API std::string basic_text_ipc_message_queue_backend< CharT >::name() const -{ - return message_queue().name(); -} - -template < typename CharT > -BOOST_LOG_API bool basic_text_ipc_message_queue_backend< CharT >::open( - char const* name, open_mode mode, unsigned int max_queue_size, unsigned int max_message_size, - permissions const& perms) -{ - return message_queue().open(name, mode, max_queue_size, max_message_size, perms); -} - -template < typename CharT > -BOOST_LOG_API bool basic_text_ipc_message_queue_backend< CharT >::is_open() const -{ - return message_queue().is_open(); -} - -template < typename CharT > -BOOST_LOG_API unsigned int basic_text_ipc_message_queue_backend< CharT >::max_queue_size() const -{ - return message_queue().max_queue_size(); -} - -template < typename CharT > -BOOST_LOG_API unsigned int basic_text_ipc_message_queue_backend< CharT >::max_message_size() const -{ - return message_queue().max_message_size(); -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::stop() -{ - message_queue().stop(); -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::reset() -{ - message_queue().reset(); -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::close() -{ - message_queue().close(); -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::set_queue_policy(queue_policy_type policy) -{ - m_pImpl->m_QueuePolicy = policy; -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::set_message_policy(message_policy_type policy) -{ - m_pImpl->m_MessagePolicy = policy; -} - -template < typename CharT > -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::queue_policy_type -basic_text_ipc_message_queue_backend< CharT >::queue_policy() const -{ - return m_pImpl->m_QueuePolicy; -} - -template < typename CharT > -BOOST_LOG_API typename basic_text_ipc_message_queue_backend< CharT >::message_policy_type -basic_text_ipc_message_queue_backend< CharT >::message_policy() const -{ - return m_pImpl->m_MessagePolicy; -} - -template < typename CharT > -BOOST_LOG_API void basic_text_ipc_message_queue_backend< CharT >::consume( - record_view const&, string_type const& message) -{ - // No associated message queue, return directly. - if (!is_open()) return; - - unsigned int message_size = static_cast< unsigned int >(message.size() * sizeof(char_type)); - - // Deal with messages that are too long. - if (message_size > max_message_size()) - { - switch (message_policy()) - { - case drop_when_too_long: - return; - case truncate_when_too_long: - message_size = max_message_size(); - break; - default: // case throw_when_too_long: - throw std::logic_error("Message is too long."); - } - } - - // Send message. - if (queue_policy() == block_when_full) - { - message_queue().send(message.c_str(), message_size); - } - else - { - bool succeeded = message_queue().try_send(message.c_str(), message_size); - if (queue_policy() == throw_when_full && !succeeded) - { - throw std::runtime_error("Message queue is full."); - } - } -} - -//! Explicitly instantiate sink backend implementation -#ifdef BOOST_LOG_USE_CHAR -template class basic_text_ipc_message_queue_backend< char >; -#endif -#ifdef BOOST_LOG_USE_WCHAR_T -template class basic_text_ipc_message_queue_backend< wchar_t >; -#endif - -} // namespace sinks - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#include diff --git a/src/thread_id.cpp b/src/thread_id.cpp index cccd3d1..e3a70a4 100644 --- a/src/thread_id.cpp +++ b/src/thread_id.cpp @@ -32,8 +32,7 @@ #include #include #else -#include -#include +#include #include #endif #if !defined(BOOST_LOG_USE_COMPILER_TLS) @@ -212,7 +211,7 @@ BOOST_LOG_API thread::id const& get_id() { if (int err = pthread_key_create(&g_key, &deleter)) { - BOOST_THROW_EXCEPTION(system::system_error(err, system::system_category(), "Failed to create a thread-specific storage for thread id")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create a thread-specific storage for thread id", (err)); } } diff --git a/src/thread_specific.cpp b/src/thread_specific.cpp index c494b8b..a8b62ce 100644 --- a/src/thread_specific.cpp +++ b/src/thread_specific.cpp @@ -24,6 +24,7 @@ #if defined(BOOST_THREAD_PLATFORM_WIN32) #include +#include #include namespace boost { @@ -37,7 +38,7 @@ thread_specific_base::thread_specific_base() m_Key = TlsAlloc(); if (BOOST_UNLIKELY(m_Key == TLS_OUT_OF_INDEXES)) { - BOOST_LOG_THROW_DESCR(system_error, "TLS capacity depleted"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (boost::system::errc::not_enough_memory)); } } @@ -89,7 +90,7 @@ struct pthread_key_traits if (BOOST_UNLIKELY(res != 0)) { delete pkey; - BOOST_LOG_THROW_DESCR(system_error, "TLS capacity depleted"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res)); } stg = pkey; } @@ -129,7 +130,7 @@ struct pthread_key_traits< KeyT, true > const int res = pthread_key_create(&caster.as_key, NULL); if (BOOST_UNLIKELY(res != 0)) { - BOOST_LOG_THROW_DESCR(system_error, "TLS capacity depleted"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res)); } stg = caster.as_storage; } @@ -167,7 +168,7 @@ struct pthread_key_traits< KeyT*, true > const int res = pthread_key_create(&key, NULL); if (BOOST_UNLIKELY(res != 0)) { - BOOST_LOG_THROW_DESCR(system_error, "TLS capacity depleted"); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "TLS capacity depleted", (res)); } stg = static_cast< void* >(key); } diff --git a/src/timestamp.cpp b/src/timestamp.cpp index 0f3b940..25b8c47 100644 --- a/src/timestamp.cpp +++ b/src/timestamp.cpp @@ -29,12 +29,12 @@ #include #include #include +#include #endif #include #include #include -#include -#include +#include #endif #include @@ -132,8 +132,7 @@ timestamp get_timestamp_realtime_clock() if (BOOST_UNLIKELY(clock_gettime(CLOCK_REALTIME, &ts) != 0)) { const int err = errno; - BOOST_THROW_EXCEPTION(boost::system::system_error( - err, boost::system::system_category(), "Failed to acquire current time")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err)); } return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec); @@ -156,8 +155,7 @@ timestamp get_timestamp_monotonic_clock() get_timestamp = &get_timestamp_realtime_clock; return get_timestamp_realtime_clock(); } - BOOST_THROW_EXCEPTION(boost::system::system_error( - err, boost::system::system_category(), "Failed to acquire current time")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to acquire current time", (err)); } return timestamp(static_cast< uint64_t >(ts.tv_sec) * UINT64_C(1000000000) + ts.tv_nsec); @@ -186,8 +184,7 @@ BOOST_LOG_API int64_t duration::milliseconds() const kern_return_t err = mach_timebase_info(&timebase_info); if (err != KERN_SUCCESS) { - BOOST_THROW_EXCEPTION(boost::system::system_error( - err, boost::system::system_category(), "Failed to initialize timebase info")); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to initialize timebase info", (boost::system::errc::not_supported)); } }