annotate DEPENDENCIES/generic/include/boost/interprocess/ipc/message_queue.hpp @ 16:2665513ce2d3

Add boost headers
author Chris Cannam
date Tue, 05 Aug 2014 11:11:38 +0100
parents
children c530137014c0
rev   line source
Chris@16 1 //////////////////////////////////////////////////////////////////////////////
Chris@16 2 //
Chris@16 3 // (C) Copyright Ion Gaztanaga 2005-2012. Distributed under the Boost
Chris@16 4 // Software License, Version 1.0. (See accompanying file
Chris@16 5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6 //
Chris@16 7 // See http://www.boost.org/libs/interprocess for documentation.
Chris@16 8 //
Chris@16 9 //////////////////////////////////////////////////////////////////////////////
Chris@16 10
Chris@16 11 #ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP
Chris@16 12 #define BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP
Chris@16 13
Chris@16 14 #include <boost/interprocess/detail/config_begin.hpp>
Chris@16 15 #include <boost/interprocess/detail/workaround.hpp>
Chris@16 16
Chris@16 17 #include <boost/interprocess/shared_memory_object.hpp>
Chris@16 18 #include <boost/interprocess/detail/managed_open_or_create_impl.hpp>
Chris@16 19 #include <boost/interprocess/sync/interprocess_condition.hpp>
Chris@16 20 #include <boost/interprocess/sync/interprocess_mutex.hpp>
Chris@16 21 #include <boost/interprocess/sync/scoped_lock.hpp>
Chris@16 22 #include <boost/interprocess/detail/utilities.hpp>
Chris@16 23 #include <boost/interprocess/offset_ptr.hpp>
Chris@16 24 #include <boost/interprocess/creation_tags.hpp>
Chris@16 25 #include <boost/interprocess/exceptions.hpp>
Chris@16 26 #include <boost/interprocess/permissions.hpp>
Chris@16 27 #include <boost/detail/no_exceptions_support.hpp>
Chris@16 28 #include <boost/interprocess/detail/type_traits.hpp>
Chris@16 29 #include <boost/intrusive/pointer_traits.hpp>
Chris@16 30 #include <boost/type_traits/make_unsigned.hpp>
Chris@16 31 #include <boost/type_traits/alignment_of.hpp>
Chris@16 32 #include <boost/intrusive/pointer_traits.hpp>
Chris@16 33 #include <boost/assert.hpp>
Chris@16 34 #include <algorithm> //std::lower_bound
Chris@16 35 #include <cstddef> //std::size_t
Chris@16 36 #include <cstring> //memcpy
Chris@16 37
Chris@16 38
Chris@16 39 //!\file
Chris@16 40 //!Describes an inter-process message queue. This class allows sending
Chris@16 41 //!messages between processes and allows blocking, non-blocking and timed
Chris@16 42 //!sending and receiving.
Chris@16 43
Chris@16 44 namespace boost{ namespace interprocess{
Chris@16 45
Chris@16 46 namespace ipcdetail
Chris@16 47 {
Chris@16 48 template<class VoidPointer>
Chris@16 49 class msg_queue_initialization_func_t;
Chris@16 50 }
Chris@16 51
Chris@16 52 //!A class that allows sending messages
Chris@16 53 //!between processes.
Chris@16 54 template<class VoidPointer>
Chris@16 55 class message_queue_t
Chris@16 56 {
Chris@16 57 /// @cond
Chris@16 58 //Blocking modes
Chris@16 59 enum block_t { blocking, timed, non_blocking };
Chris@16 60
Chris@16 61 message_queue_t();
Chris@16 62 /// @endcond
Chris@16 63
Chris@16 64 public:
Chris@16 65 typedef VoidPointer void_pointer;
Chris@16 66 typedef typename boost::intrusive::
Chris@16 67 pointer_traits<void_pointer>::template
Chris@16 68 rebind_pointer<char>::type char_ptr;
Chris@16 69 typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
Chris@16 70 typedef typename boost::make_unsigned<difference_type>::type size_type;
Chris@16 71
Chris@16 72 //!Creates a process shared message queue with name "name". For this message queue,
Chris@16 73 //!the maximum number of messages will be "max_num_msg" and the maximum message size
Chris@16 74 //!will be "max_msg_size". Throws on error and if the queue was previously created.
Chris@16 75 message_queue_t(create_only_t create_only,
Chris@16 76 const char *name,
Chris@16 77 size_type max_num_msg,
Chris@16 78 size_type max_msg_size,
Chris@16 79 const permissions &perm = permissions());
Chris@16 80
Chris@16 81 //!Opens or creates a process shared message queue with name "name".
Chris@16 82 //!If the queue is created, the maximum number of messages will be "max_num_msg"
Chris@16 83 //!and the maximum message size will be "max_msg_size". If queue was previously
Chris@16 84 //!created the queue will be opened and "max_num_msg" and "max_msg_size" parameters
Chris@16 85 //!are ignored. Throws on error.
Chris@16 86 message_queue_t(open_or_create_t open_or_create,
Chris@16 87 const char *name,
Chris@16 88 size_type max_num_msg,
Chris@16 89 size_type max_msg_size,
Chris@16 90 const permissions &perm = permissions());
Chris@16 91
Chris@16 92 //!Opens a previously created process shared message queue with name "name".
Chris@16 93 //!If the queue was not previously created or there are no free resources,
Chris@16 94 //!throws an error.
Chris@16 95 message_queue_t(open_only_t open_only,
Chris@16 96 const char *name);
Chris@16 97
Chris@16 98 //!Destroys *this and indicates that the calling process is finished using
Chris@16 99 //!the resource. All opened message queues are still
Chris@16 100 //!valid after destruction. The destructor function will deallocate
Chris@16 101 //!any system resources allocated by the system for use by this process for
Chris@16 102 //!this resource. The resource can still be opened again calling
Chris@16 103 //!the open constructor overload. To erase the message queue from the system
Chris@16 104 //!use remove().
Chris@16 105 ~message_queue_t();
Chris@16 106
Chris@16 107 //!Sends a message stored in buffer "buffer" with size "buffer_size" in the
Chris@16 108 //!message queue with priority "priority". If the message queue is full
Chris@16 109 //!the sender is blocked. Throws interprocess_error on error.
Chris@16 110 void send (const void *buffer, size_type buffer_size,
Chris@16 111 unsigned int priority);
Chris@16 112
Chris@16 113 //!Sends a message stored in buffer "buffer" with size "buffer_size" through the
Chris@16 114 //!message queue with priority "priority". If the message queue is full
Chris@16 115 //!the sender is not blocked and returns false, otherwise returns true.
Chris@16 116 //!Throws interprocess_error on error.
Chris@16 117 bool try_send (const void *buffer, size_type buffer_size,
Chris@16 118 unsigned int priority);
Chris@16 119
Chris@16 120 //!Sends a message stored in buffer "buffer" with size "buffer_size" in the
Chris@16 121 //!message queue with priority "priority". If the message queue is full
Chris@16 122 //!the sender retries until time "abs_time" is reached. Returns true if
Chris@16 123 //!the message has been successfully sent. Returns false if timeout is reached.
Chris@16 124 //!Throws interprocess_error on error.
Chris@16 125 bool timed_send (const void *buffer, size_type buffer_size,
Chris@16 126 unsigned int priority, const boost::posix_time::ptime& abs_time);
Chris@16 127
Chris@16 128 //!Receives a message from the message queue. The message is stored in buffer
Chris@16 129 //!"buffer", which has size "buffer_size". The received message has size
Chris@16 130 //!"recvd_size" and priority "priority". If the message queue is empty
Chris@16 131 //!the receiver is blocked. Throws interprocess_error on error.
Chris@16 132 void receive (void *buffer, size_type buffer_size,
Chris@16 133 size_type &recvd_size,unsigned int &priority);
Chris@16 134
Chris@16 135 //!Receives a message from the message queue. The message is stored in buffer
Chris@16 136 //!"buffer", which has size "buffer_size". The received message has size
Chris@16 137 //!"recvd_size" and priority "priority". If the message queue is empty
Chris@16 138 //!the receiver is not blocked and returns false, otherwise returns true.
Chris@16 139 //!Throws interprocess_error on error.
Chris@16 140 bool try_receive (void *buffer, size_type buffer_size,
Chris@16 141 size_type &recvd_size,unsigned int &priority);
Chris@16 142
Chris@16 143 //!Receives a message from the message queue. The message is stored in buffer
Chris@16 144 //!"buffer", which has size "buffer_size". The received message has size
Chris@16 145 //!"recvd_size" and priority "priority". If the message queue is empty
Chris@16 146 //!the receiver retries until time "abs_time" is reached. Returns true if
Chris@16 147 //!the message has been successfully sent. Returns false if timeout is reached.
Chris@16 148 //!Throws interprocess_error on error.
Chris@16 149 bool timed_receive (void *buffer, size_type buffer_size,
Chris@16 150 size_type &recvd_size,unsigned int &priority,
Chris@16 151 const boost::posix_time::ptime &abs_time);
Chris@16 152
Chris@16 153 //!Returns the maximum number of messages allowed by the queue. The message
Chris@16 154 //!queue must be opened or created previously. Otherwise, returns 0.
Chris@16 155 //!Never throws
Chris@16 156 size_type get_max_msg() const;
Chris@16 157
Chris@16 158 //!Returns the maximum size of message allowed by the queue. The message
Chris@16 159 //!queue must be opened or created previously. Otherwise, returns 0.
Chris@16 160 //!Never throws
Chris@16 161 size_type get_max_msg_size() const;
Chris@16 162
Chris@16 163 //!Returns the number of messages currently stored.
Chris@16 164 //!Never throws
Chris@16 165 size_type get_num_msg() const;
Chris@16 166
Chris@16 167 //!Removes the message queue from the system.
Chris@16 168 //!Returns false on error. Never throws
Chris@16 169 static bool remove(const char *name);
Chris@16 170
Chris@16 171 /// @cond
Chris@16 172 private:
Chris@16 173 typedef boost::posix_time::ptime ptime;
Chris@16 174
Chris@16 175 friend class ipcdetail::msg_queue_initialization_func_t<VoidPointer>;
Chris@16 176
Chris@16 177 bool do_receive(block_t block,
Chris@16 178 void *buffer, size_type buffer_size,
Chris@16 179 size_type &recvd_size, unsigned int &priority,
Chris@16 180 const ptime &abs_time);
Chris@16 181
Chris@16 182 bool do_send(block_t block,
Chris@16 183 const void *buffer, size_type buffer_size,
Chris@16 184 unsigned int priority, const ptime &abs_time);
Chris@16 185
Chris@16 186 //!Returns the needed memory size for the shared message queue.
Chris@16 187 //!Never throws
Chris@16 188 static size_type get_mem_size(size_type max_msg_size, size_type max_num_msg);
Chris@16 189 typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
Chris@16 190 open_create_impl_t m_shmem;
Chris@16 191 /// @endcond
Chris@16 192 };
Chris@16 193
Chris@16 194 /// @cond
Chris@16 195
Chris@16 196 namespace ipcdetail {
Chris@16 197
Chris@16 198 //!This header is the prefix of each message in the queue
Chris@16 199 template<class VoidPointer>
Chris@16 200 class msg_hdr_t
Chris@16 201 {
Chris@16 202 typedef VoidPointer void_pointer;
Chris@16 203 typedef typename boost::intrusive::
Chris@16 204 pointer_traits<void_pointer>::template
Chris@16 205 rebind_pointer<char>::type char_ptr;
Chris@16 206 typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
Chris@16 207 typedef typename boost::make_unsigned<difference_type>::type size_type;
Chris@16 208
Chris@16 209 public:
Chris@16 210 size_type len; // Message length
Chris@16 211 unsigned int priority;// Message priority
Chris@16 212 //!Returns the data buffer associated with this this message
Chris@16 213 void * data(){ return this+1; } //
Chris@16 214 };
Chris@16 215
Chris@16 216 //!This functor is the predicate to order stored messages by priority
Chris@16 217 template<class VoidPointer>
Chris@16 218 class priority_functor
Chris@16 219 {
Chris@16 220 typedef typename boost::intrusive::
Chris@16 221 pointer_traits<VoidPointer>::template
Chris@16 222 rebind_pointer<msg_hdr_t<VoidPointer> >::type msg_hdr_ptr_t;
Chris@16 223
Chris@16 224 public:
Chris@16 225 bool operator()(const msg_hdr_ptr_t &msg1,
Chris@16 226 const msg_hdr_ptr_t &msg2) const
Chris@16 227 { return msg1->priority < msg2->priority; }
Chris@16 228 };
Chris@16 229
Chris@16 230 //!This header is placed in the beginning of the shared memory and contains
Chris@16 231 //!the data to control the queue. This class initializes the shared memory
Chris@16 232 //!in the following way: in ascending memory address with proper alignment
Chris@16 233 //!fillings:
Chris@16 234 //!
Chris@16 235 //!-> mq_hdr_t:
Chris@16 236 //! Main control block that controls the rest of the elements
Chris@16 237 //!
Chris@16 238 //!-> offset_ptr<msg_hdr_t> index [max_num_msg]
Chris@16 239 //! An array of pointers with size "max_num_msg" called index. Each pointer
Chris@16 240 //! points to a preallocated message. Elements of this array are
Chris@16 241 //! reordered in runtime in the following way:
Chris@16 242 //!
Chris@16 243 //! IF BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is defined:
Chris@16 244 //!
Chris@16 245 //! When the current number of messages is "cur_num_msg", the array
Chris@16 246 //! is treated like a circular buffer. Starting from position "cur_first_msg"
Chris@16 247 //! "cur_num_msg" in a circular way, pointers point to inserted messages and the rest
Chris@16 248 //! point to free messages. Those "cur_num_msg" pointers are
Chris@16 249 //! ordered by the priority of the pointed message and by insertion order
Chris@16 250 //! if two messages have the same priority. So the next message to be
Chris@16 251 //! used in a "receive" is pointed by index [(cur_first_msg + cur_num_msg-1)%max_num_msg]
Chris@16 252 //! and the first free message ready to be used in a "send" operation is
Chris@16 253 //! [cur_first_msg] if circular buffer is extended from front,
Chris@16 254 //! [(cur_first_msg + cur_num_msg)%max_num_msg] otherwise.
Chris@16 255 //!
Chris@16 256 //! This transforms the index in a circular buffer with an embedded free
Chris@16 257 //! message queue.
Chris@16 258 //!
Chris@16 259 //! ELSE (BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX is NOT defined):
Chris@16 260 //!
Chris@16 261 //! When the current number of messages is "cur_num_msg", the first
Chris@16 262 //! "cur_num_msg" pointers point to inserted messages and the rest
Chris@16 263 //! point to free messages. The first "cur_num_msg" pointers are
Chris@16 264 //! ordered by the priority of the pointed message and by insertion order
Chris@16 265 //! if two messages have the same priority. So the next message to be
Chris@16 266 //! used in a "receive" is pointed by index [cur_num_msg-1] and the first free
Chris@16 267 //! message ready to be used in a "send" operation is index [cur_num_msg].
Chris@16 268 //!
Chris@16 269 //! This transforms the index in a fixed size priority queue with an embedded free
Chris@16 270 //! message queue.
Chris@16 271 //!
Chris@16 272 //!-> struct message_t
Chris@16 273 //! {
Chris@16 274 //! msg_hdr_t header;
Chris@16 275 //! char[max_msg_size] data;
Chris@16 276 //! } messages [max_num_msg];
Chris@16 277 //!
Chris@16 278 //! An array of buffers of preallocated messages, each one prefixed with the
Chris@16 279 //! msg_hdr_t structure. Each of this message is pointed by one pointer of
Chris@16 280 //! the index structure.
Chris@16 281 template<class VoidPointer>
Chris@16 282 class mq_hdr_t
Chris@16 283 : public ipcdetail::priority_functor<VoidPointer>
Chris@16 284 {
Chris@16 285 typedef VoidPointer void_pointer;
Chris@16 286 typedef msg_hdr_t<void_pointer> msg_header;
Chris@16 287 typedef typename boost::intrusive::
Chris@16 288 pointer_traits<void_pointer>::template
Chris@16 289 rebind_pointer<msg_header>::type msg_hdr_ptr_t;
Chris@16 290 typedef typename boost::intrusive::pointer_traits
Chris@16 291 <msg_hdr_ptr_t>::difference_type difference_type;
Chris@16 292 typedef typename boost::make_unsigned<difference_type>::type size_type;
Chris@16 293 typedef typename boost::intrusive::
Chris@16 294 pointer_traits<void_pointer>::template
Chris@16 295 rebind_pointer<msg_hdr_ptr_t>::type msg_hdr_ptr_ptr_t;
Chris@16 296 typedef ipcdetail::managed_open_or_create_impl<shared_memory_object, 0, true, false> open_create_impl_t;
Chris@16 297
Chris@16 298 public:
Chris@16 299 //!Constructor. This object must be constructed in the beginning of the
Chris@16 300 //!shared memory of the size returned by the function "get_mem_size".
Chris@16 301 //!This constructor initializes the needed resources and creates
Chris@16 302 //!the internal structures like the priority index. This can throw.
Chris@16 303 mq_hdr_t(size_type max_num_msg, size_type max_msg_size)
Chris@16 304 : m_max_num_msg(max_num_msg),
Chris@16 305 m_max_msg_size(max_msg_size),
Chris@16 306 m_cur_num_msg(0)
Chris@16 307 #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
Chris@16 308 ,m_cur_first_msg(0u)
Chris@16 309 #endif
Chris@16 310 { this->initialize_memory(); }
Chris@16 311
Chris@16 312 //!Returns true if the message queue is full
Chris@16 313 bool is_full() const
Chris@16 314 { return m_cur_num_msg == m_max_num_msg; }
Chris@16 315
Chris@16 316 //!Returns true if the message queue is empty
Chris@16 317 bool is_empty() const
Chris@16 318 { return !m_cur_num_msg; }
Chris@16 319
Chris@16 320 //!Frees the top priority message and saves it in the free message list
Chris@16 321 void free_top_msg()
Chris@16 322 { --m_cur_num_msg; }
Chris@16 323
Chris@16 324 #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
Chris@16 325
Chris@16 326 typedef msg_hdr_ptr_t *iterator;
Chris@16 327
Chris@16 328 size_type end_pos() const
Chris@16 329 {
Chris@16 330 const size_type space_until_bufend = m_max_num_msg - m_cur_first_msg;
Chris@16 331 return space_until_bufend > m_cur_num_msg
Chris@16 332 ? m_cur_first_msg + m_cur_num_msg : m_cur_num_msg - space_until_bufend;
Chris@16 333 }
Chris@16 334
Chris@16 335 //!Returns the inserted message with top priority
Chris@16 336 msg_header &top_msg()
Chris@16 337 {
Chris@16 338 size_type pos = this->end_pos();
Chris@16 339 return *mp_index[pos ? --pos : m_max_num_msg - 1];
Chris@16 340 }
Chris@16 341
Chris@16 342 //!Returns the inserted message with bottom priority
Chris@16 343 msg_header &bottom_msg()
Chris@16 344 { return *mp_index[m_cur_first_msg]; }
Chris@16 345
Chris@16 346 iterator inserted_ptr_begin() const
Chris@16 347 { return &mp_index[m_cur_first_msg]; }
Chris@16 348
Chris@16 349 iterator inserted_ptr_end() const
Chris@16 350 { return &mp_index[this->end_pos()]; }
Chris@16 351
Chris@16 352 iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor<VoidPointer> func)
Chris@16 353 {
Chris@16 354 iterator begin(this->inserted_ptr_begin()), end(this->inserted_ptr_end());
Chris@16 355 if(end < begin){
Chris@16 356 iterator idx_end = &mp_index[m_max_num_msg];
Chris@16 357 iterator ret = std::lower_bound(begin, idx_end, value, func);
Chris@16 358 if(idx_end == ret){
Chris@16 359 iterator idx_beg = &mp_index[0];
Chris@16 360 ret = std::lower_bound(idx_beg, end, value, func);
Chris@16 361 //sanity check, these cases should not call lower_bound (optimized out)
Chris@16 362 BOOST_ASSERT(ret != end);
Chris@16 363 BOOST_ASSERT(ret != begin);
Chris@16 364 return ret;
Chris@16 365 }
Chris@16 366 else{
Chris@16 367 return ret;
Chris@16 368 }
Chris@16 369 }
Chris@16 370 else{
Chris@16 371 return std::lower_bound(begin, end, value, func);
Chris@16 372 }
Chris@16 373 }
Chris@16 374
Chris@16 375 msg_header & insert_at(iterator where)
Chris@16 376 {
Chris@16 377 iterator it_inserted_ptr_end = this->inserted_ptr_end();
Chris@16 378 iterator it_inserted_ptr_beg = this->inserted_ptr_begin();
Chris@16 379 if(where == it_inserted_ptr_end){
Chris@16 380 ++m_cur_num_msg;
Chris@16 381 return **it_inserted_ptr_end;
Chris@16 382 }
Chris@16 383 else if(where == it_inserted_ptr_beg){
Chris@16 384 //unsigned integer guarantees underflow
Chris@16 385 m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg;
Chris@16 386 --m_cur_first_msg;
Chris@16 387 ++m_cur_num_msg;
Chris@16 388 return *mp_index[m_cur_first_msg];
Chris@16 389 }
Chris@16 390 else{
Chris@16 391 size_type pos = where - &mp_index[0];
Chris@16 392 size_type circ_pos = pos >= m_cur_first_msg ? pos - m_cur_first_msg : pos + (m_max_num_msg - m_cur_first_msg);
Chris@16 393 //Check if it's more efficient to move back or move front
Chris@16 394 if(circ_pos < m_cur_num_msg/2){
Chris@16 395 //The queue can't be full so m_cur_num_msg == 0 or m_cur_num_msg <= pos
Chris@16 396 //indicates two step insertion
Chris@16 397 if(!pos){
Chris@16 398 pos = m_max_num_msg;
Chris@16 399 where = &mp_index[m_max_num_msg-1];
Chris@16 400 }
Chris@16 401 else{
Chris@16 402 --where;
Chris@16 403 }
Chris@16 404 const bool unique_segment = m_cur_first_msg && m_cur_first_msg <= pos;
Chris@16 405 const size_type first_segment_beg = unique_segment ? m_cur_first_msg : 1u;
Chris@16 406 const size_type first_segment_end = pos;
Chris@16 407 const size_type second_segment_beg = unique_segment || !m_cur_first_msg ? m_max_num_msg : m_cur_first_msg;
Chris@16 408 const size_type second_segment_end = m_max_num_msg;
Chris@16 409 const msg_hdr_ptr_t backup = *(&mp_index[0] + (unique_segment ? first_segment_beg : second_segment_beg) - 1);
Chris@16 410
Chris@16 411 //First segment
Chris@16 412 if(!unique_segment){
Chris@16 413 std::copy( &mp_index[0] + second_segment_beg
Chris@16 414 , &mp_index[0] + second_segment_end
Chris@16 415 , &mp_index[0] + second_segment_beg - 1);
Chris@16 416 mp_index[m_max_num_msg-1] = mp_index[0];
Chris@16 417 }
Chris@16 418 std::copy( &mp_index[0] + first_segment_beg
Chris@16 419 , &mp_index[0] + first_segment_end
Chris@16 420 , &mp_index[0] + first_segment_beg - 1);
Chris@16 421 *where = backup;
Chris@16 422 m_cur_first_msg = m_cur_first_msg ? m_cur_first_msg : m_max_num_msg;
Chris@16 423 --m_cur_first_msg;
Chris@16 424 ++m_cur_num_msg;
Chris@16 425 return **where;
Chris@16 426 }
Chris@16 427 else{
Chris@16 428 //The queue can't be full so end_pos < m_cur_first_msg
Chris@16 429 //indicates two step insertion
Chris@16 430 const size_type pos_end = this->end_pos();
Chris@16 431 const bool unique_segment = pos < pos_end;
Chris@16 432 const size_type first_segment_beg = pos;
Chris@16 433 const size_type first_segment_end = unique_segment ? pos_end : m_max_num_msg-1;
Chris@16 434 const size_type second_segment_beg = 0u;
Chris@16 435 const size_type second_segment_end = unique_segment ? 0u : pos_end;
Chris@16 436 const msg_hdr_ptr_t backup = *it_inserted_ptr_end;
Chris@16 437
Chris@16 438 //First segment
Chris@16 439 if(!unique_segment){
Chris@16 440 std::copy_backward( &mp_index[0] + second_segment_beg
Chris@16 441 , &mp_index[0] + second_segment_end
Chris@16 442 , &mp_index[0] + second_segment_end + 1);
Chris@16 443 mp_index[0] = mp_index[m_max_num_msg-1];
Chris@16 444 }
Chris@16 445 std::copy_backward( &mp_index[0] + first_segment_beg
Chris@16 446 , &mp_index[0] + first_segment_end
Chris@16 447 , &mp_index[0] + first_segment_end + 1);
Chris@16 448 *where = backup;
Chris@16 449 ++m_cur_num_msg;
Chris@16 450 return **where;
Chris@16 451 }
Chris@16 452 }
Chris@16 453 }
Chris@16 454
Chris@16 455 #else
Chris@16 456
Chris@16 457 typedef msg_hdr_ptr_t *iterator;
Chris@16 458
Chris@16 459 //!Returns the inserted message with top priority
Chris@16 460 msg_header &top_msg()
Chris@16 461 { return *mp_index[m_cur_num_msg-1]; }
Chris@16 462
Chris@16 463 //!Returns the inserted message with bottom priority
Chris@16 464 msg_header &bottom_msg()
Chris@16 465 { return *mp_index[0]; }
Chris@16 466
Chris@16 467 iterator inserted_ptr_begin() const
Chris@16 468 { return &mp_index[0]; }
Chris@16 469
Chris@16 470 iterator inserted_ptr_end() const
Chris@16 471 { return &mp_index[m_cur_num_msg]; }
Chris@16 472
Chris@16 473 iterator lower_bound(const msg_hdr_ptr_t & value, priority_functor<VoidPointer> func)
Chris@16 474 { return std::lower_bound(this->inserted_ptr_begin(), this->inserted_ptr_end(), value, func); }
Chris@16 475
Chris@16 476 msg_header & insert_at(iterator pos)
Chris@16 477 {
Chris@16 478 const msg_hdr_ptr_t backup = *inserted_ptr_end();
Chris@16 479 std::copy_backward(pos, inserted_ptr_end(), inserted_ptr_end()+1);
Chris@16 480 *pos = backup;
Chris@16 481 ++m_cur_num_msg;
Chris@16 482 return **pos;
Chris@16 483 }
Chris@16 484
Chris@16 485 #endif
Chris@16 486
Chris@16 487 //!Inserts the first free message in the priority queue
Chris@16 488 msg_header & queue_free_msg(unsigned int priority)
Chris@16 489 {
Chris@16 490 //Get priority queue's range
Chris@16 491 iterator it (inserted_ptr_begin()), it_end(inserted_ptr_end());
Chris@16 492 //Optimize for non-priority usage
Chris@16 493 if(m_cur_num_msg && priority > this->bottom_msg().priority){
Chris@16 494 //Check for higher priority than all stored messages
Chris@16 495 if(priority > this->top_msg().priority){
Chris@16 496 it = it_end;
Chris@16 497 }
Chris@16 498 else{
Chris@16 499 //Since we don't now which free message we will pick
Chris@16 500 //build a dummy header for searches
Chris@16 501 msg_header dummy_hdr;
Chris@16 502 dummy_hdr.priority = priority;
Chris@16 503
Chris@16 504 //Get free msg
Chris@16 505 msg_hdr_ptr_t dummy_ptr(&dummy_hdr);
Chris@16 506
Chris@16 507 //Check where the free message should be placed
Chris@16 508 it = this->lower_bound(dummy_ptr, static_cast<priority_functor<VoidPointer>&>(*this));
Chris@16 509 }
Chris@16 510
Chris@16 511 }
Chris@16 512 //Insert the free message in the correct position
Chris@16 513 return this->insert_at(it);
Chris@16 514 }
Chris@16 515
Chris@16 516 //!Returns the number of bytes needed to construct a message queue with
Chris@16 517 //!"max_num_size" maximum number of messages and "max_msg_size" maximum
Chris@16 518 //!message size. Never throws.
Chris@16 519 static size_type get_mem_size
Chris@16 520 (size_type max_msg_size, size_type max_num_msg)
Chris@16 521 {
Chris@16 522 const size_type
Chris@16 523 msg_hdr_align = ::boost::alignment_of<msg_header>::value,
Chris@16 524 index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
Chris@16 525 r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
Chris@16 526 r_index_size = ipcdetail::get_rounded_size(max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
Chris@16 527 r_max_msg_size = ipcdetail::get_rounded_size(max_msg_size, msg_hdr_align) + sizeof(msg_header);
Chris@16 528 return r_hdr_size + r_index_size + (max_num_msg*r_max_msg_size) +
Chris@16 529 open_create_impl_t::ManagedOpenOrCreateUserOffset;
Chris@16 530 }
Chris@16 531
Chris@16 532 //!Initializes the memory structures to preallocate messages and constructs the
Chris@16 533 //!message index. Never throws.
Chris@16 534 void initialize_memory()
Chris@16 535 {
Chris@16 536 const size_type
Chris@16 537 msg_hdr_align = ::boost::alignment_of<msg_header>::value,
Chris@16 538 index_align = ::boost::alignment_of<msg_hdr_ptr_t>::value,
Chris@16 539 r_hdr_size = ipcdetail::ct_rounded_size<sizeof(mq_hdr_t), index_align>::value,
Chris@16 540 r_index_size = ipcdetail::get_rounded_size(m_max_num_msg*sizeof(msg_hdr_ptr_t), msg_hdr_align),
Chris@16 541 r_max_msg_size = ipcdetail::get_rounded_size(m_max_msg_size, msg_hdr_align) + sizeof(msg_header);
Chris@16 542
Chris@16 543 //Pointer to the index
Chris@16 544 msg_hdr_ptr_t *index = reinterpret_cast<msg_hdr_ptr_t*>
Chris@16 545 (reinterpret_cast<char*>(this)+r_hdr_size);
Chris@16 546
Chris@16 547 //Pointer to the first message header
Chris@16 548 msg_header *msg_hdr = reinterpret_cast<msg_header*>
Chris@16 549 (reinterpret_cast<char*>(this)+r_hdr_size+r_index_size);
Chris@16 550
Chris@16 551 //Initialize the pointer to the index
Chris@16 552 mp_index = index;
Chris@16 553
Chris@16 554 //Initialize the index so each slot points to a preallocated message
Chris@16 555 for(size_type i = 0; i < m_max_num_msg; ++i){
Chris@16 556 index[i] = msg_hdr;
Chris@16 557 msg_hdr = reinterpret_cast<msg_header*>
Chris@16 558 (reinterpret_cast<char*>(msg_hdr)+r_max_msg_size);
Chris@16 559 }
Chris@16 560 }
Chris@16 561
Chris@16 562 public:
Chris@16 563 //Pointer to the index
Chris@16 564 msg_hdr_ptr_ptr_t mp_index;
Chris@16 565 //Maximum number of messages of the queue
Chris@16 566 const size_type m_max_num_msg;
Chris@16 567 //Maximum size of messages of the queue
Chris@16 568 const size_type m_max_msg_size;
Chris@16 569 //Current number of messages
Chris@16 570 size_type m_cur_num_msg;
Chris@16 571 //Mutex to protect data structures
Chris@16 572 interprocess_mutex m_mutex;
Chris@16 573 //Condition block receivers when there are no messages
Chris@16 574 interprocess_condition m_cond_recv;
Chris@16 575 //Condition block senders when the queue is full
Chris@16 576 interprocess_condition m_cond_send;
Chris@16 577 #if defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
Chris@16 578 //Current start offset in the circular index
Chris@16 579 size_type m_cur_first_msg;
Chris@16 580 #endif
Chris@16 581 };
Chris@16 582
Chris@16 583
Chris@16 584 //!This is the atomic functor to be executed when creating or opening
Chris@16 585 //!shared memory. Never throws
Chris@16 586 template<class VoidPointer>
Chris@16 587 class msg_queue_initialization_func_t
Chris@16 588 {
Chris@16 589 public:
Chris@16 590 typedef typename boost::intrusive::
Chris@16 591 pointer_traits<VoidPointer>::template
Chris@16 592 rebind_pointer<char>::type char_ptr;
Chris@16 593 typedef typename boost::intrusive::pointer_traits<char_ptr>::difference_type difference_type;
Chris@16 594 typedef typename boost::make_unsigned<difference_type>::type size_type;
Chris@16 595
Chris@16 596 msg_queue_initialization_func_t(size_type maxmsg = 0,
Chris@16 597 size_type maxmsgsize = 0)
Chris@16 598 : m_maxmsg (maxmsg), m_maxmsgsize(maxmsgsize) {}
Chris@16 599
Chris@16 600 bool operator()(void *address, size_type, bool created)
Chris@16 601 {
Chris@16 602 char *mptr;
Chris@16 603
Chris@16 604 if(created){
Chris@16 605 mptr = reinterpret_cast<char*>(address);
Chris@16 606 //Construct the message queue header at the beginning
Chris@16 607 BOOST_TRY{
Chris@16 608 new (mptr) mq_hdr_t<VoidPointer>(m_maxmsg, m_maxmsgsize);
Chris@16 609 }
Chris@16 610 BOOST_CATCH(...){
Chris@16 611 return false;
Chris@16 612 }
Chris@16 613 BOOST_CATCH_END
Chris@16 614 }
Chris@16 615 return true;
Chris@16 616 }
Chris@16 617
Chris@16 618 std::size_t get_min_size() const
Chris@16 619 {
Chris@16 620 return mq_hdr_t<VoidPointer>::get_mem_size(m_maxmsgsize, m_maxmsg)
Chris@16 621 - message_queue_t<VoidPointer>::open_create_impl_t::ManagedOpenOrCreateUserOffset;
Chris@16 622 }
Chris@16 623
Chris@16 624 const size_type m_maxmsg;
Chris@16 625 const size_type m_maxmsgsize;
Chris@16 626 };
Chris@16 627
Chris@16 628 } //namespace ipcdetail {
Chris@16 629
Chris@16 630 template<class VoidPointer>
Chris@16 631 inline message_queue_t<VoidPointer>::~message_queue_t()
Chris@16 632 {}
Chris@16 633
Chris@16 634 template<class VoidPointer>
Chris@16 635 inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_mem_size
Chris@16 636 (size_type max_msg_size, size_type max_num_msg)
Chris@16 637 { return ipcdetail::mq_hdr_t<VoidPointer>::get_mem_size(max_msg_size, max_num_msg); }
Chris@16 638
Chris@16 639 template<class VoidPointer>
Chris@16 640 inline message_queue_t<VoidPointer>::message_queue_t(create_only_t,
Chris@16 641 const char *name,
Chris@16 642 size_type max_num_msg,
Chris@16 643 size_type max_msg_size,
Chris@16 644 const permissions &perm)
Chris@16 645 //Create shared memory and execute functor atomically
Chris@16 646 : m_shmem(create_only,
Chris@16 647 name,
Chris@16 648 get_mem_size(max_msg_size, max_num_msg),
Chris@16 649 read_write,
Chris@16 650 static_cast<void*>(0),
Chris@16 651 //Prepare initialization functor
Chris@16 652 ipcdetail::msg_queue_initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
Chris@16 653 perm)
Chris@16 654 {}
Chris@16 655
Chris@16 656 template<class VoidPointer>
Chris@16 657 inline message_queue_t<VoidPointer>::message_queue_t(open_or_create_t,
Chris@16 658 const char *name,
Chris@16 659 size_type max_num_msg,
Chris@16 660 size_type max_msg_size,
Chris@16 661 const permissions &perm)
Chris@16 662 //Create shared memory and execute functor atomically
Chris@16 663 : m_shmem(open_or_create,
Chris@16 664 name,
Chris@16 665 get_mem_size(max_msg_size, max_num_msg),
Chris@16 666 read_write,
Chris@16 667 static_cast<void*>(0),
Chris@16 668 //Prepare initialization functor
Chris@16 669 ipcdetail::msg_queue_initialization_func_t<VoidPointer> (max_num_msg, max_msg_size),
Chris@16 670 perm)
Chris@16 671 {}
Chris@16 672
Chris@16 673 template<class VoidPointer>
Chris@16 674 inline message_queue_t<VoidPointer>::message_queue_t(open_only_t, const char *name)
Chris@16 675 //Create shared memory and execute functor atomically
Chris@16 676 : m_shmem(open_only,
Chris@16 677 name,
Chris@16 678 read_write,
Chris@16 679 static_cast<void*>(0),
Chris@16 680 //Prepare initialization functor
Chris@16 681 ipcdetail::msg_queue_initialization_func_t<VoidPointer> ())
Chris@16 682 {}
Chris@16 683
Chris@16 684 template<class VoidPointer>
Chris@16 685 inline void message_queue_t<VoidPointer>::send
Chris@16 686 (const void *buffer, size_type buffer_size, unsigned int priority)
Chris@16 687 { this->do_send(blocking, buffer, buffer_size, priority, ptime()); }
Chris@16 688
Chris@16 689 template<class VoidPointer>
Chris@16 690 inline bool message_queue_t<VoidPointer>::try_send
Chris@16 691 (const void *buffer, size_type buffer_size, unsigned int priority)
Chris@16 692 { return this->do_send(non_blocking, buffer, buffer_size, priority, ptime()); }
Chris@16 693
Chris@16 694 template<class VoidPointer>
Chris@16 695 inline bool message_queue_t<VoidPointer>::timed_send
Chris@16 696 (const void *buffer, size_type buffer_size
Chris@16 697 ,unsigned int priority, const boost::posix_time::ptime &abs_time)
Chris@16 698 {
Chris@16 699 if(abs_time == boost::posix_time::pos_infin){
Chris@16 700 this->send(buffer, buffer_size, priority);
Chris@16 701 return true;
Chris@16 702 }
Chris@16 703 return this->do_send(timed, buffer, buffer_size, priority, abs_time);
Chris@16 704 }
Chris@16 705
Chris@16 706 template<class VoidPointer>
Chris@16 707 inline bool message_queue_t<VoidPointer>::do_send(block_t block,
Chris@16 708 const void *buffer, size_type buffer_size,
Chris@16 709 unsigned int priority, const boost::posix_time::ptime &abs_time)
Chris@16 710 {
Chris@16 711 ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
Chris@16 712 //Check if buffer is smaller than maximum allowed
Chris@16 713 if (buffer_size > p_hdr->m_max_msg_size) {
Chris@16 714 throw interprocess_exception(size_error);
Chris@16 715 }
Chris@16 716
Chris@16 717 bool was_empty = false;
Chris@16 718 //---------------------------------------------
Chris@16 719 scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
Chris@16 720 //---------------------------------------------
Chris@16 721 {
Chris@16 722 //If the queue is full execute blocking logic
Chris@16 723 if (p_hdr->is_full()) {
Chris@16 724 switch(block){
Chris@16 725 case non_blocking :
Chris@16 726 return false;
Chris@16 727 break;
Chris@16 728
Chris@16 729 case blocking :
Chris@16 730 do{
Chris@16 731 p_hdr->m_cond_send.wait(lock);
Chris@16 732 }
Chris@16 733 while (p_hdr->is_full());
Chris@16 734 break;
Chris@16 735
Chris@16 736 case timed :
Chris@16 737 do{
Chris@16 738 if(!p_hdr->m_cond_send.timed_wait(lock, abs_time)){
Chris@16 739 if(p_hdr->is_full())
Chris@16 740 return false;
Chris@16 741 break;
Chris@16 742 }
Chris@16 743 }
Chris@16 744 while (p_hdr->is_full());
Chris@16 745 break;
Chris@16 746 default:
Chris@16 747 break;
Chris@16 748 }
Chris@16 749 }
Chris@16 750
Chris@16 751 was_empty = p_hdr->is_empty();
Chris@16 752 //Insert the first free message in the priority queue
Chris@16 753 ipcdetail::msg_hdr_t<VoidPointer> &free_msg_hdr = p_hdr->queue_free_msg(priority);
Chris@16 754
Chris@16 755 //Sanity check, free msgs are always cleaned when received
Chris@16 756 BOOST_ASSERT(free_msg_hdr.priority == 0);
Chris@16 757 BOOST_ASSERT(free_msg_hdr.len == 0);
Chris@16 758
Chris@16 759 //Copy control data to the free message
Chris@16 760 free_msg_hdr.priority = priority;
Chris@16 761 free_msg_hdr.len = buffer_size;
Chris@16 762
Chris@16 763 //Copy user buffer to the message
Chris@16 764 std::memcpy(free_msg_hdr.data(), buffer, buffer_size);
Chris@16 765 } // Lock end
Chris@16 766
Chris@16 767 //Notify outside lock to avoid contention. This might produce some
Chris@16 768 //spurious wakeups, but it's usually far better than notifying inside.
Chris@16 769 //If this message changes the queue empty state, notify it to receivers
Chris@16 770 if (was_empty){
Chris@16 771 p_hdr->m_cond_recv.notify_one();
Chris@16 772 }
Chris@16 773
Chris@16 774 return true;
Chris@16 775 }
Chris@16 776
Chris@16 777 template<class VoidPointer>
Chris@16 778 inline void message_queue_t<VoidPointer>::receive(void *buffer, size_type buffer_size,
Chris@16 779 size_type &recvd_size, unsigned int &priority)
Chris@16 780 { this->do_receive(blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
Chris@16 781
Chris@16 782 template<class VoidPointer>
Chris@16 783 inline bool
Chris@16 784 message_queue_t<VoidPointer>::try_receive(void *buffer, size_type buffer_size,
Chris@16 785 size_type &recvd_size, unsigned int &priority)
Chris@16 786 { return this->do_receive(non_blocking, buffer, buffer_size, recvd_size, priority, ptime()); }
Chris@16 787
Chris@16 788 template<class VoidPointer>
Chris@16 789 inline bool
Chris@16 790 message_queue_t<VoidPointer>::timed_receive(void *buffer, size_type buffer_size,
Chris@16 791 size_type &recvd_size, unsigned int &priority,
Chris@16 792 const boost::posix_time::ptime &abs_time)
Chris@16 793 {
Chris@16 794 if(abs_time == boost::posix_time::pos_infin){
Chris@16 795 this->receive(buffer, buffer_size, recvd_size, priority);
Chris@16 796 return true;
Chris@16 797 }
Chris@16 798 return this->do_receive(timed, buffer, buffer_size, recvd_size, priority, abs_time);
Chris@16 799 }
Chris@16 800
Chris@16 801 template<class VoidPointer>
Chris@16 802 inline bool
Chris@16 803 message_queue_t<VoidPointer>::do_receive(block_t block,
Chris@16 804 void *buffer, size_type buffer_size,
Chris@16 805 size_type &recvd_size, unsigned int &priority,
Chris@16 806 const boost::posix_time::ptime &abs_time)
Chris@16 807 {
Chris@16 808 ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
Chris@16 809 //Check if buffer is big enough for any message
Chris@16 810 if (buffer_size < p_hdr->m_max_msg_size) {
Chris@16 811 throw interprocess_exception(size_error);
Chris@16 812 }
Chris@16 813
Chris@16 814 bool was_full = false;
Chris@16 815 //---------------------------------------------
Chris@16 816 scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
Chris@16 817 //---------------------------------------------
Chris@16 818 {
Chris@16 819 //If there are no messages execute blocking logic
Chris@16 820 if (p_hdr->is_empty()) {
Chris@16 821 switch(block){
Chris@16 822 case non_blocking :
Chris@16 823 return false;
Chris@16 824 break;
Chris@16 825
Chris@16 826 case blocking :
Chris@16 827 do{
Chris@16 828 p_hdr->m_cond_recv.wait(lock);
Chris@16 829 }
Chris@16 830 while (p_hdr->is_empty());
Chris@16 831 break;
Chris@16 832
Chris@16 833 case timed :
Chris@16 834 do{
Chris@16 835 if(!p_hdr->m_cond_recv.timed_wait(lock, abs_time)){
Chris@16 836 if(p_hdr->is_empty())
Chris@16 837 return false;
Chris@16 838 break;
Chris@16 839 }
Chris@16 840 }
Chris@16 841 while (p_hdr->is_empty());
Chris@16 842 break;
Chris@16 843
Chris@16 844 //Paranoia check
Chris@16 845 default:
Chris@16 846 break;
Chris@16 847 }
Chris@16 848 }
Chris@16 849
Chris@16 850 //There is at least one message ready to pick, get the top one
Chris@16 851 ipcdetail::msg_hdr_t<VoidPointer> &top_msg = p_hdr->top_msg();
Chris@16 852
Chris@16 853 //Get data from the message
Chris@16 854 recvd_size = top_msg.len;
Chris@16 855 priority = top_msg.priority;
Chris@16 856
Chris@16 857 //Some cleanup to ease debugging
Chris@16 858 top_msg.len = 0;
Chris@16 859 top_msg.priority = 0;
Chris@16 860
Chris@16 861 //Copy data to receiver's bufers
Chris@16 862 std::memcpy(buffer, top_msg.data(), recvd_size);
Chris@16 863
Chris@16 864 was_full = p_hdr->is_full();
Chris@16 865
Chris@16 866 //Free top message and put it in the free message list
Chris@16 867 p_hdr->free_top_msg();
Chris@16 868 } //Lock end
Chris@16 869
Chris@16 870 //Notify outside lock to avoid contention. This might produce some
Chris@16 871 //spurious wakeups, but it's usually far better than notifying inside.
Chris@16 872 //If this reception changes the queue full state, notify senders
Chris@16 873 if (was_full){
Chris@16 874 p_hdr->m_cond_send.notify_one();
Chris@16 875 }
Chris@16 876
Chris@16 877 return true;
Chris@16 878 }
Chris@16 879
Chris@16 880 template<class VoidPointer>
Chris@16 881 inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_max_msg() const
Chris@16 882 {
Chris@16 883 ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
Chris@16 884 return p_hdr ? p_hdr->m_max_num_msg : 0; }
Chris@16 885
Chris@16 886 template<class VoidPointer>
Chris@16 887 inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_max_msg_size() const
Chris@16 888 {
Chris@16 889 ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
Chris@16 890 return p_hdr ? p_hdr->m_max_msg_size : 0;
Chris@16 891 }
Chris@16 892
Chris@16 893 template<class VoidPointer>
Chris@16 894 inline typename message_queue_t<VoidPointer>::size_type message_queue_t<VoidPointer>::get_num_msg() const
Chris@16 895 {
Chris@16 896 ipcdetail::mq_hdr_t<VoidPointer> *p_hdr = static_cast<ipcdetail::mq_hdr_t<VoidPointer>*>(m_shmem.get_user_address());
Chris@16 897 if(p_hdr){
Chris@16 898 //---------------------------------------------
Chris@16 899 scoped_lock<interprocess_mutex> lock(p_hdr->m_mutex);
Chris@16 900 //---------------------------------------------
Chris@16 901 return p_hdr->m_cur_num_msg;
Chris@16 902 }
Chris@16 903
Chris@16 904 return 0;
Chris@16 905 }
Chris@16 906
Chris@16 907 template<class VoidPointer>
Chris@16 908 inline bool message_queue_t<VoidPointer>::remove(const char *name)
Chris@16 909 { return shared_memory_object::remove(name); }
Chris@16 910
Chris@16 911 /// @endcond
Chris@16 912
Chris@16 913 }} //namespace boost{ namespace interprocess{
Chris@16 914
Chris@16 915 #include <boost/interprocess/detail/config_end.hpp>
Chris@16 916
Chris@16 917 #endif //#ifndef BOOST_INTERPROCESS_MESSAGE_QUEUE_HPP