ManagedBuffer.hpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. ///
  2. /// \file Framework/ManagedBuffer.hpp
  3. ///
  4. /// A ManagedBuffer is checked-out and automatically returned to a BufferManager.
  5. ///
  6. /// \copyright
  7. /// Copyright (c) 2013-2017 Josh Blum
  8. /// 2019 Nicholas Corgan
  9. /// SPDX-License-Identifier: BSL-1.0
  10. ///
  11. #pragma once
  12. #include <Pothos/Config.hpp>
  13. #include <Pothos/Framework/SharedBuffer.hpp>
  14. #include <memory> //shared_ptr
  15. #include <atomic>
  16. #include <cassert>
  17. namespace Pothos {
  18. //! Forward declares
  19. class BufferManager;
  20. class BufferChunk;
  21. class BufferAccumulator;
  22. /*!
  23. * A ManagedBuffer is a buffer that interacts with a BufferManager.
  24. * The ManagedBuffer maintains a reference count, and when no more
  25. * copies are held by the user, the ManagedBuffer will be returned
  26. * to the BufferManager; unless the BufferManager has been deleted.
  27. */
  28. class POTHOS_API ManagedBuffer
  29. {
  30. public:
  31. /*!
  32. * Create a null buffer.
  33. * All fields are initialized to zero.
  34. */
  35. ManagedBuffer(void);
  36. /*!
  37. * Create from a shared buffer with no manager.
  38. */
  39. ManagedBuffer(const SharedBuffer &buff);
  40. /*!
  41. * Is this managed buffer valid?
  42. * \return true if it holds an allocation.
  43. */
  44. explicit operator bool(void) const;
  45. /*!
  46. * Reset any reference held by the managed buffer.
  47. * This managed buffer will become a null buffer.
  48. */
  49. void reset(void);
  50. /*!
  51. * Reset the managed buffer for its next usage.
  52. * \param manager shared pointer to the buffer manager
  53. * \param buff the shared buffer with memory and length
  54. * \param slabIndex an identifying index used with slabs
  55. */
  56. void reset(std::shared_ptr<BufferManager> manager, const SharedBuffer &buff, const size_t slabIndex = 0);
  57. /*!
  58. * Get the internal buffer as set by the manager
  59. * and which cannot be changed by the caller.
  60. * \return a const reference to the buffer
  61. */
  62. const SharedBuffer &getBuffer(void) const;
  63. /*!
  64. * Get the slab index associated with this buffer.
  65. * The slab index related to implementation specifics.
  66. * Typically, this index is only used when the underlying
  67. * buffer is sourced from a continuous slab of memory.
  68. */
  69. size_t getSlabIndex(void) const;
  70. //! ManagedBuffer destructor
  71. ~ManagedBuffer(void);
  72. //! ManagedBuffer copy constructor
  73. ManagedBuffer(const ManagedBuffer &obj);
  74. //! ManagedBuffer move constructor
  75. ManagedBuffer(ManagedBuffer &&obj) noexcept;
  76. //! ManagedBuffer copy assignment
  77. ManagedBuffer &operator=(const ManagedBuffer &obj);
  78. //! ManagedBuffer move assignment
  79. ManagedBuffer &operator=(ManagedBuffer &&obj);
  80. //! Get the associated buffer manager
  81. std::shared_ptr<BufferManager> getBufferManager(void) const;
  82. //! sortable operator for ManagedBuffer
  83. bool operator<(const ManagedBuffer &) const;
  84. /*!
  85. * Is the reference to the managed buffer unique?
  86. * \return true if this is the only copy of the managed buffer
  87. */
  88. bool unique(void) const;
  89. /*!
  90. * The number of copies of the managed buffer.
  91. */
  92. size_t useCount(void) const;
  93. /*!
  94. * Set the next contiguous buffer in the chain.
  95. */
  96. void setNextBuffer(const ManagedBuffer &next);
  97. /*!
  98. * Get the next contiguous buffer in the chain.
  99. * Or return a null managed buffer if there is none.
  100. */
  101. ManagedBuffer getNextBuffer(void) const;
  102. private:
  103. friend BufferChunk;
  104. friend BufferAccumulator;
  105. struct Impl; Impl *_impl;
  106. ManagedBuffer(Impl *impl);
  107. POTHOS_API friend bool operator==(const ManagedBuffer &lhs, const ManagedBuffer &rhs);
  108. POTHOS_API friend bool operator!=(const ManagedBuffer &lhs, const ManagedBuffer &rhs);
  109. };
  110. /*!
  111. * Equality operator for ManagedBuffer.
  112. * True when the containers are identical.
  113. */
  114. inline bool operator==(const ManagedBuffer &lhs, const ManagedBuffer &rhs);
  115. /*!
  116. * Inquality operator for ManagedBuffer.
  117. * True when the containers are not identical.
  118. */
  119. inline bool operator!=(const ManagedBuffer &lhs, const ManagedBuffer &rhs);
  120. } //namespace Pothos
  121. struct Pothos::ManagedBuffer::Impl
  122. {
  123. Impl(void);
  124. std::atomic<int> counter;
  125. std::weak_ptr<BufferManager> weakManager;
  126. SharedBuffer buffer;
  127. size_t slabIndex;
  128. Pothos::ManagedBuffer::Impl *nextBuffer;
  129. void incr(void)
  130. {
  131. counter.fetch_add(1, std::memory_order_relaxed);
  132. }
  133. void decr(void)
  134. {
  135. //decrement the counter, and handle the last ref case
  136. if (counter.fetch_sub(1, std::memory_order_release) == 1)
  137. {
  138. std::atomic_thread_fence(std::memory_order_acquire);
  139. this->cleanup();
  140. }
  141. }
  142. void cleanup(void);
  143. };
  144. inline Pothos::ManagedBuffer::ManagedBuffer(void):
  145. _impl(nullptr)
  146. {
  147. return;
  148. }
  149. inline Pothos::ManagedBuffer::operator bool(void) const
  150. {
  151. return _impl != nullptr;
  152. }
  153. inline void Pothos::ManagedBuffer::reset(void)
  154. {
  155. if (_impl != nullptr) _impl->decr();
  156. _impl = nullptr;
  157. }
  158. inline const Pothos::SharedBuffer &Pothos::ManagedBuffer::getBuffer(void) const
  159. {
  160. if (_impl == nullptr) return SharedBuffer::null();
  161. return _impl->buffer;
  162. }
  163. inline size_t Pothos::ManagedBuffer::getSlabIndex(void) const
  164. {
  165. assert(*this);
  166. return _impl->slabIndex;
  167. }
  168. inline Pothos::ManagedBuffer::~ManagedBuffer(void)
  169. {
  170. if (_impl != nullptr) _impl->decr();
  171. }
  172. inline Pothos::ManagedBuffer::ManagedBuffer(const ManagedBuffer &obj):
  173. _impl(obj._impl)
  174. {
  175. if (_impl != nullptr) _impl->incr();
  176. }
  177. inline Pothos::ManagedBuffer::ManagedBuffer(ManagedBuffer &&obj) noexcept:
  178. _impl(obj._impl)
  179. {
  180. obj._impl = nullptr;
  181. }
  182. inline Pothos::ManagedBuffer &Pothos::ManagedBuffer::operator=(const ManagedBuffer &obj)
  183. {
  184. if (_impl != nullptr) _impl->decr();
  185. this->_impl = obj._impl;
  186. if (_impl != nullptr) _impl->incr();
  187. return *this;
  188. }
  189. inline Pothos::ManagedBuffer &Pothos::ManagedBuffer::operator=(ManagedBuffer &&obj)
  190. {
  191. if (_impl != nullptr) _impl->decr();
  192. this->_impl = obj._impl;
  193. obj._impl = nullptr;
  194. return *this;
  195. }
  196. inline std::shared_ptr<Pothos::BufferManager> Pothos::ManagedBuffer::getBufferManager(void) const
  197. {
  198. assert(*this);
  199. return _impl->weakManager.lock();
  200. }
  201. inline bool Pothos::ManagedBuffer::operator<(const ManagedBuffer &rhs) const
  202. {
  203. return _impl < rhs._impl;
  204. }
  205. inline bool Pothos::ManagedBuffer::unique(void) const
  206. {
  207. if (_impl == nullptr) return false;
  208. return _impl->counter.load(std::memory_order_relaxed) == 1;
  209. }
  210. inline size_t Pothos::ManagedBuffer::useCount(void) const
  211. {
  212. if (_impl == nullptr) return 0;
  213. return _impl->counter.load(std::memory_order_relaxed);
  214. }
  215. inline void Pothos::ManagedBuffer::setNextBuffer(const ManagedBuffer &next)
  216. {
  217. assert(*this);
  218. _impl->nextBuffer = next._impl;
  219. }
  220. inline Pothos::ManagedBuffer Pothos::ManagedBuffer::getNextBuffer(void) const
  221. {
  222. assert(*this);
  223. return Pothos::ManagedBuffer(_impl->nextBuffer);
  224. }
  225. inline Pothos::ManagedBuffer::ManagedBuffer(Impl *impl):
  226. _impl(impl)
  227. {
  228. if (_impl != nullptr) _impl->incr();
  229. }
  230. inline bool Pothos::operator==(const ManagedBuffer &lhs, const ManagedBuffer &rhs)
  231. {
  232. return lhs._impl == rhs._impl;
  233. }
  234. inline bool Pothos::operator!=(const ManagedBuffer &lhs, const ManagedBuffer &rhs)
  235. {
  236. return !(lhs == rhs);
  237. }