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.

222 lines
5.7KB

  1. #include <cstddef>
  2. #include <cstdlib>
  3. #include <cassert>
  4. #include <utility>
  5. #include <cstdio>
  6. #include "tlsf/tlsf.h"
  7. #include "Allocator.h"
  8. //Used for dummy allocations
  9. DummyAllocator DummyAlloc;
  10. //recursive type class to avoid void *v = *(void**)v style casting
  11. struct next_t
  12. {
  13. next_t *next;
  14. size_t pool_size;
  15. };
  16. void *data(next_t *n)
  17. {
  18. return n+sizeof(next_t);
  19. }
  20. struct AllocatorImpl
  21. {
  22. void *tlsf = 0;
  23. //singly linked list of memory pools
  24. //XXX this may violate alignment on some platforms if malloc doesn't return
  25. //nice values
  26. next_t *pools = 0;
  27. unsigned long long totalAlloced = 0;
  28. };
  29. Allocator::Allocator(void) : transaction_active()
  30. {
  31. impl = new AllocatorImpl;
  32. size_t default_size = 10*1024*1024;
  33. impl->pools = (next_t*)malloc(default_size);
  34. impl->pools->next = 0x0;
  35. impl->pools->pool_size = default_size;
  36. size_t off = tlsf_size() + tlsf_pool_overhead() + sizeof(next_t);
  37. //printf("Generated Memory Pool with '%p'\n", impl->pools);
  38. impl->tlsf = tlsf_create_with_pool(((char*)impl->pools)+off, default_size-2*off);
  39. //printf("Allocator(%p)\n", impl);
  40. }
  41. Allocator::~Allocator(void)
  42. {
  43. next_t *n = impl->pools;
  44. while(n) {
  45. next_t *nn = n->next;
  46. free(n);
  47. n = nn;
  48. }
  49. delete impl;
  50. }
  51. void *AllocatorClass::alloc_mem(size_t mem_size)
  52. {
  53. impl->totalAlloced += mem_size;
  54. void *mem = tlsf_malloc(impl->tlsf, mem_size);
  55. //printf("Allocator.malloc(%p, %d) = %p\n", impl, mem_size, mem);
  56. //void *mem = malloc(mem_size);
  57. //printf("Allocator result = %p\n", mem);
  58. return mem;
  59. }
  60. void AllocatorClass::dealloc_mem(void *memory)
  61. {
  62. //printf("dealloc_mem(%d)\n", tlsf_block_size(memory));
  63. tlsf_free(impl->tlsf, memory);
  64. //free(memory);
  65. }
  66. bool AllocatorClass::lowMemory(unsigned n, size_t chunk_size) const
  67. {
  68. //This should stay on the stack
  69. void *buf[n];
  70. for(unsigned i=0; i<n; ++i)
  71. buf[i] = tlsf_malloc(impl->tlsf, chunk_size);
  72. bool outOfMem = false;
  73. for(unsigned i=0; i<n; ++i)
  74. outOfMem |= (buf[i] == nullptr);
  75. for(unsigned i=0; i<n; ++i)
  76. if(buf[i])
  77. tlsf_free(impl->tlsf, buf[i]);
  78. return outOfMem;
  79. }
  80. void AllocatorClass::addMemory(void *v, size_t mem_size)
  81. {
  82. next_t *n = impl->pools;
  83. while(n->next) n = n->next;
  84. n->next = (next_t*)v;
  85. n->next->next = 0x0;
  86. n->next->pool_size = mem_size;
  87. //printf("Inserting '%p'\n", v);
  88. off_t off = sizeof(next_t) + tlsf_pool_overhead();
  89. void *result =
  90. tlsf_add_pool(impl->tlsf, ((char*)n->next)+off,
  91. //0x0eadbeef);
  92. mem_size-off-sizeof(size_t));
  93. if(!result)
  94. printf("FAILED TO INSERT MEMORY POOL\n");
  95. };//{(void)mem_size;};
  96. #ifndef INCLUDED_tlsfbits
  97. //From tlsf internals
  98. typedef struct block_header_t
  99. {
  100. /* Points to the previous physical block. */
  101. struct block_header_t* prev_phys_block;
  102. /* The size of this block, excluding the block header. */
  103. size_t size;
  104. /* Next and previous free blocks. */
  105. struct block_header_t* next_free;
  106. struct block_header_t* prev_free;
  107. } block_header_t;
  108. static const size_t block_header_free_bit = 1 << 0;
  109. #endif
  110. void Allocator::beginTransaction() {
  111. // TODO: log about unsupported nested transaction when a RT compliant
  112. // logging is available and transaction_active == true
  113. transaction_active = true;
  114. transaction_alloc_index = 0;
  115. }
  116. void Allocator::endTransaction() {
  117. // TODO: log about invalid end of transaction when a RT copmliant logging
  118. // is available and transaction_active == false
  119. transaction_active = false;
  120. }
  121. bool Allocator::memFree(void *pool) const
  122. {
  123. size_t bh_shift = sizeof(next_t)+sizeof(size_t);
  124. //Assume that memory is free to start with
  125. bool isFree = true;
  126. //Get the block header from the pool
  127. block_header_t &bh = *(block_header_t*)((char*)pool+bh_shift);
  128. //The first block must be free
  129. if((bh.size&block_header_free_bit) == 0)
  130. isFree = false;
  131. block_header_t &bhn = *(block_header_t*)
  132. (((char*)&bh)+((bh.size&~0x3)+bh_shift-2*sizeof(size_t)));
  133. //The next block must be 'non-free' and zero length
  134. if((bhn.size&block_header_free_bit) != 0)
  135. isFree = false;
  136. if((bhn.size&~0x3) != 0)
  137. isFree = false;
  138. return isFree;
  139. }
  140. int Allocator::memPools() const
  141. {
  142. int i = 1;
  143. next_t *n = impl->pools;
  144. while(n->next) {
  145. i++;
  146. n = n->next;
  147. }
  148. return i;
  149. }
  150. int Allocator::freePools() const
  151. {
  152. int i = 0;
  153. next_t *n = impl->pools->next;
  154. while(n) {
  155. if(memFree(n))
  156. i++;
  157. n = n->next;
  158. }
  159. return i;
  160. }
  161. unsigned long long Allocator::totalAlloced() const
  162. {
  163. return impl->totalAlloced;
  164. }
  165. void Allocator::rollbackTransaction() {
  166. // if a transaction is active
  167. if (transaction_active) {
  168. // deallocate all allocated memory within this transaction
  169. for (size_t temp_idx = 0;
  170. temp_idx < transaction_alloc_index; ++temp_idx) {
  171. dealloc_mem(transaction_alloc_content[temp_idx]);
  172. }
  173. }
  174. transaction_active = false;
  175. }
  176. /*
  177. * Notes on tlsf internals
  178. * - TLSF consists of blocks linked by block headers and these form a doubly
  179. * linked list of free segments
  180. * - Original memory is [control_t pool]
  181. * base sentinal
  182. * Pools are [block_t block_t blocks ...]
  183. * Blocks are [memory block_t](??)
  184. * - These are stored in the control_t structure in an order dependent on the
  185. * size that they are
  186. * it's a bit unclear how collisions are handled here, but the basic premise
  187. * makes sense
  188. * - Additional structure is added before the start of each pool to define the
  189. * pool size and the next pool in the list as this information is not
  190. * accessible in O(good) time
  191. */