Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Allocator.h 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #pragma once
  2. #include <cstdlib>
  3. #include <utility>
  4. #include <new>
  5. //! Allocator Base class
  6. //! subclasses must specify allocation and deallocation
  7. class Allocator
  8. {
  9. public:
  10. Allocator(void);
  11. Allocator(const Allocator&) = delete;
  12. virtual ~Allocator(void);
  13. virtual void *alloc_mem(size_t mem_size) = 0;
  14. virtual void dealloc_mem(void *memory) = 0;
  15. /**
  16. * High level allocator method, which return a pointer to a class
  17. * or struct
  18. * allocated with the specialized subclass strategy
  19. * @param ts argument(s) for the constructor of the type T
  20. * @return a non null pointer to a new object of type T
  21. * @throw std::bad_alloc is no memory could be allocated
  22. */
  23. template <typename T, typename... Ts>
  24. T *alloc(Ts&&... ts)
  25. {
  26. void *data = alloc_mem(sizeof(T));
  27. if(!data) {
  28. rollbackTransaction();
  29. throw std::bad_alloc();
  30. }
  31. append_alloc_to_memory_transaction(data);
  32. return new (data) T(std::forward<Ts>(ts)...);
  33. }
  34. /**
  35. * High level allocator method, which return a pointer to an array of
  36. * class or struct
  37. * allocated with the specialized subclass strategy
  38. * @param len the array length
  39. * @param ts argument(s) for the constructor of the type T
  40. * @return a non null pointer to an array of new object(s) of type T
  41. * @throw std::bad_alloc is no memory could be allocated
  42. */
  43. template <typename T, typename... Ts>
  44. T *valloc(size_t len, Ts&&... ts)
  45. {
  46. T *data = (T*)alloc_mem(len*sizeof(T));
  47. if(!data) {
  48. rollbackTransaction();
  49. throw std::bad_alloc();
  50. }
  51. append_alloc_to_memory_transaction(data);
  52. for(unsigned i=0; i<len; ++i)
  53. new ((void*)&data[i]) T(std::forward<Ts>(ts)...);
  54. return data;
  55. }
  56. template <typename T>
  57. void dealloc(T*&t)
  58. {
  59. if(t) {
  60. t->~T();
  61. dealloc_mem((void*)t);
  62. t = nullptr;
  63. }
  64. }
  65. //Destructor Free Version
  66. template <typename T>
  67. void devalloc(T*&t)
  68. {
  69. if(t) {
  70. dealloc_mem(t);
  71. t = nullptr;
  72. }
  73. }
  74. template <typename T>
  75. void devalloc(size_t elms, T*&t)
  76. {
  77. if(t) {
  78. for(size_t i=0; i<elms; ++i)
  79. (t+i)->~T();
  80. dealloc_mem(t);
  81. t = nullptr;
  82. }
  83. }
  84. void beginTransaction();
  85. void endTransaction();
  86. virtual void addMemory(void *, size_t mem_size) = 0;
  87. //Return true if the current pool cannot allocate n chunks of chunk_size
  88. virtual bool lowMemory(unsigned n, size_t chunk_size) const = 0;
  89. bool memFree(void *pool) const;
  90. //returns number of pools
  91. int memPools() const;
  92. int freePools() const;
  93. unsigned long long totalAlloced() const;
  94. struct AllocatorImpl *impl;
  95. private:
  96. const static size_t max_transaction_length = 256;
  97. void* transaction_alloc_content[max_transaction_length];
  98. size_t transaction_alloc_index;
  99. bool transaction_active;
  100. void rollbackTransaction();
  101. /**
  102. * Append memory block to the list of memory blocks allocated during this
  103. * transaction
  104. * @param new_memory pointer to the memory pointer to freshly allocated
  105. */
  106. void append_alloc_to_memory_transaction(void *new_memory) {
  107. if (transaction_active) {
  108. if (transaction_alloc_index < max_transaction_length) {
  109. transaction_alloc_content[transaction_alloc_index++] = new_memory;
  110. }
  111. // TODO add log about transaction too long and memory transaction
  112. // safety net being disabled
  113. }
  114. }
  115. };
  116. //! the allocator for normal use
  117. class AllocatorClass : public Allocator
  118. {
  119. public:
  120. void *alloc_mem(size_t mem_size);
  121. void dealloc_mem(void *memory);
  122. void addMemory(void *, size_t mem_size);
  123. bool lowMemory(unsigned n, size_t chunk_size) const;
  124. using Allocator::Allocator;
  125. };
  126. typedef AllocatorClass Alloc;
  127. //! the dummy allocator, which does not allow any allocation
  128. class DummyAllocator : public Allocator
  129. {
  130. void not_allowed() const {
  131. throw "(de)allocation forbidden"; // TODO: std exception
  132. }
  133. public:
  134. void *alloc_mem(size_t ) { return not_allowed(), nullptr; }
  135. void dealloc_mem(void* ) { not_allowed(); } // TODO: more functions?
  136. void addMemory(void *, size_t ) { not_allowed(); }
  137. bool lowMemory(unsigned , size_t ) const { return not_allowed(), true; }
  138. using Allocator::Allocator;
  139. };
  140. extern DummyAllocator DummyAlloc;
  141. /**
  142. * General notes on Memory Allocation Within ZynAddSubFX
  143. * -----------------------------------------------------
  144. *
  145. * - Parameter Objects Are never allocated within the realtime thread
  146. * - Effects, notes and note subcomponents must be allocated with an allocator
  147. * - 5M Chunks are used to give the allocator the memory it wants
  148. * - If there are 3 chunks that are unused then 1 will be deallocated
  149. * - The system will request more allocated space if 5x 1MB chunks cannot be
  150. * allocated at any given time (this is likely huge overkill, but if this is
  151. * satisfied, then a lot of note spamming would be needed to run out of
  152. * space)
  153. *
  154. * - Things will get a bit weird around the effects due to how pointer swaps
  155. * occur
  156. * * When a new Part instance is provided it may or may not come with some
  157. * instrument effects
  158. * * Merging blocks is an option, but one that is not going to likely be
  159. * implmented too soon, thus all effects need to be reallocated when the
  160. * pointer swap occurs
  161. * * The old effect is extracted from the manager
  162. * * A new one is constructed with a deep copy
  163. * * The old one is returned to middleware for deallocation
  164. */