/indra/llcommon/llthreadsafequeue.h

https://bitbucket.org/lindenlab/viewer-beta/ · C++ Header · 205 lines · 109 code · 40 blank · 56 comment · 3 complexity · 03c2d7ecb18958aed3344098c391189c MD5 · raw file

  1. /**
  2. * @file llthreadsafequeue.h
  3. * @brief Base classes for thread, mutex and condition handling.
  4. *
  5. * $LicenseInfo:firstyear=2004&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #ifndef LL_LLTHREADSAFEQUEUE_H
  27. #define LL_LLTHREADSAFEQUEUE_H
  28. #include <string>
  29. #include <stdexcept>
  30. struct apr_pool_t; // From apr_pools.h
  31. class LLThreadSafeQueueImplementation; // See below.
  32. //
  33. // A general queue exception.
  34. //
  35. class LL_COMMON_API LLThreadSafeQueueError:
  36. public std::runtime_error
  37. {
  38. public:
  39. LLThreadSafeQueueError(std::string const & message):
  40. std::runtime_error(message)
  41. {
  42. ; // No op.
  43. }
  44. };
  45. //
  46. // An exception raised when blocking operations are interrupted.
  47. //
  48. class LL_COMMON_API LLThreadSafeQueueInterrupt:
  49. public LLThreadSafeQueueError
  50. {
  51. public:
  52. LLThreadSafeQueueInterrupt(void):
  53. LLThreadSafeQueueError("queue operation interrupted")
  54. {
  55. ; // No op.
  56. }
  57. };
  58. struct apr_queue_t; // From apr_queue.h
  59. //
  60. // Implementation details.
  61. //
  62. class LL_COMMON_API LLThreadSafeQueueImplementation
  63. {
  64. public:
  65. LLThreadSafeQueueImplementation(apr_pool_t * pool, unsigned int capacity);
  66. ~LLThreadSafeQueueImplementation();
  67. void pushFront(void * element);
  68. bool tryPushFront(void * element);
  69. void * popBack(void);
  70. bool tryPopBack(void *& element);
  71. size_t size();
  72. private:
  73. bool mOwnsPool;
  74. apr_pool_t * mPool;
  75. apr_queue_t * mQueue;
  76. };
  77. //
  78. // Implements a thread safe FIFO.
  79. //
  80. template<typename ElementT>
  81. class LLThreadSafeQueue
  82. {
  83. public:
  84. typedef ElementT value_type;
  85. // If the pool is set to NULL one will be allocated and managed by this
  86. // queue.
  87. LLThreadSafeQueue(apr_pool_t * pool = 0, unsigned int capacity = 1024);
  88. // Add an element to the front of queue (will block if the queue has
  89. // reached capacity).
  90. //
  91. // This call will raise an interrupt error if the queue is deleted while
  92. // the caller is blocked.
  93. void pushFront(ElementT const & element);
  94. // Try to add an element to the front ofqueue without blocking. Returns
  95. // true only if the element was actually added.
  96. bool tryPushFront(ElementT const & element);
  97. // Pop the element at the end of the queue (will block if the queue is
  98. // empty).
  99. //
  100. // This call will raise an interrupt error if the queue is deleted while
  101. // the caller is blocked.
  102. ElementT popBack(void);
  103. // Pop an element from the end of the queue if there is one available.
  104. // Returns true only if an element was popped.
  105. bool tryPopBack(ElementT & element);
  106. // Returns the size of the queue.
  107. size_t size();
  108. private:
  109. LLThreadSafeQueueImplementation mImplementation;
  110. };
  111. // LLThreadSafeQueue
  112. //-----------------------------------------------------------------------------
  113. template<typename ElementT>
  114. LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(apr_pool_t * pool, unsigned int capacity):
  115. mImplementation(pool, capacity)
  116. {
  117. ; // No op.
  118. }
  119. template<typename ElementT>
  120. void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
  121. {
  122. ElementT * elementCopy = new ElementT(element);
  123. try {
  124. mImplementation.pushFront(elementCopy);
  125. } catch (LLThreadSafeQueueInterrupt) {
  126. delete elementCopy;
  127. throw;
  128. }
  129. }
  130. template<typename ElementT>
  131. bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
  132. {
  133. ElementT * elementCopy = new ElementT(element);
  134. bool result = mImplementation.tryPushFront(elementCopy);
  135. if(!result) delete elementCopy;
  136. return result;
  137. }
  138. template<typename ElementT>
  139. ElementT LLThreadSafeQueue<ElementT>::popBack(void)
  140. {
  141. ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
  142. ElementT result(*element);
  143. delete element;
  144. return result;
  145. }
  146. template<typename ElementT>
  147. bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
  148. {
  149. void * storedElement;
  150. bool result = mImplementation.tryPopBack(storedElement);
  151. if(result) {
  152. ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
  153. element = *elementPtr;
  154. delete elementPtr;
  155. } else {
  156. ; // No op.
  157. }
  158. return result;
  159. }
  160. template<typename ElementT>
  161. size_t LLThreadSafeQueue<ElementT>::size(void)
  162. {
  163. return mImplementation.size();
  164. }
  165. #endif