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.

rtmempool.c 8.9KB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /*
  2. * RealTime Memory Pool, heavily based on work by Nedko Arnaudov
  3. * Copyright (C) 2006-2009 Nedko Arnaudov <nedko@arnaudov.name>
  4. * Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * For a full copy of the GNU General Public License see the GPL.txt file
  17. */
  18. #include "list.h"
  19. #include "rtmempool.h"
  20. #include "rtmempool-lv2.h"
  21. #include <assert.h>
  22. #include <pthread.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #define RTMEMPOOL_THREAD_SAFETY 0
  27. #if RTMEMPOOL_THREAD_SAFETY
  28. #define rtmempool_mutex_lock(m) pthread_mutex_lock(m)
  29. #define rtmempool_mutex_unlock(m) pthread_mutex_unlock(m)
  30. #else
  31. #define rtmempool_mutex_lock(...)
  32. #define rtmempool_mutex_unlock(...)
  33. #endif
  34. // ------------------------------------------------------------------------------------------------
  35. typedef struct list_head k_list_head;
  36. // ------------------------------------------------------------------------------------------------
  37. typedef struct _RtMemPool
  38. {
  39. char name[RTSAFE_MEMORY_POOL_NAME_MAX];
  40. size_t dataSize;
  41. size_t minPreallocated;
  42. size_t maxPreallocated;
  43. k_list_head used;
  44. unsigned int usedCount;
  45. k_list_head unused;
  46. unsigned int unusedCount;
  47. pthread_mutex_t mutex;
  48. } RtMemPool;
  49. // ------------------------------------------------------------------------------------------------
  50. // adjust unused list size
  51. static void rtsafe_memory_pool_sleepy(RtMemPool* poolPtr, bool* overMaxOrMallocFailed)
  52. {
  53. k_list_head* nodePtr;
  54. k_list_head unused;
  55. unsigned int unusedCount;
  56. INIT_LIST_HEAD(&unused);
  57. unusedCount = 0;
  58. while (poolPtr->unusedCount + unusedCount < poolPtr->minPreallocated)
  59. {
  60. if (poolPtr->usedCount + poolPtr->unusedCount + unusedCount >= poolPtr->maxPreallocated)
  61. {
  62. *overMaxOrMallocFailed = true;
  63. break;
  64. }
  65. nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize);
  66. if (nodePtr == NULL)
  67. {
  68. *overMaxOrMallocFailed = true;
  69. break;
  70. }
  71. list_add_tail(nodePtr, &unused);
  72. ++unusedCount;
  73. }
  74. rtmempool_mutex_lock(&poolPtr->mutex);
  75. poolPtr->unusedCount += unusedCount;
  76. while (unusedCount != 0)
  77. {
  78. assert(! list_empty(&unused));
  79. nodePtr = unused.next;
  80. list_del(nodePtr);
  81. list_add_tail(nodePtr, &poolPtr->unused);
  82. --unusedCount;
  83. }
  84. rtmempool_mutex_unlock(&poolPtr->mutex);
  85. }
  86. // ------------------------------------------------------------------------------------------------
  87. static bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr,
  88. const char* poolName,
  89. size_t dataSize,
  90. size_t minPreallocated,
  91. size_t maxPreallocated)
  92. {
  93. assert(minPreallocated <= maxPreallocated);
  94. assert(poolName == NULL || strlen(poolName) < RTSAFE_MEMORY_POOL_NAME_MAX);
  95. k_list_head* nodePtr;
  96. RtMemPool* poolPtr;
  97. poolPtr = malloc(sizeof(RtMemPool));
  98. if (poolPtr == NULL)
  99. {
  100. return false;
  101. }
  102. if (poolName != NULL)
  103. {
  104. strcpy(poolPtr->name, poolName);
  105. }
  106. else
  107. {
  108. sprintf(poolPtr->name, "%p", poolPtr);
  109. }
  110. poolPtr->dataSize = dataSize;
  111. poolPtr->minPreallocated = minPreallocated;
  112. poolPtr->maxPreallocated = maxPreallocated;
  113. INIT_LIST_HEAD(&poolPtr->used);
  114. poolPtr->usedCount = 0;
  115. INIT_LIST_HEAD(&poolPtr->unused);
  116. poolPtr->unusedCount = 0;
  117. pthread_mutexattr_t atts;
  118. pthread_mutexattr_init(&atts);
  119. #ifdef __ARM_ARCH_7A__
  120. pthread_mutexattr_setprotocol(&atts, PTHREAD_PRIO_INHERIT);
  121. #endif
  122. pthread_mutex_init(&poolPtr->mutex, &atts);
  123. pthread_mutexattr_destroy(&atts);
  124. while (poolPtr->unusedCount < poolPtr->minPreallocated)
  125. {
  126. nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize);
  127. if (nodePtr == NULL)
  128. {
  129. break;
  130. }
  131. list_add_tail(nodePtr, &poolPtr->unused);
  132. poolPtr->unusedCount++;
  133. }
  134. *handlePtr = (RtMemPool_Handle)poolPtr;
  135. return true;
  136. }
  137. // ------------------------------------------------------------------------------------------------
  138. static unsigned char rtsafe_memory_pool_create_old(const char* poolName,
  139. size_t dataSize,
  140. size_t minPreallocated,
  141. size_t maxPreallocated,
  142. RtMemPool_Handle* handlePtr)
  143. {
  144. return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated);
  145. }
  146. // ------------------------------------------------------------------------------------------------
  147. bool rtsafe_memory_pool_create(RtMemPool_Handle* handlePtr,
  148. const char* poolName,
  149. size_t dataSize,
  150. size_t minPreallocated,
  151. size_t maxPreallocated)
  152. {
  153. return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated);
  154. }
  155. // ------------------------------------------------------------------------------------------------
  156. void rtsafe_memory_pool_destroy(RtMemPool_Handle handle)
  157. {
  158. assert(handle);
  159. k_list_head* nodePtr;
  160. RtMemPool* poolPtr = (RtMemPool*)handle;
  161. // caller should deallocate all chunks prior releasing pool itself
  162. if (poolPtr->usedCount != 0)
  163. {
  164. fprintf(stderr, "warning: rtsafe_memory_pool_destroy called with nodes still active\n");
  165. }
  166. while (poolPtr->unusedCount != 0)
  167. {
  168. assert(! list_empty(&poolPtr->unused));
  169. nodePtr = poolPtr->unused.next;
  170. list_del(nodePtr);
  171. poolPtr->unusedCount--;
  172. free(nodePtr);
  173. }
  174. assert(list_empty(&poolPtr->unused));
  175. pthread_mutex_destroy(&poolPtr->mutex);
  176. free(poolPtr);
  177. }
  178. // ------------------------------------------------------------------------------------------------
  179. // find entry in unused list, fail if it is empty
  180. void* rtsafe_memory_pool_allocate_atomic(RtMemPool_Handle handle)
  181. {
  182. assert(handle);
  183. k_list_head* nodePtr;
  184. RtMemPool* poolPtr = (RtMemPool*)handle;
  185. rtmempool_mutex_lock(&poolPtr->mutex);
  186. if (list_empty(&poolPtr->unused))
  187. {
  188. rtmempool_mutex_unlock(&poolPtr->mutex);
  189. return NULL;
  190. }
  191. nodePtr = poolPtr->unused.next;
  192. list_del(nodePtr);
  193. poolPtr->unusedCount--;
  194. poolPtr->usedCount++;
  195. list_add_tail(nodePtr, &poolPtr->used);
  196. rtmempool_mutex_unlock(&poolPtr->mutex);
  197. return (nodePtr + 1);
  198. }
  199. // ------------------------------------------------------------------------------------------------
  200. void* rtsafe_memory_pool_allocate_sleepy(RtMemPool_Handle handle)
  201. {
  202. assert(handle);
  203. void* data;
  204. bool overMaxOrMallocFailed = false;
  205. RtMemPool* poolPtr = (RtMemPool*)handle;
  206. do {
  207. rtsafe_memory_pool_sleepy(poolPtr, &overMaxOrMallocFailed);
  208. data = rtsafe_memory_pool_allocate_atomic((RtMemPool_Handle)poolPtr);
  209. }
  210. while (data == NULL && ! overMaxOrMallocFailed);
  211. return data;
  212. }
  213. // ------------------------------------------------------------------------------------------------
  214. // move from used to unused list
  215. void rtsafe_memory_pool_deallocate(RtMemPool_Handle handle, void* memoryPtr)
  216. {
  217. assert(handle);
  218. RtMemPool* poolPtr = (RtMemPool*)handle;
  219. rtmempool_mutex_lock(&poolPtr->mutex);
  220. list_del((k_list_head*)memoryPtr - 1);
  221. list_add_tail((k_list_head*)memoryPtr - 1, &poolPtr->unused);
  222. poolPtr->usedCount--;
  223. poolPtr->unusedCount++;
  224. rtmempool_mutex_unlock(&poolPtr->mutex);
  225. }
  226. // ------------------------------------------------------------------------------------------------
  227. // LV2 stuff
  228. void lv2_rtmempool_init(LV2_RtMemPool_Pool* poolPtr)
  229. {
  230. poolPtr->create = rtsafe_memory_pool_create;
  231. poolPtr->destroy = rtsafe_memory_pool_destroy;
  232. poolPtr->allocate_atomic = rtsafe_memory_pool_allocate_atomic;
  233. poolPtr->allocate_sleepy = rtsafe_memory_pool_allocate_sleepy;
  234. poolPtr->deallocate = rtsafe_memory_pool_deallocate;
  235. }
  236. void lv2_rtmempool_init_deprecated(LV2_RtMemPool_Pool_Deprecated* poolPtr)
  237. {
  238. poolPtr->create = rtsafe_memory_pool_create_old;
  239. poolPtr->destroy = rtsafe_memory_pool_destroy;
  240. poolPtr->allocate_atomic = rtsafe_memory_pool_allocate_atomic;
  241. poolPtr->allocate_sleepy = rtsafe_memory_pool_allocate_sleepy;
  242. poolPtr->deallocate = rtsafe_memory_pool_deallocate;
  243. }