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 10KB

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
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  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 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 "rtmempool.h"
  19. #include "list.h"
  20. #include <assert.h>
  21. #include <pthread.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. // ------------------------------------------------------------------------------------------------
  26. typedef struct list_head k_list_head;
  27. // ------------------------------------------------------------------------------------------------
  28. typedef struct _RtMemPool
  29. {
  30. char name[RTSAFE_MEMORY_POOL_NAME_MAX];
  31. size_t dataSize;
  32. size_t minPreallocated;
  33. size_t maxPreallocated;
  34. k_list_head used;
  35. unsigned int usedCount;
  36. k_list_head unused;
  37. unsigned int unusedCount;
  38. bool enforceThreadSafety;
  39. // next members are initialized/used only if enforceThreadSafety is true
  40. pthread_mutex_t mutex;
  41. unsigned int unusedCount2;
  42. k_list_head pending;
  43. size_t usedSize;
  44. } RtMemPool;
  45. // ------------------------------------------------------------------------------------------------
  46. // additional function prototypes
  47. void rtsafe_memory_pool_sleepy(RtMemPool* poolPtr);
  48. bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr, const char* poolName,
  49. size_t dataSize, size_t minPreallocated, size_t maxPreallocated,
  50. int enforceThreadSafety);
  51. // ------------------------------------------------------------------------------------------------
  52. // adjust unused list size
  53. void rtsafe_memory_pool_sleepy(RtMemPool* poolPtr)
  54. {
  55. k_list_head* nodePtr;
  56. unsigned int count;
  57. if (poolPtr->enforceThreadSafety)
  58. {
  59. pthread_mutex_lock(&poolPtr->mutex);
  60. count = poolPtr->unusedCount2;
  61. assert(poolPtr->minPreallocated < poolPtr->maxPreallocated);
  62. while (count < poolPtr->minPreallocated)
  63. {
  64. nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize);
  65. if (nodePtr == NULL)
  66. {
  67. break;
  68. }
  69. list_add_tail(nodePtr, &poolPtr->pending);
  70. count++;
  71. poolPtr->usedSize += poolPtr->dataSize;
  72. }
  73. while (count > poolPtr->maxPreallocated && ! list_empty(&poolPtr->pending))
  74. {
  75. nodePtr = poolPtr->pending.next;
  76. list_del(nodePtr);
  77. free(nodePtr);
  78. count--;
  79. poolPtr->usedSize -= poolPtr->dataSize;
  80. }
  81. pthread_mutex_unlock(&poolPtr->mutex);
  82. }
  83. else
  84. {
  85. while (poolPtr->unusedCount < poolPtr->minPreallocated)
  86. {
  87. nodePtr = malloc(sizeof(k_list_head) + poolPtr->dataSize);
  88. if (nodePtr == NULL)
  89. {
  90. return;
  91. }
  92. list_add_tail(nodePtr, &poolPtr->unused);
  93. poolPtr->unusedCount++;
  94. poolPtr->usedSize += poolPtr->dataSize;
  95. }
  96. while (poolPtr->unusedCount > poolPtr->maxPreallocated)
  97. {
  98. assert(! list_empty(&poolPtr->unused));
  99. nodePtr = poolPtr->unused.next;
  100. list_del(nodePtr);
  101. poolPtr->unusedCount--;
  102. free(nodePtr);
  103. poolPtr->usedSize -= poolPtr->dataSize;
  104. }
  105. }
  106. }
  107. // ------------------------------------------------------------------------------------------------
  108. bool rtsafe_memory_pool_create2(RtMemPool_Handle* handlePtr,
  109. const char* poolName,
  110. size_t dataSize,
  111. size_t minPreallocated,
  112. size_t maxPreallocated,
  113. int enforceThreadSafety)
  114. {
  115. assert(minPreallocated <= maxPreallocated);
  116. assert(poolName == NULL || strlen(poolName) < RTSAFE_MEMORY_POOL_NAME_MAX);
  117. RtMemPool* poolPtr;
  118. poolPtr = malloc(sizeof(RtMemPool));
  119. if (poolPtr == NULL)
  120. {
  121. return false;
  122. }
  123. if (poolName != NULL)
  124. {
  125. strcpy(poolPtr->name, poolName);
  126. }
  127. else
  128. {
  129. sprintf(poolPtr->name, "%p", poolPtr);
  130. }
  131. poolPtr->dataSize = dataSize;
  132. poolPtr->minPreallocated = minPreallocated;
  133. poolPtr->maxPreallocated = maxPreallocated;
  134. INIT_LIST_HEAD(&poolPtr->used);
  135. poolPtr->usedCount = 0;
  136. INIT_LIST_HEAD(&poolPtr->unused);
  137. poolPtr->unusedCount = 0;
  138. poolPtr->enforceThreadSafety = (enforceThreadSafety != 0);
  139. if (poolPtr->enforceThreadSafety)
  140. {
  141. if (pthread_mutex_init(&poolPtr->mutex, NULL) != 0)
  142. {
  143. free(poolPtr);
  144. return false;
  145. }
  146. INIT_LIST_HEAD(&poolPtr->pending);
  147. }
  148. poolPtr->unusedCount2 = 0;
  149. poolPtr->usedSize = 0;
  150. rtsafe_memory_pool_sleepy(poolPtr);
  151. *handlePtr = (RtMemPool_Handle)poolPtr;
  152. return true;
  153. }
  154. // ------------------------------------------------------------------------------------------------
  155. bool rtsafe_memory_pool_create(RtMemPool_Handle* handlePtr,
  156. const char* poolName,
  157. size_t dataSize,
  158. size_t minPreallocated,
  159. size_t maxPreallocated)
  160. {
  161. return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated, 0);
  162. }
  163. // ------------------------------------------------------------------------------------------------
  164. bool rtsafe_memory_pool_create_safe(RtMemPool_Handle* handlePtr,
  165. const char* poolName,
  166. size_t dataSize,
  167. size_t minPreallocated,
  168. size_t maxPreallocated)
  169. {
  170. return rtsafe_memory_pool_create2(handlePtr, poolName, dataSize, minPreallocated, maxPreallocated, 1);
  171. }
  172. // ------------------------------------------------------------------------------------------------
  173. void rtsafe_memory_pool_destroy(RtMemPool_Handle handle)
  174. {
  175. assert(handle);
  176. k_list_head* nodePtr;
  177. RtMemPool* poolPtr = (RtMemPool*)handle;
  178. // caller should deallocate all chunks prior releasing pool itself
  179. if (poolPtr->usedCount != 0)
  180. {
  181. assert(0);
  182. }
  183. while (poolPtr->unusedCount != 0)
  184. {
  185. assert(! list_empty(&poolPtr->unused));
  186. nodePtr = poolPtr->unused.next;
  187. list_del(nodePtr);
  188. poolPtr->unusedCount--;
  189. free(nodePtr);
  190. }
  191. assert(list_empty(&poolPtr->unused));
  192. if (poolPtr->enforceThreadSafety)
  193. {
  194. while (! list_empty(&poolPtr->pending))
  195. {
  196. nodePtr = poolPtr->pending.next;
  197. list_del(nodePtr);
  198. free(nodePtr);
  199. }
  200. int ret = pthread_mutex_destroy(&poolPtr->mutex);
  201. #ifdef DEBUG
  202. assert(ret == 0);
  203. #else
  204. // unused
  205. (void)ret;
  206. #endif
  207. }
  208. free(poolPtr);
  209. }
  210. // ------------------------------------------------------------------------------------------------
  211. // find entry in unused list, fail if it is empty
  212. void* rtsafe_memory_pool_allocate_atomic(RtMemPool_Handle handle)
  213. {
  214. assert(handle);
  215. k_list_head* nodePtr;
  216. RtMemPool* poolPtr = (RtMemPool*)handle;
  217. if (list_empty(&poolPtr->unused))
  218. {
  219. return NULL;
  220. }
  221. nodePtr = poolPtr->unused.next;
  222. list_del(nodePtr);
  223. poolPtr->unusedCount--;
  224. poolPtr->usedCount++;
  225. list_add_tail(nodePtr, &poolPtr->used);
  226. if (poolPtr->enforceThreadSafety && pthread_mutex_trylock(&poolPtr->mutex) == 0)
  227. {
  228. while (poolPtr->unusedCount < poolPtr->minPreallocated && ! list_empty(&poolPtr->pending))
  229. {
  230. nodePtr = poolPtr->pending.next;
  231. list_del(nodePtr);
  232. list_add_tail(nodePtr, &poolPtr->unused);
  233. poolPtr->unusedCount++;
  234. }
  235. poolPtr->unusedCount2 = poolPtr->unusedCount;
  236. pthread_mutex_unlock(&poolPtr->mutex);
  237. }
  238. return (nodePtr + 1);
  239. }
  240. // ------------------------------------------------------------------------------------------------
  241. void* rtsafe_memory_pool_allocate_sleepy(RtMemPool_Handle handle)
  242. {
  243. assert(handle);
  244. void* data;
  245. RtMemPool* poolPtr = (RtMemPool*)handle;
  246. do {
  247. rtsafe_memory_pool_sleepy(poolPtr);
  248. data = rtsafe_memory_pool_allocate_atomic((RtMemPool_Handle)poolPtr);
  249. }
  250. while (data == NULL);
  251. return data;
  252. }
  253. // ------------------------------------------------------------------------------------------------
  254. // move from used to unused list
  255. void rtsafe_memory_pool_deallocate(RtMemPool_Handle handle, void* memoryPtr)
  256. {
  257. assert(handle);
  258. k_list_head* nodePtr;
  259. RtMemPool* poolPtr = (RtMemPool*)handle;
  260. list_del((k_list_head*)memoryPtr - 1);
  261. list_add_tail((k_list_head*)memoryPtr - 1, &poolPtr->unused);
  262. poolPtr->usedCount--;
  263. poolPtr->unusedCount++;
  264. if (poolPtr->enforceThreadSafety && pthread_mutex_trylock(&poolPtr->mutex) == 0)
  265. {
  266. while (poolPtr->unusedCount > poolPtr->maxPreallocated)
  267. {
  268. assert(! list_empty(&poolPtr->unused));
  269. nodePtr = poolPtr->unused.next;
  270. list_del(nodePtr);
  271. list_add_tail(nodePtr, &poolPtr->pending);
  272. poolPtr->unusedCount--;
  273. }
  274. poolPtr->unusedCount2 = poolPtr->unusedCount;
  275. pthread_mutex_unlock(&poolPtr->mutex);
  276. }
  277. }
  278. #ifdef WANT_LV2
  279. # include "rtmempool-lv2.h"
  280. void lv2_rtmempool_init(LV2_RtMemPool_Pool* poolPtr)
  281. {
  282. poolPtr->create = rtsafe_memory_pool_create;
  283. poolPtr->destroy = rtsafe_memory_pool_destroy;
  284. poolPtr->allocate_atomic = rtsafe_memory_pool_allocate_atomic;
  285. poolPtr->allocate_sleepy = rtsafe_memory_pool_allocate_sleepy;
  286. poolPtr->deallocate = rtsafe_memory_pool_deallocate;
  287. }
  288. #endif