reliable_message_queue.hpp 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /*
  2. * Copyright Lingxi Li 2015.
  3. * Copyright Andrey Semashev 2016.
  4. * Distributed under the Boost Software License, Version 1.0.
  5. * (See accompanying file LICENSE_1_0.txt or copy at
  6. * http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. /*!
  9. * \file utility/ipc/reliable_message_queue.hpp
  10. * \author Lingxi Li
  11. * \author Andrey Semashev
  12. * \date 01.01.2016
  13. *
  14. * The header contains declaration of a reliable interprocess message queue.
  15. */
  16. #ifndef BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_
  17. #define BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_
  18. #include <boost/log/detail/config.hpp>
  19. #include <cstddef>
  20. #include <boost/cstdint.hpp>
  21. #include <boost/move/core.hpp>
  22. #include <boost/log/keywords/open_mode.hpp>
  23. #include <boost/log/keywords/name.hpp>
  24. #include <boost/log/keywords/capacity.hpp>
  25. #include <boost/log/keywords/block_size.hpp>
  26. #include <boost/log/keywords/overflow_policy.hpp>
  27. #include <boost/log/keywords/permissions.hpp>
  28. #include <boost/log/utility/open_mode.hpp>
  29. #include <boost/log/utility/permissions.hpp>
  30. #include <boost/log/utility/ipc/object_name.hpp>
  31. #include <boost/log/detail/parameter_tools.hpp>
  32. #include <boost/log/detail/header.hpp>
  33. #ifdef BOOST_HAS_PRAGMA_ONCE
  34. #pragma once
  35. #endif
  36. namespace boost {
  37. BOOST_LOG_OPEN_NAMESPACE
  38. namespace ipc {
  39. namespace aux {
  40. template< typename T, typename R >
  41. struct enable_if_byte {};
  42. template< typename R >
  43. struct enable_if_byte< char, R > { typedef R type; };
  44. template< typename R >
  45. struct enable_if_byte< signed char, R > { typedef R type; };
  46. template< typename R >
  47. struct enable_if_byte< unsigned char, R > { typedef R type; };
  48. #if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603
  49. template< typename R >
  50. struct enable_if_byte< std::byte, R > { typedef R type; };
  51. #endif
  52. } // namespace aux
  53. /*!
  54. * \brief A reliable interprocess message queue
  55. *
  56. * The queue implements a reliable one-way channel of passing messages from one or multiple writers to a single reader.
  57. * The format of the messages is user-defined and must be consistent across all writers and the reader. The queue does
  58. * not enforce any specific format of the messages, other than they should be supplied as a contiguous array of bytes.
  59. *
  60. * The queue internally uses a process-shared storage identified by an \c object_name (the queue name). Refer to \c object_name
  61. * documentation for details on restrictions imposed on object names.
  62. *
  63. * 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
  64. * is expressed in bytes. Each written message, together with some metadata added by the queue, consumes an integer number
  65. * of blocks. Each read message received by the reader releases the blocks allocated for that message. As such the maximum size
  66. * of a message is slightly less than block size times capacity of the queue. For efficiency, it is recommended to choose
  67. * block size large enough to accommodate most of the messages to be passed through the queue.
  68. *
  69. * The queue is considered empty when no messages are enqueued (all blocks are free). The queue is considered full at the point
  70. * of enqueueing a message when there is not enough free blocks to accommodate the message.
  71. *
  72. * The queue is reliable in that it will not drop successfully sent messages that are not received by the reader, other than the
  73. * 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
  74. * full, the queue can either block the writer or return an error or throw an exception, depending on the policy specified at
  75. * the queue creation. The policy is object local, i.e. different writers and the reader can have different overflow policies.
  76. *
  77. * If the queue is empty and the reader attempts to dequeue a message, it will block until a message is enqueued by a writer.
  78. *
  79. * A blocked reader or writer can be unblocked by calling \c stop_local. After this method is called, all threads blocked on
  80. * this particular object are released and return \c operation_result::aborted. The other instances of the queue (in the current
  81. * or other processes) are unaffected. In order to restore the normal functioning of the queue instance after the \c stop_local
  82. * call the user has to invoke \c reset_local.
  83. *
  84. * The queue does not guarantee any particular order of received messages from different writer threads. Messages sent by a
  85. * particular writer thread will be received in the order of sending.
  86. *
  87. * Methods of this class are not thread-safe, unless otherwise specified.
  88. */
  89. class reliable_message_queue
  90. {
  91. public:
  92. //! Result codes for various operations on the queue
  93. enum operation_result
  94. {
  95. succeeded, //!< The operation has completed successfully
  96. no_space, //!< The message could not be sent because the queue is full
  97. aborted //!< The operation has been aborted because the queue method <tt>stop_local()</tt> has been called
  98. };
  99. //! Interprocess queue overflow policies
  100. enum overflow_policy
  101. {
  102. //! Block the send operation when the queue is full
  103. block_on_overflow,
  104. //! Return \c operation_result::no_space when the queue is full
  105. fail_on_overflow,
  106. //! Throw \c capacity_limit_reached exception when the queue is full
  107. throw_on_overflow
  108. };
  109. //! Queue message size type
  110. typedef uint32_t size_type;
  111. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  112. BOOST_MOVABLE_BUT_NOT_COPYABLE(reliable_message_queue)
  113. private:
  114. typedef void (*receive_handler)(void* state, const void* data, size_type size);
  115. struct fixed_buffer_state
  116. {
  117. uint8_t* data;
  118. size_type size;
  119. };
  120. struct implementation;
  121. implementation* m_impl;
  122. #endif // !defined(BOOST_LOG_DOXYGEN_PASS)
  123. public:
  124. /*!
  125. * Default constructor. The method constructs an object that is not associated with any
  126. * message queue.
  127. *
  128. * \post <tt>is_open() == false</tt>
  129. */
  130. BOOST_CONSTEXPR reliable_message_queue() BOOST_NOEXCEPT : m_impl(NULL)
  131. {
  132. }
  133. /*!
  134. * Constructor. The method is used to construct an object and create the associated
  135. * message queue. The constructed object will be in running state if the message queue is
  136. * successfully created.
  137. *
  138. * \post <tt>is_open() == true</tt>
  139. *
  140. * \param name Name of the message queue to be associated with.
  141. * \param capacity Maximum number of allocation blocks the queue can hold.
  142. * \param block_size Size in bytes of allocation block. Must be a power of 2.
  143. * \param oflow_policy Queue behavior policy in case of overflow.
  144. * \param perms Access permissions for the associated message queue.
  145. */
  146. reliable_message_queue
  147. (
  148. open_mode::create_only_tag,
  149. object_name const& name,
  150. uint32_t capacity,
  151. size_type block_size,
  152. overflow_policy oflow_policy = block_on_overflow,
  153. permissions const& perms = permissions()
  154. ) :
  155. m_impl(NULL)
  156. {
  157. this->create(name, capacity, block_size, oflow_policy, perms);
  158. }
  159. /*!
  160. * Constructor. The method is used to construct an object and create or open the associated
  161. * message queue. The constructed object will be in running state if the message queue is
  162. * successfully created or opened. If the message queue that is identified by the name already
  163. * exists then the other queue parameters are ignored. The actual queue parameters can be obtained
  164. * with accessors from the constructed object.
  165. *
  166. * \post <tt>is_open() == true</tt>
  167. *
  168. * \param name Name of the message queue to be associated with.
  169. * \param capacity Maximum number of allocation blocks the queue can hold.
  170. * \param block_size Size in bytes of allocation block. Must be a power of 2.
  171. * \param oflow_policy Queue behavior policy in case of overflow.
  172. * \param perms Access permissions for the associated message queue.
  173. */
  174. reliable_message_queue
  175. (
  176. open_mode::open_or_create_tag,
  177. object_name const& name,
  178. uint32_t capacity,
  179. size_type block_size,
  180. overflow_policy oflow_policy = block_on_overflow,
  181. permissions const& perms = permissions()
  182. ) :
  183. m_impl(NULL)
  184. {
  185. this->open_or_create(name, capacity, block_size, oflow_policy, perms);
  186. }
  187. /*!
  188. * Constructor. The method is used to construct an object and open the existing
  189. * message queue. The constructed object will be in running state if the message queue is
  190. * successfully opened.
  191. *
  192. * \post <tt>is_open() == true</tt>
  193. *
  194. * \param name Name of the message queue to be associated with.
  195. * \param oflow_policy Queue behavior policy in case of overflow.
  196. * \param perms Access permissions for the associated message queue. The permissions will only be used
  197. * if the queue implementation has to create system objects while operating.
  198. * This parameter is currently not used on POSIX systems.
  199. */
  200. reliable_message_queue
  201. (
  202. open_mode::open_only_tag,
  203. object_name const& name,
  204. overflow_policy oflow_policy = block_on_overflow,
  205. permissions const& perms = permissions()
  206. ) :
  207. m_impl(NULL)
  208. {
  209. this->open(name, oflow_policy, perms);
  210. }
  211. /*!
  212. * Constructor with named parameters. The method is used to construct an object and create or open
  213. * the associated message queue. The constructed object will be in running state if the message queue is
  214. * successfully created.
  215. *
  216. * The following named parameters are accepted:
  217. *
  218. * * open_mode - One of the open mode tags: \c open_mode::create_only, \c open_mode::open_only or
  219. * \c open_mode::open_or_create.
  220. * * name - Name of the message queue to be associated with.
  221. * * capacity - Maximum number of allocation blocks the queue can hold. Used only if the queue is created.
  222. * * block_size - Size in bytes of allocation block. Must be a power of 2. Used only if the queue is created.
  223. * * overflow_policy - Queue behavior policy in case of overflow, see \c overflow_policy.
  224. * * permissions - Access permissions for the associated message queue.
  225. *
  226. * \post <tt>is_open() == true</tt>
  227. */
  228. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  229. BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(reliable_message_queue, construct)
  230. #else
  231. template< typename... Args >
  232. explicit reliable_message_queue(Args const&... args);
  233. #endif
  234. /*!
  235. * Destructor. Calls <tt>close()</tt>.
  236. */
  237. ~reliable_message_queue() BOOST_NOEXCEPT
  238. {
  239. this->close();
  240. }
  241. /*!
  242. * Move constructor. The method move-constructs an object from \c other. After
  243. * the call, the constructed object becomes \c other, while \c other is left in
  244. * default constructed state.
  245. *
  246. * \param that The object to be moved.
  247. */
  248. reliable_message_queue(BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT :
  249. m_impl(that.m_impl)
  250. {
  251. that.m_impl = NULL;
  252. }
  253. /*!
  254. * Move assignment operator. If the object is associated with a message queue,
  255. * <tt>close()</tt> is first called and the precondition to calling <tt>close()</tt>
  256. * applies. After the call, the object becomes \a that while \a that is left
  257. * in default constructed state.
  258. *
  259. * \param that The object to be moved.
  260. *
  261. * \return A reference to the assigned object.
  262. */
  263. reliable_message_queue& operator= (BOOST_RV_REF(reliable_message_queue) that) BOOST_NOEXCEPT
  264. {
  265. reliable_message_queue other(static_cast< BOOST_RV_REF(reliable_message_queue) >(that));
  266. this->swap(other);
  267. return *this;
  268. }
  269. /*!
  270. * The method swaps the object with \a that.
  271. *
  272. * \param that The other object to swap with.
  273. */
  274. void swap(reliable_message_queue& that) BOOST_NOEXCEPT
  275. {
  276. implementation* p = m_impl;
  277. m_impl = that.m_impl;
  278. that.m_impl = p;
  279. }
  280. //! Swaps the two \c reliable_message_queue objects.
  281. friend void swap(reliable_message_queue& a, reliable_message_queue& b) BOOST_NOEXCEPT
  282. {
  283. a.swap(b);
  284. }
  285. /*!
  286. * The method creates the message queue to be associated with the object. After the call,
  287. * the object will be in running state if a message queue is successfully created.
  288. *
  289. * \pre <tt>is_open() == false</tt>
  290. * \post <tt>is_open() == true</tt>
  291. *
  292. * \param name Name of the message queue to be associated with.
  293. * \param capacity Maximum number of allocation blocks the queue can hold.
  294. * \param block_size Size in bytes of allocation block. Must be a power of 2.
  295. * \param oflow_policy Queue behavior policy in case of overflow.
  296. * \param perms Access permissions for the associated message queue.
  297. */
  298. BOOST_LOG_API void create
  299. (
  300. object_name const& name,
  301. uint32_t capacity,
  302. size_type block_size,
  303. overflow_policy oflow_policy = block_on_overflow,
  304. permissions const& perms = permissions()
  305. );
  306. /*!
  307. * The method creates or opens the message queue to be associated with the object.
  308. * After the call, the object will be in running state if a message queue is successfully
  309. * created or opened. If the message queue that is identified by the name already exists then
  310. * the other queue parameters are ignored. The actual queue parameters can be obtained
  311. * with accessors from this object after this method returns.
  312. *
  313. * \pre <tt>is_open() == false</tt>
  314. * \post <tt>is_open() == true</tt>
  315. *
  316. * \param name Name of the message queue to be associated with.
  317. * \param capacity Maximum number of allocation blocks the queue can hold.
  318. * \param block_size Size in bytes of allocation block. Must be a power of 2.
  319. * \param oflow_policy Queue behavior policy in case of overflow.
  320. * \param perms Access permissions for the associated message queue.
  321. */
  322. BOOST_LOG_API void open_or_create
  323. (
  324. object_name const& name,
  325. uint32_t capacity,
  326. size_type block_size,
  327. overflow_policy oflow_policy = block_on_overflow,
  328. permissions const& perms = permissions()
  329. );
  330. /*!
  331. * The method opens the existing message queue to be associated with the object.
  332. * After the call, the object will be in running state if a message queue is successfully
  333. * opened.
  334. *
  335. * \pre <tt>is_open() == false</tt>
  336. * \post <tt>is_open() == true</tt>
  337. *
  338. * \param name Name of the message queue to be associated with.
  339. * \param oflow_policy Queue behavior policy in case of overflow.
  340. * \param perms Access permissions for the associated message queue. The permissions will only be used
  341. * if the queue implementation has to create system objects while operating.
  342. * This parameter is currently not used on POSIX systems.
  343. */
  344. BOOST_LOG_API void open
  345. (
  346. object_name const& name,
  347. overflow_policy oflow_policy = block_on_overflow,
  348. permissions const& perms = permissions()
  349. );
  350. /*!
  351. * Tests whether the object is associated with any message queue.
  352. *
  353. * \return \c true if the object is associated with a message queue, and \c false otherwise.
  354. */
  355. bool is_open() const BOOST_NOEXCEPT
  356. {
  357. return m_impl != NULL;
  358. }
  359. /*!
  360. * This method empties the associated message queue. Concurrent calls to this method, <tt>send()</tt>,
  361. * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, and <tt>stop_local()</tt> are allowed.
  362. *
  363. * \pre <tt>is_open() == true</tt>
  364. */
  365. BOOST_LOG_API void clear();
  366. /*!
  367. * The method returns the name of the associated message queue.
  368. *
  369. * \pre <tt>is_open() == true</tt>
  370. *
  371. * \return Name of the associated message queue
  372. */
  373. BOOST_LOG_API object_name const& name() const;
  374. /*!
  375. * The method returns the maximum number of allocation blocks the associated message queue
  376. * can hold. Note that the returned value may be different from the corresponding
  377. * value passed to the constructor or <tt>open_or_create()</tt>, for the message queue may
  378. * not have been created by this object.
  379. *
  380. * \pre <tt>is_open() == true</tt>
  381. *
  382. * \return Maximum number of allocation blocks the associated message queue can hold.
  383. */
  384. BOOST_LOG_API uint32_t capacity() const;
  385. /*!
  386. * The method returns the allocation block size, in bytes. Each message in the
  387. * associated message queue consumes an integer number of allocation blocks.
  388. * Note that the returned value may be different from the corresponding value passed
  389. * to the constructor or <tt>open_or_create()</tt>, for the message queue may not
  390. * have been created by this object.
  391. *
  392. * \pre <tt>is_open() == true</tt>
  393. *
  394. * \return Allocation block size, in bytes.
  395. */
  396. BOOST_LOG_API size_type block_size() const;
  397. /*!
  398. * The method wakes up all threads that are blocked in calls to <tt>send()</tt> or
  399. * <tt>receive()</tt>. Those calls would then return <tt>operation_result::aborted</tt>.
  400. * Note that, the method does not block until the woken-up threads have actually
  401. * returned from <tt>send()</tt> or <tt>receive()</tt>. Other means is needed to ensure
  402. * that calls to <tt>send()</tt> or <tt>receive()</tt> have returned, e.g., joining the
  403. * threads that might be blocking on the calls.
  404. *
  405. * The method also puts the object in stopped state. When in stopped state, calls to
  406. * <tt>send()</tt> or <tt>receive()</tt> will return immediately with return value
  407. * <tt>operation_result::aborted</tt> when they would otherwise block in running state.
  408. *
  409. * Concurrent calls to this method, <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  410. * <tt>try_receive()</tt>, and <tt>clear()</tt> are allowed.
  411. *
  412. * \pre <tt>is_open() == true</tt>
  413. */
  414. BOOST_LOG_API void stop_local();
  415. /*!
  416. * The method puts the object in running state where calls to <tt>send()</tt> or
  417. * <tt>receive()</tt> may block. This method is not thread-safe.
  418. *
  419. * \pre <tt>is_open() == true</tt>
  420. */
  421. BOOST_LOG_API void reset_local();
  422. /*!
  423. * The method disassociates the associated message queue, if any. No other threads
  424. * should be using this object before calling this method. The <tt>stop_local()</tt> method
  425. * can be used to have any threads currently blocked in <tt>send()</tt> or
  426. * <tt>receive()</tt> return, and prevent further calls to them from blocking. Typically,
  427. * before calling this method, one would first call <tt>stop_local()</tt> and then join all
  428. * threads that might be blocking on <tt>send()</tt> or <tt>receive()</tt> to ensure that
  429. * they have returned from the calls. The associated message queue is destroyed if the
  430. * object represents the last outstanding reference to it.
  431. *
  432. * \post <tt>is_open() == false</tt>
  433. */
  434. void close() BOOST_NOEXCEPT
  435. {
  436. if (is_open())
  437. do_close();
  438. }
  439. /*!
  440. * The method sends a message to the associated message queue. When the object is in
  441. * running state and the queue has no free space for the message, the method either blocks
  442. * or throws an exception, depending on the overflow policy that was specified on the queue
  443. * opening/creation. If blocking policy is in effect, the blocking can be interrupted by
  444. * calling <tt>stop_local()</tt>, in which case the method returns \c operation_result::aborted.
  445. * When the object is already in the stopped state, the method does not block but returns
  446. * immediately with return value \c operation_result::aborted.
  447. *
  448. * It is possible to send an empty message by passing \c 0 to the parameter \c message_size.
  449. *
  450. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>,
  451. * <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  452. *
  453. * \pre <tt>is_open() == true</tt>
  454. *
  455. * \param message_data The message data to send. Ignored when \c message_size is \c 0.
  456. * \param message_size Size of the message data in bytes. If the size is larger than
  457. * the associated message queue capacity, an <tt>std::logic_error</tt> exception is thrown.
  458. *
  459. * \retval operation_result::succeeded if the operation is successful
  460. * \retval operation_result::no_space if \c overflow_policy::fail_on_overflow is in effect and the queue is full
  461. * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
  462. *
  463. * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue
  464. * capacity, <tt>system_error</tt> in case if a native OS method fails.
  465. */
  466. BOOST_LOG_API operation_result send(void const* message_data, size_type message_size);
  467. /*!
  468. * The method performs an attempt to send a message to the associated message queue.
  469. * The method is non-blocking, and always returns immediately.
  470. * <tt>boost::system::system_error</tt> is thrown for errors resulting from native
  471. * operating system calls. Note that it is possible to send an empty message by passing
  472. * \c 0 to the parameter \c message_size. Concurrent calls to <tt>send()</tt>,
  473. * <tt>try_send()</tt>, <tt>receive()</tt>, <tt>try_receive()</tt>, <tt>stop_local()</tt>,
  474. * and <tt>clear()</tt> are allowed.
  475. *
  476. * \pre <tt>is_open() == true</tt>
  477. *
  478. * \param message_data The message data to send. Ignored when \c message_size is \c 0.
  479. * \param message_size Size of the message data in bytes. If the size is larger than the
  480. * maximum size allowed by the associated message queue, an
  481. * <tt>std::logic_error</tt> exception is thrown.
  482. *
  483. * \return \c true if the message is successfully sent, and \c false otherwise (e.g.,
  484. * when the queue is full).
  485. *
  486. * <b>Throws:</b> <tt>std::logic_error</tt> in case if the message size exceeds the queue
  487. * capacity, <tt>system_error</tt> in case if a native OS method fails.
  488. */
  489. BOOST_LOG_API bool try_send(void const* message_data, size_type message_size);
  490. /*!
  491. * The method takes a message from the associated message queue. When the object is in
  492. * running state and the queue is empty, the method blocks. The blocking is interrupted
  493. * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
  494. * When the object is already in the stopped state and the queue is empty, the method
  495. * does not block but returns immediately with return value \c operation_result::aborted.
  496. *
  497. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  498. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  499. *
  500. * \pre <tt>is_open() == true</tt>
  501. *
  502. * \param buffer The memory buffer to store the received message in.
  503. * \param buffer_size The size of the buffer, in bytes.
  504. * \param message_size Receives the size of the received message, in bytes.
  505. *
  506. * \retval operation_result::succeeded if the operation is successful
  507. * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
  508. */
  509. operation_result receive(void* buffer, size_type buffer_size, size_type& message_size)
  510. {
  511. fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size };
  512. operation_result result = do_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state);
  513. message_size = buffer_size - state.size;
  514. return result;
  515. }
  516. /*!
  517. * The method takes a message from the associated message queue. When the object is in
  518. * running state and the queue is empty, the method blocks. The blocking is interrupted
  519. * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
  520. * When the object is already in the stopped state and the queue is empty, the method
  521. * does not block but returns immediately with return value \c operation_result::aborted.
  522. *
  523. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  524. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  525. *
  526. * \pre <tt>is_open() == true</tt>
  527. *
  528. * \param buffer The memory buffer to store the received message in.
  529. * \param message_size Receives the size of the received message, in bytes.
  530. *
  531. * \retval operation_result::succeeded if the operation is successful
  532. * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
  533. */
  534. template< typename ElementT, size_type SizeV >
  535. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  536. typename aux::enable_if_byte< ElementT, operation_result >::type
  537. #else
  538. operation_result
  539. #endif
  540. receive(ElementT (&buffer)[SizeV], size_type& message_size)
  541. {
  542. return receive(buffer, SizeV, message_size);
  543. }
  544. /*!
  545. * The method takes a message from the associated message queue. When the object is in
  546. * running state and the queue is empty, the method blocks. The blocking is interrupted
  547. * when <tt>stop_local()</tt> is called, in which case the method returns \c operation_result::aborted.
  548. * When the object is already in the stopped state and the queue is empty, the method
  549. * does not block but returns immediately with return value \c operation_result::aborted.
  550. *
  551. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  552. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  553. *
  554. * \pre <tt>is_open() == true</tt>
  555. *
  556. * \param container The container to store the received message in. The container should have
  557. * value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt>
  558. * and support inserting elements at the end.
  559. *
  560. * \retval operation_result::succeeded if the operation is successful
  561. * \retval operation_result::aborted if the call was interrupted by <tt>stop_local()</tt>
  562. */
  563. template< typename ContainerT >
  564. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  565. typename aux::enable_if_byte< typename ContainerT::value_type, operation_result >::type
  566. #else
  567. operation_result
  568. #endif
  569. receive(ContainerT& container)
  570. {
  571. return do_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container);
  572. }
  573. /*!
  574. * The method performs an attempt to take a message from the associated message queue. The
  575. * method is non-blocking, and always returns immediately.
  576. *
  577. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  578. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  579. *
  580. * \pre <tt>is_open() == true</tt>
  581. *
  582. * \param buffer The memory buffer to store the received message in.
  583. * \param buffer_size The size of the buffer, in bytes.
  584. * \param message_size Receives the size of the received message, in bytes.
  585. *
  586. * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
  587. * when the queue is empty).
  588. */
  589. bool try_receive(void* buffer, size_type buffer_size, size_type& message_size)
  590. {
  591. fixed_buffer_state state = { static_cast< uint8_t* >(buffer), buffer_size };
  592. bool result = do_try_receive(&reliable_message_queue::fixed_buffer_receive_handler, &state);
  593. message_size = buffer_size - state.size;
  594. return result;
  595. }
  596. /*!
  597. * The method performs an attempt to take a message from the associated message queue. The
  598. * method is non-blocking, and always returns immediately.
  599. *
  600. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  601. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  602. *
  603. * \pre <tt>is_open() == true</tt>
  604. *
  605. * \param buffer The memory buffer to store the received message in.
  606. * \param message_size Receives the size of the received message, in bytes.
  607. *
  608. * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
  609. * when the queue is empty).
  610. */
  611. template< typename ElementT, size_type SizeV >
  612. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  613. typename aux::enable_if_byte< ElementT, bool >::type
  614. #else
  615. bool
  616. #endif
  617. try_receive(ElementT (&buffer)[SizeV], size_type& message_size)
  618. {
  619. return try_receive(buffer, SizeV, message_size);
  620. }
  621. /*!
  622. * The method performs an attempt to take a message from the associated message queue. The
  623. * method is non-blocking, and always returns immediately.
  624. *
  625. * Concurrent calls to <tt>send()</tt>, <tt>try_send()</tt>, <tt>receive()</tt>,
  626. * <tt>try_receive()</tt>, <tt>stop_local()</tt>, and <tt>clear()</tt> are allowed.
  627. *
  628. * \pre <tt>is_open() == true</tt>
  629. *
  630. * \param container The container to store the received message in. The container should have
  631. * value type of <tt>char</tt>, <tt>signed char</tt> or <tt>unsigned char</tt>
  632. * and support inserting elements at the end.
  633. *
  634. * \return \c true if a message is successfully received, and \c false otherwise (e.g.,
  635. * when the queue is empty).
  636. */
  637. template< typename ContainerT >
  638. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  639. typename aux::enable_if_byte< typename ContainerT::value_type, bool >::type
  640. #else
  641. bool
  642. #endif
  643. try_receive(ContainerT& container)
  644. {
  645. return do_try_receive(&reliable_message_queue::container_receive_handler< ContainerT >, &container);
  646. }
  647. /*!
  648. * The method frees system-wide resources, associated with the interprocess queue with the supplied name.
  649. * The queue referred to by the specified name must not be opened in any process at the point of this call.
  650. * After this call succeeds a new queue with the specified name can be created.
  651. *
  652. * This call can be useful to recover from an earlier process misbehavior (e.g. a crash without properly
  653. * closing the message queue). In this case resources allocated for the interprocess queue may remain
  654. * allocated after the last process closed the queue, which in turn may prevent creating a new queue with
  655. * the same name. By calling this method before creating a queue the application can attempt to ensure
  656. * it starts with a clean slate.
  657. *
  658. * On some platforms resources associated with the queue are automatically reclaimed by the operating system
  659. * when the last process using those resources terminates (even if it terminates abnormally). On these
  660. * platforms this call may be a no-op. However, portable code should still call this method at appropriate
  661. * places to ensure compatibility with other platforms and future library versions, which may change implementation
  662. * of the queue.
  663. *
  664. * \param name Name of the message queue to be removed.
  665. */
  666. static BOOST_LOG_API void remove(object_name const& name);
  667. #if !defined(BOOST_LOG_DOXYGEN_PASS)
  668. private:
  669. //! Implementation of the constructor with named arguments
  670. template< typename ArgsT >
  671. void construct(ArgsT const& args)
  672. {
  673. m_impl = NULL;
  674. construct_dispatch(args[keywords::open_mode], args);
  675. }
  676. //! Implementation of the constructor with named arguments
  677. template< typename ArgsT >
  678. void construct_dispatch(open_mode::create_only_tag, ArgsT const& args)
  679. {
  680. this->create(args[keywords::name], args[keywords::capacity], args[keywords::block_size], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]);
  681. }
  682. //! Implementation of the constructor with named arguments
  683. template< typename ArgsT >
  684. void construct_dispatch(open_mode::open_or_create_tag, ArgsT const& args)
  685. {
  686. 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()]);
  687. }
  688. //! Implementation of the constructor with named arguments
  689. template< typename ArgsT >
  690. void construct_dispatch(open_mode::open_only_tag, ArgsT const& args)
  691. {
  692. this->open(args[keywords::name], args[keywords::overflow_policy | block_on_overflow], args[keywords::permissions | permissions()]);
  693. }
  694. //! Closes the message queue, if it's open
  695. BOOST_LOG_API void do_close() BOOST_NOEXCEPT;
  696. //! Receives the message from the queue and calls the handler to place the data in the user's storage
  697. BOOST_LOG_API operation_result do_receive(receive_handler handler, void* state);
  698. //! Attempts to receives the message from the queue and calls the handler to place the data in the user's storage
  699. BOOST_LOG_API bool do_try_receive(receive_handler handler, void* state);
  700. //! Fixed buffer receive handler
  701. static BOOST_LOG_API void fixed_buffer_receive_handler(void* state, const void* data, size_type size);
  702. //! Receive handler for a container
  703. template< typename ContainerT >
  704. static void container_receive_handler(void* state, const void* data, size_type size)
  705. {
  706. ContainerT* const container = static_cast< ContainerT* >(state);
  707. container->insert
  708. (
  709. container->end(),
  710. static_cast< typename ContainerT::value_type const* >(data),
  711. static_cast< typename ContainerT::value_type const* >(data) + size
  712. );
  713. }
  714. #endif
  715. };
  716. } // namespace ipc
  717. BOOST_LOG_CLOSE_NAMESPACE // namespace log
  718. } // namespace boost
  719. #include <boost/log/detail/footer.hpp>
  720. #endif // BOOST_LOG_UTILITY_IPC_RELIABLE_MESSAGE_QUEUE_HPP_INCLUDED_