Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:27

0001 /*
0002  *                Copyright Lingxi Li 2015.
0003  *             Copyright Andrey Semashev 2016.
0004  * Distributed under the Boost Software License, Version 1.0.
0005  *    (See accompanying file LICENSE_1_0.txt or copy at
0006  *          http://www.boost.org/LICENSE_1_0.txt)
0007  */
0008 /*!
0009  * \file   utility/ipc/reliable_message_queue.hpp
0010  * \author Lingxi Li
0011  * \author Andrey Semashev
0012  * \date   01.01.2016
0013  *
0014  * The header contains declaration of a reliable interprocess message queue.
0015  */
0016 
0017 #ifndef BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_
0018 #define BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_
0019 
0020 #include <boost/log/detail/config.hpp>
0021 #include <cstddef>
0022 #include <boost/cstdint.hpp>
0023 #include <boost/move/core.hpp>
0024 #include <boost/log/keywords/open_mode.hpp>
0025 #include <boost/log/keywords/name.hpp>
0026 #include <boost/log/keywords/capacity.hpp>
0027 #include <boost/log/keywords/block_size.hpp>
0028 #include <boost/log/keywords/overflow_policy.hpp>
0029 #include <boost/log/keywords/permissions.hpp>
0030 #include <boost/log/utility/open_mode.hpp>
0031 #include <boost/log/utility/permissions.hpp>
0032 #include <boost/log/utility/ipc/object_name.hpp>
0033 #include <boost/log/detail/parameter_tools.hpp>
0034 #include <boost/log/detail/header.hpp>
0035 
0036 #ifdef BOOST_HAS_PRAGMA_ONCE
0037 #pragma once
0038 #endif
0039 
0040 namespace boost {
0041 
0042 BOOST_LOG_OPEN_NAMESPACE
0043 
0044 namespace ipc {
0045 
0046 namespace aux {
0047 
0048 template< typename T, typename R >
0049 struct enable_if_byte {};
0050 template< typename R >
0051 struct enable_if_byte< char, R > { typedef R type; };
0052 template< typename R >
0053 struct enable_if_byte< signed char, R > { typedef R type; };
0054 template< typename R >
0055 struct enable_if_byte< unsigned char, R > { typedef R type; };
0056 #if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
0057 template< typename R >
0058 struct enable_if_byte< std::byte, R > { typedef R type; };
0059 #endif
0060 
0061 } // namespace aux
0062 
0063 /*!
0064  * \brief A reliable interprocess message queue
0065  *
0066  * The queue implements a reliable one-way channel of passing messages from one or multiple writers to a single reader.
0067  * The format of the messages is user-defined and must be consistent across all writers and the reader. The queue does
0068  * not enforce any specific format of the messages, other than they should be supplied as a contiguous array of bytes.
0069  *
0070  * The queue internally uses a process-shared storage identified by an \c object_name (the queue name). Refer to \c object_name
0071  * documentation for details on restrictions imposed on object names.
0072  *
0073  * The queue storage is organized as a fixed number of blocks of a fixed size. The block size must be an integer power of 2 and
0074  * is expressed in bytes. Each written message, together with some metadata added by the queue, consumes an integer number
0075  * of blocks. Each read message received by the reader releases the blocks allocated for that message. As such the maximum size
0076  * of a message is slightly less than block size times capacity of the queue. For efficiency, it is recommended to choose
0077  * block size large enough to accommodate most of the messages to be passed through the queue.
0078  *
0079  * The queue is considered empty when no messages are enqueued (all blocks are free). The queue is considered full at the point
0080  * of enqueueing a message when there is not enough free blocks to accommodate the message.
0081  *
0082  * The queue is reliable in that it will not drop successfully sent messages that are not received by the reader, other than the
0083  * case when a non-empty queue is destroyed by the last user. If a message cannot be enqueued by the writer because the queue is
0084  * full, the queue can either block the writer or return an error or throw an exception, depending on the policy specified at
0085  * the queue creation. The policy is object local, i.e. different writers and the reader can have different overflow policies.
0086  *
0087  * If the queue is empty and the reader attempts to dequeue a message, it will block until a message is enqueued by a writer.
0088  *
0089  * A blocked reader or writer can be unblocked by calling \c stop_local. After this method is called, all threads blocked on
0090  * this particular object are released and return \c operation_result::aborted. The other instances of the queue (in the current
0091  * or other processes) are unaffected. In order to restore the normal functioning of the queue instance after the \c stop_local
0092  * call the user has to invoke \c reset_local.
0093  *
0094  * The queue does not guarantee any particular order of received messages from different writer threads. Messages sent by a
0095  * particular writer thread will be received in the order of sending.
0096  *
0097  * Methods of this class are not thread-safe, unless otherwise specified.
0098  */
0099 class reliable_message_queue
0100 {
0101 public:
0102     //! Result codes for various operations on the queue
0103     enum operation_result
0104     {
0105         succeeded,    //!< The operation has completed successfully
0106         no_space,     //!< The message could not be sent because the queue is full
0107         aborted       //!< The operation has been aborted because the queue method <tt>stop_local()</tt> has been called
0108     };
0109 
0110     //! Interprocess queue overflow policies
0111     enum overflow_policy
0112     {
0113         //! Block the send operation when the queue is full
0114         block_on_overflow,
0115         //! Return \c operation_result::no_space when the queue is full
0116         fail_on_overflow,
0117         //! Throw \c capacity_limit_reached exception when the queue is full
0118         throw_on_overflow
0119     };
0120 
0121     //! Queue message size type
0122     typedef uint32_t size_type;
0123 
0124 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0125 
0126     BOOST_MOVABLE_BUT_NOT_COPYABLE(reliable_message_queue)
0127 
0128 private:
0129     typedef void (*receive_handler)(void* state, const void* data, size_type size);
0130 
0131     struct fixed_buffer_state
0132     {
0133         uint8_t* data;
0134         size_type size;
0135     };
0136 
0137     struct implementation;
0138     implementation* m_impl;
0139 
0140 #endif // !defined(BOOST_LOG_DOXYGEN_PASS)
0141 
0142 public:
0143     /*!
0144      * Default constructor. The method constructs an object that is not associated with any
0145      * message queue.
0146      *
0147      * \post <tt>is_open() == false</tt>
0148      */
0149     BOOST_CONSTEXPR reliable_message_queue() BOOST_NOEXCEPT : m_impl(NULL)
0150     {
0151     }
0152 
0153     /*!
0154      * Constructor. The method is used to construct an object and create the associated
0155      * message queue. The constructed object will be in running state if the message queue is
0156      * successfully created.
0157      *
0158      * \post <tt>is_open() == true</tt>
0159      *
0160      * \param name Name of the message queue to be associated with.
0161      * \param capacity Maximum number of allocation blocks the queue can hold.
0162      * \param block_size Size in bytes of allocation block. Must be a power of 2.
0163      * \param oflow_policy Queue behavior policy in case of overflow.
0164      * \param perms Access permissions for the associated message queue.
0165      */
0166     reliable_message_queue
0167     (
0168         open_mode::create_only_tag,
0169         object_name const& name,
0170         uint32_t capacity,
0171         size_type block_size,
0172         overflow_policy oflow_policy = block_on_overflow,
0173         permissions const& perms = permissions()
0174     ) :
0175         m_impl(NULL)
0176     {
0177         this->create(name, capacity, block_size, oflow_policy, perms);
0178     }
0179 
0180     /*!
0181      * Constructor. The method is used to construct an object and create or open the associated
0182      * message queue. The constructed object will be in running state if the message queue is
0183      * successfully created or opened. If the message queue that is identified by the name already
0184      * exists then the other queue parameters are ignored. The actual queue parameters can be obtained
0185      * with accessors from the constructed object.
0186      *
0187      * \post <tt>is_open() == true</tt>
0188      *
0189      * \param name Name of the message queue to be associated with.
0190      * \param capacity Maximum number of allocation blocks the queue can hold.
0191      * \param block_size Size in bytes of allocation block. Must be a power of 2.
0192      * \param oflow_policy Queue behavior policy in case of overflow.
0193      * \param perms Access permissions for the associated message queue.
0194      */
0195     reliable_message_queue
0196     (
0197         open_mode::open_or_create_tag,
0198         object_name const& name,
0199         uint32_t capacity,
0200         size_type block_size,
0201         overflow_policy oflow_policy = block_on_overflow,
0202         permissions const& perms = permissions()
0203     ) :
0204         m_impl(NULL)
0205     {
0206         this->open_or_create(name, capacity, block_size, oflow_policy, perms);
0207     }
0208 
0209     /*!
0210      * Constructor. The method is used to construct an object and open the existing
0211      * message queue. The constructed object will be in running state if the message queue is
0212      * successfully opened.
0213      *
0214      * \post <tt>is_open() == true</tt>
0215      *
0216      * \param name Name of the message queue to be associated with.
0217      * \param oflow_policy Queue behavior policy in case of overflow.
0218      * \param perms Access permissions for the associated message queue. The permissions will only be used
0219      *              if the queue implementation has to create system objects while operating.
0220      *              This parameter is currently not used on POSIX systems.
0221      */
0222     reliable_message_queue
0223     (
0224         open_mode::open_only_tag,
0225         object_name const& name,
0226         overflow_policy oflow_policy = block_on_overflow,
0227         permissions const& perms = permissions()
0228     ) :
0229         m_impl(NULL)
0230     {
0231         this->open(name, oflow_policy, perms);
0232     }
0233 
0234     /*!
0235      * Constructor with named parameters. The method is used to construct an object and create or open
0236      * the associated message queue. The constructed object will be in running state if the message queue is
0237      * successfully created.
0238      *
0239      * The following named parameters are accepted:
0240      *
0241      * * open_mode - One of the open mode tags: \c open_mode::create_only, \c open_mode::open_only or
0242      *               \c open_mode::open_or_create.
0243      * * name - Name of the message queue to be associated with.
0244      * * capacity - Maximum number of allocation blocks the queue can hold. Used only if the queue is created.
0245      * * block_size - Size in bytes of allocation block. Must be a power of 2. Used only if the queue is created.
0246      * * overflow_policy - Queue behavior policy in case of overflow, see \c overflow_policy.
0247      * * permissions - Access permissions for the associated message queue.
0248      *
0249      * \post <tt>is_open() == true</tt>
0250      */
0251 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0252     BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(reliable_message_queue, construct)
0253 #else
0254     template< typename... Args >
0255     explicit reliable_message_queue(Args const&... args);
0256 #endif
0257 
0258     /*!
0259      * Destructor. Calls <tt>close()</tt>.
0260      */
0261     ~reliable_message_queue() BOOST_NOEXCEPT
0262     {
0263         this->close();
0264     }
0265 
0266     /*!
0267      * Move constructor. The method move-constructs an object from \c other. After
0268      * the call, the constructed object becomes \c other, while \c other is left in
0269      * default constructed state.
0270      *
0271      * \param that The object to be moved.
0272      */
0273     reliable_message_queue(BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT :
0274         m_impl(that.m_impl)
0275     {
0276         that.m_impl = NULL;
0277     }
0278 
0279     /*!
0280      * Move assignment operator. If the object is associated with a message queue,
0281      * <tt>close()</tt> is first called and the precondition to calling <tt>close()</tt>
0282      * applies. After the call, the object becomes \a that while \a that is left
0283      * in default constructed state.
0284      *
0285      * \param that The object to be moved.
0286      *
0287      * \return A reference to the assigned object.
0288      */
0289     reliable_message_queue& operator= (BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT
0290     {
0291         reliable_message_queue other(static_cast< BOOST_RV_REF(reliable_message_queue) >(that));
0292         this->swap(other);
0293         return *this;
0294     }
0295 
0296     /*!
0297      * The method swaps the object with \a that.
0298      *
0299      * \param that The other object to swap with.
0300      */
0301     void swap(reliable_message_queue& that) BOOST_NOEXCEPT
0302     {
0303         implementation* p = m_impl;
0304         m_impl = that.m_impl;
0305         that.m_impl = p;
0306     }
0307 
0308     //! Swaps the two \c reliable_message_queue objects.
0309     friend void swap(reliable_message_queue& a, reliable_message_queue& b) BOOST_NOEXCEPT
0310     {
0311         a.swap(b);
0312     }
0313 
0314     /*!
0315      * The method creates the message queue to be associated with the object. After the call,
0316      * the object will be in running state if a message queue is successfully created.
0317      *
0318      * \pre <tt>is_open() == false</tt>
0319      * \post <tt>is_open() == true</tt>
0320      *
0321      * \param name Name of the message queue to be associated with.
0322      * \param capacity Maximum number of allocation blocks the queue can hold.
0323      * \param block_size Size in bytes of allocation block. Must be a power of 2.
0324      * \param oflow_policy Queue behavior policy in case of overflow.
0325      * \param perms Access permissions for the associated message queue.
0326      */
0327     BOOST_LOG_API void create
0328     (
0329         object_name const& name,
0330         uint32_t capacity,
0331         size_type block_size,
0332         overflow_policy oflow_policy = block_on_overflow,
0333         permissions const& perms = permissions()
0334     );
0335 
0336     /*!
0337      * The method creates or opens the message queue to be associated with the object.
0338      * After the call, the object will be in running state if a message queue is successfully
0339      * created or opened. If the message queue that is identified by the name already exists then
0340      * the other queue parameters are ignored. The actual queue parameters can be obtained
0341      * with accessors from this object after this method returns.
0342      *
0343      * \pre <tt>is_open() == false</tt>
0344      * \post <tt>is_open() == true</tt>
0345      *
0346      * \param name Name of the message queue to be associated with.
0347      * \param capacity Maximum number of allocation blocks the queue can hold.
0348      * \param block_size Size in bytes of allocation block. Must be a power of 2.
0349      * \param oflow_policy Queue behavior policy in case of overflow.
0350      * \param perms Access permissions for the associated message queue.
0351      */
0352     BOOST_LOG_API void open_or_create
0353     (
0354         object_name const& name,
0355         uint32_t capacity,
0356         size_type block_size,
0357         overflow_policy oflow_policy = block_on_overflow,
0358         permissions const& perms = permissions()
0359     );
0360 
0361     /*!
0362      * The method opens the existing message queue to be associated with the object.
0363      * After the call, the object will be in running state if a message queue is successfully
0364      * opened.
0365      *
0366      * \pre <tt>is_open() == false</tt>
0367      * \post <tt>is_open() == true</tt>
0368      *
0369      * \param name Name of the message queue to be associated with.
0370      * \param oflow_policy Queue behavior policy in case of overflow.
0371      * \param perms Access permissions for the associated message queue. The permissions will only be used
0372      *              if the queue implementation has to create system objects while operating.
0373      *              This parameter is currently not used on POSIX systems.
0374      */
0375     BOOST_LOG_API void open
0376     (
0377         object_name const& name,
0378         overflow_policy oflow_policy = block_on_overflow,
0379         permissions const& perms = permissions()
0380     );
0381 
0382     /*!
0383      * Tests whether the object is associated with any message queue.
0384      *
0385      * \return \c true if the object is associated with a message queue, and \c false otherwise.
0386      */
0387     bool is_open() const BOOST_NOEXCEPT
0388     {
0389         return m_impl != NULL;
0390     }
0391 
0392     /*!
0393      * This method empties the associated message queue. Concurrent calls to this method, <tt>send()</tt>,
0394      * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, and <tt>stop_local()</tt> are allowed.
0395      *
0396      * \pre <tt>is_open() == true</tt>
0397      */
0398     BOOST_LOG_API void clear();
0399 
0400     /*!
0401      * The method returns the name of the associated message queue.
0402      *
0403      * \pre <tt>is_open() == true</tt>
0404      *
0405      * \return Name of the associated message queue
0406      */
0407     BOOST_LOG_API object_name const& name() const;
0408 
0409     /*!
0410      * The method returns the maximum number of allocation blocks the associated message queue
0411      * can hold. Note that the returned value may be different from the corresponding
0412      * value passed to the constructor or <tt>open_or_create()</tt>, for the message queue may
0413      * not have been created by this object.
0414      *
0415      * \pre <tt>is_open() == true</tt>
0416      *
0417      * \return Maximum number of allocation blocks the associated message queue can hold.
0418      */
0419     BOOST_LOG_API uint32_t capacity() const;
0420 
0421     /*!
0422      * The method returns the allocation block size, in bytes. Each message in the
0423      * associated message queue consumes an integer number of allocation blocks.
0424      * Note that the returned value may be different from the corresponding value passed
0425      * to the constructor or <tt>open_or_create()</tt>, for the message queue may not
0426      * have been created by this object.
0427      *
0428      * \pre <tt>is_open() == true</tt>
0429      *
0430      * \return Allocation block size, in bytes.
0431      */
0432     BOOST_LOG_API size_type block_size() const;
0433 
0434     /*!
0435      * The method wakes up all threads that are blocked in calls to <tt>send()</tt> or
0436      * <tt>receive()</tt>. Those calls would then return <tt>operation_result::aborted</tt>.
0437      * Note that, the method does not block until the woken-up threads have actually
0438      * returned from <tt>send()</tt> or <tt>receive()</tt>. Other means is needed to ensure
0439      * that calls to <tt>send()</tt> or <tt>receive()</tt> have returned, e.g., joining the
0440      * threads that might be blocking on the calls.
0441      *
0442      * The method also puts the object in stopped state. When in stopped state, calls to
0443      * <tt>send()</tt> or <tt>receive()</tt> will return immediately with return value
0444      * <tt>operation_result::aborted</tt> when they would otherwise block in running state.
0445      *
0446      * Concurrent calls to this method, <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0447      * <tt>try_receive()</tt>, and <tt>clear()</tt> are allowed.
0448      *
0449      * \pre <tt>is_open() == true</tt>
0450      */
0451     BOOST_LOG_API void stop_local();
0452 
0453     /*!
0454      * The method puts the object in running state where calls to <tt>send()</tt> or
0455      * <tt>receive()</tt> may block. This method is not thread-safe.
0456      *
0457      * \pre <tt>is_open() == true</tt>
0458      */
0459     BOOST_LOG_API void reset_local();
0460 
0461     /*!
0462      * The method disassociates the associated message queue, if any. No other threads
0463      * should be using this object before calling this method. The <tt>stop_local()</tt> method
0464      * can be used to have any threads currently blocked in <tt>send()</tt> or
0465      * <tt>receive()</tt> return, and prevent further calls to them from blocking. Typically,
0466      * before calling this method, one would first call <tt>stop_local()</tt> and then join all
0467      * threads that might be blocking on <tt>send()</tt> or <tt>receive()</tt> to ensure that
0468      * they have returned from the calls. The associated message queue is destroyed if the
0469      * object represents the last outstanding reference to it.
0470      *
0471      * \post <tt>is_open() == false</tt>
0472      */
0473     void close() BOOST_NOEXCEPT
0474     {
0475         if (is_open())
0476             do_close();
0477     }
0478 
0479     /*!
0480      * The method sends a message to the associated message queue. When the object is in
0481      * running state and the queue has no free space for the message, the method either blocks
0482      * or throws an exception, depending on the overflow policy that was specified on the queue
0483      * opening/creation. If blocking policy is in effect, the blocking can be interrupted by
0484      * calling <tt>stop_local()</tt>, in which case the method returns \c operation_result::aborted.
0485      * When the object is already in the stopped state, the method does not block but returns
0486      * immediately with return value \c operation_result::aborted.
0487      *
0488      * It is possible to send an empty message by passing \c 0 to the parameter \c message_size.
0489      *
0490      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>,
0491      * <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0492      *
0493      * \pre <tt>is_open() == true</tt>
0494      *
0495      * \param message_data The message data to send. Ignored when \c message_size is \c 0.
0496      * \param message_size Size of the message data in bytes. If the size is larger than
0497      *                     the associated message queue capacity, an <tt>std::logic_error</tt> exception is thrown.
0498      *
0499      * \retval operation_result::succeeded if the operation is successful
0500      * \retval operation_result::no_space if \c overflow_policy::fail_on_overflow is in effect and the queue is full
0501      * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
0502      *
0503      * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue
0504      *                capacity, <tt>system_error</tt> in case if a native OS method fails.
0505      */
0506     BOOST_LOG_API operation_result send(void const* message_data, size_type message_size);
0507 
0508     /*!
0509      * The method performs an attempt to send a message to the associated message queue.
0510      * The method is non-blocking, and always returns immediately.
0511      * <tt>boost::system::system_error</tt> is thrown for errors resulting from native
0512      * operating system calls. Note that it is possible to send an empty message by passing
0513      * \c 0 to the parameter \c message_size. Concurrent calls to <tt>send()</tt>,
0514      * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, <tt>stop_local()</tt>,
0515      * and <tt>clear()</tt> are allowed.
0516      *
0517      * \pre <tt>is_open() == true</tt>
0518      *
0519      * \param message_data The message data to send. Ignored when \c message_size is \c 0.
0520      * \param message_size Size of the message data in bytes. If the size is larger than the
0521      *                     maximum size allowed by the associated message queue, an
0522      *                     <tt>std::logic_error</tt> exception is thrown.
0523      *
0524      * \return \c true if the message is successfully sent, and \c false otherwise (e.g.,
0525      *         when the queue is full).
0526      *
0527      * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue
0528      *                capacity, <tt>system_error</tt> in case if a native OS method fails.
0529      */
0530     BOOST_LOG_API bool try_send(void const* message_data, size_type message_size);
0531 
0532     /*!
0533      * The method takes a message from the associated message queue. When the object is in
0534      * running state and the queue is empty, the method blocks. The blocking is interrupted
0535      * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
0536      * When the object is already in the stopped state and the queue is empty, the method
0537      * does not block but returns immediately with return value \c operation_result::aborted.
0538      *
0539      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0540      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0541      *
0542      * \pre <tt>is_open() == true</tt>
0543      *
0544      * \param buffer The memory buffer to store the received message in.
0545      * \param buffer_size The size of the buffer, in bytes.
0546      * \param message_size Receives the size of the received message, in bytes.
0547      *
0548      * \retval operation_result::succeeded if the operation is successful
0549      * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
0550      */
0551     operation_result receive(void* buffer, size_type buffer_size, size_type& message_size)
0552     {
0553         fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size };
0554         operation_result result = do_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state);
0555         message_size = buffer_size - state.size;
0556         return result;
0557     }
0558 
0559     /*!
0560      * The method takes a message from the associated message queue. When the object is in
0561      * running state and the queue is empty, the method blocks. The blocking is interrupted
0562      * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
0563      * When the object is already in the stopped state and the queue is empty, the method
0564      * does not block but returns immediately with return value \c operation_result::aborted.
0565      *
0566      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0567      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0568      *
0569      * \pre <tt>is_open() == true</tt>
0570      *
0571      * \param buffer The memory buffer to store the received message in.
0572      * \param message_size Receives the size of the received message, in bytes.
0573      *
0574      * \retval operation_result::succeeded if the operation is successful
0575      * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
0576      */
0577     template< typename ElementT, size_type SizeV >
0578 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0579     typename aux::enable_if_byte< ElementT, operation_result >::type
0580 #else
0581     operation_result
0582 #endif
0583     receive(ElementT (&buffer)[SizeV], size_type& message_size)
0584     {
0585         return receive(buffer, SizeV, message_size);
0586     }
0587 
0588     /*!
0589      * The method takes a message from the associated message queue. When the object is in
0590      * running state and the queue is empty, the method blocks. The blocking is interrupted
0591      * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
0592      * When the object is already in the stopped state and the queue is empty, the method
0593      * does not block but returns immediately with return value \c operation_result::aborted.
0594      *
0595      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0596      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0597      *
0598      * \pre <tt>is_open() == true</tt>
0599      *
0600      * \param container The container to store the received message in. The container should have
0601      *                  value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt>
0602      *                  and support inserting elements at the end.
0603      *
0604      * \retval operation_result::succeeded if the operation is successful
0605      * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
0606      */
0607     template< typename ContainerT >
0608 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0609     typename aux::enable_if_byte< typename ContainerT::value_type, operation_result >::type
0610 #else
0611     operation_result
0612 #endif
0613     receive(ContainerT& container)
0614     {
0615         return do_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container);
0616     }
0617 
0618     /*!
0619      * The method performs an attempt to take a message from the associated message queue. The
0620      * method is non-blocking, and always returns immediately.
0621      *
0622      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0623      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0624      *
0625      * \pre <tt>is_open() == true</tt>
0626      *
0627      * \param buffer The memory buffer to store the received message in.
0628      * \param buffer_size The size of the buffer, in bytes.
0629      * \param message_size Receives the size of the received message, in bytes.
0630      *
0631      * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
0632      *         when the queue is empty).
0633      */
0634     bool try_receive(void* buffer, size_type buffer_size, size_type& message_size)
0635     {
0636         fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size };
0637         bool result = do_try_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state);
0638         message_size = buffer_size - state.size;
0639         return result;
0640     }
0641 
0642     /*!
0643      * The method performs an attempt to take a message from the associated message queue. The
0644      * method is non-blocking, and always returns immediately.
0645      *
0646      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0647      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0648      *
0649      * \pre <tt>is_open() == true</tt>
0650      *
0651      * \param buffer The memory buffer to store the received message in.
0652      * \param message_size Receives the size of the received message, in bytes.
0653      *
0654      * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
0655      *         when the queue is empty).
0656      */
0657     template< typename ElementT, size_type SizeV >
0658 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0659     typename aux::enable_if_byte< ElementT, bool >::type
0660 #else
0661     bool
0662 #endif
0663     try_receive(ElementT (&buffer)[SizeV], size_type& message_size)
0664     {
0665         return try_receive(buffer, SizeV, message_size);
0666     }
0667 
0668     /*!
0669      * The method performs an attempt to take a message from the associated message queue. The
0670      * method is non-blocking, and always returns immediately.
0671      *
0672      * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
0673      * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
0674      *
0675      * \pre <tt>is_open() == true</tt>
0676      *
0677      * \param container The container to store the received message in. The container should have
0678      *                  value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt>
0679      *                  and support inserting elements at the end.
0680      *
0681      * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
0682      *         when the queue is empty).
0683      */
0684     template< typename ContainerT >
0685 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0686     typename aux::enable_if_byte< typename ContainerT::value_type, bool >::type
0687 #else
0688     bool
0689 #endif
0690     try_receive(ContainerT& container)
0691     {
0692         return do_try_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container);
0693     }
0694 
0695     /*!
0696      * The method frees system-wide resources, associated with the interprocess queue with the supplied name.
0697      * The queue referred to by the specified name must not be opened in any process at the point of this call.
0698      * After this call succeeds a new queue with the specified name can be created.
0699      *
0700      * This call can be useful to recover from an earlier process misbehavior (e.g. a crash without properly
0701      * closing the message queue). In this case resources allocated for the interprocess queue may remain
0702      * allocated after the last process closed the queue, which in turn may prevent creating a new queue with
0703      * the same name. By calling this method before creating a queue the application can attempt to ensure
0704      * it starts with a clean slate.
0705      *
0706      * On some platforms resources associated with the queue are automatically reclaimed by the operating system
0707      * when the last process using those resources terminates (even if it terminates abnormally). On these
0708      * platforms this call may be a no-op. However, portable code should still call this method at appropriate
0709      * places to ensure compatibility with other platforms and future library versions, which may change implementation
0710      * of the queue.
0711      *
0712      * \param name Name of the message queue to be removed.
0713      */
0714     static BOOST_LOG_API void remove(object_name const& name);
0715 
0716 #if !defined(BOOST_LOG_DOXYGEN_PASS)
0717 private:
0718     //! Implementation of the constructor with named arguments
0719     template< typename ArgsT >
0720     void construct(ArgsT const& args)
0721     {
0722         m_impl = NULL;
0723         construct_dispatch(args[keywords::open_mode], args);
0724     }
0725 
0726     //! Implementation of the constructor with named arguments
0727     template< typename ArgsT >
0728     void construct_dispatch(open_mode::create_only_tag, ArgsT const& args)
0729     {
0730         this->create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]);
0731     }
0732 
0733     //! Implementation of the constructor with named arguments
0734     template< typename ArgsT >
0735     void construct_dispatch(open_mode::open_or_create_tag, ArgsT const& args)
0736     {
0737         this->open_or_create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]);
0738     }
0739 
0740     //! Implementation of the constructor with named arguments
0741     template< typename ArgsT >
0742     void construct_dispatch(open_mode::open_only_tag, ArgsT const& args)
0743     {
0744         this->open(args[keywords::name], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]);
0745     }
0746 
0747     //! Closes the message queue, if it's open
0748     BOOST_LOG_API void do_close() BOOST_NOEXCEPT;
0749 
0750     //! Receives the message from the queue and calls the handler to place the data in the user's storage
0751     BOOST_LOG_API operation_result do_receive(receive_handler handler, void* state);
0752     //! Attempts to receives the message from the queue and calls the handler to place the data in the user's storage
0753     BOOST_LOG_API bool do_try_receive(receive_handler handler, void* state);
0754 
0755     //! Fixed buffer receive handler
0756     static BOOST_LOG_API void fixed_buffer_receive_handler(void* state, const void* data, size_type size);
0757     //! Receive handler for a container
0758     template< typename ContainerT >
0759     static void container_receive_handler(void* state, const void* data, size_type size)
0760     {
0761         ContainerT* const container = static_cast< ContainerT* >(state);
0762         container->insert
0763         (
0764             container->end(),
0765             static_cast< typename ContainerT::value_type const* >(data),
0766             static_cast< typename ContainerT::value_type const* >(data) + size
0767         );
0768     }
0769 #endif
0770 };
0771 
0772 } // namespace ipc
0773 
0774 BOOST_LOG_CLOSE_NAMESPACE // namespace log
0775 
0776 } // namespace boost
0777 
0778 #include <boost/log/detail/footer.hpp>
0779 
0780 #endif // BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_