Collection of tools useful for audio production
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.

398 lines
9.4KB

  1. /* -*- Mode: C ; c-basic-offset: 2 -*- */
  2. /*****************************************************************************
  3. *
  4. * This file is part of zynjacku
  5. *
  6. * Copyright (C) 2006,2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name>
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; version 2 of the License
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20. *
  21. *****************************************************************************/
  22. #include <stddef.h>
  23. #include <stdbool.h>
  24. #include <string.h>
  25. #include <stdio.h> /* sprintf */
  26. #include <stdlib.h>
  27. #include <assert.h>
  28. #include <pthread.h>
  29. #include "lv2/lv2_rtmempool.h"
  30. #include "rtmempool.h"
  31. #include "list.h"
  32. //#define LOG_LEVEL LOG_LEVEL_DEBUG
  33. #include "log.h"
  34. struct rtsafe_memory_pool
  35. {
  36. char name[LV2_RTSAFE_MEMORY_POOL_NAME_MAX];
  37. size_t data_size;
  38. size_t min_preallocated;
  39. size_t max_preallocated;
  40. unsigned int used_count;
  41. struct list_head unused;
  42. struct list_head used;
  43. unsigned int unused_count;
  44. bool enforce_thread_safety;
  45. /* next members are initialized/used only if enforce_thread_safety is true */
  46. pthread_mutex_t mutex;
  47. unsigned int unused_count2;
  48. struct list_head pending;
  49. size_t used_size;
  50. };
  51. static
  52. void
  53. rtsafe_memory_pool_sleepy(
  54. lv2_rtsafe_memory_pool_handle pool_handle);
  55. static
  56. bool
  57. rtsafe_memory_pool_create(
  58. const char * pool_name,
  59. size_t data_size,
  60. size_t min_preallocated,
  61. size_t max_preallocated,
  62. bool enforce_thread_safety,
  63. lv2_rtsafe_memory_pool_handle * pool_handle_ptr)
  64. {
  65. int ret;
  66. struct rtsafe_memory_pool * pool_ptr;
  67. assert(min_preallocated <= max_preallocated);
  68. assert(pool_name == NULL || strlen(pool_name) < LV2_RTSAFE_MEMORY_POOL_NAME_MAX);
  69. LOG_DEBUG(
  70. "creating pool \"%s\" (size %u, min = %u, max = %u, enforce = %s)",
  71. pool_name,
  72. (unsigned int)data_size,
  73. (unsigned int)min_preallocated,
  74. (unsigned int)max_preallocated,
  75. enforce_thread_safety ? "true" : "false");
  76. pool_ptr = malloc(sizeof(struct rtsafe_memory_pool));
  77. if (pool_ptr == NULL)
  78. {
  79. return false;
  80. }
  81. if (pool_name != NULL)
  82. {
  83. strcpy(pool_ptr->name, pool_name);
  84. }
  85. else
  86. {
  87. sprintf(pool_ptr->name, "%p", pool_ptr);
  88. }
  89. pool_ptr->data_size = data_size;
  90. pool_ptr->min_preallocated = min_preallocated;
  91. pool_ptr->max_preallocated = max_preallocated;
  92. INIT_LIST_HEAD(&pool_ptr->used);
  93. pool_ptr->used_count = 0;
  94. INIT_LIST_HEAD(&pool_ptr->unused);
  95. pool_ptr->unused_count = 0;
  96. pool_ptr->enforce_thread_safety = enforce_thread_safety;
  97. if (enforce_thread_safety)
  98. {
  99. ret = pthread_mutex_init(&pool_ptr->mutex, NULL);
  100. if (ret != 0)
  101. {
  102. free(pool_ptr);
  103. return false;
  104. }
  105. INIT_LIST_HEAD(&pool_ptr->pending);
  106. pool_ptr->unused_count2 = 0;
  107. }
  108. pool_ptr->used_size = 0;
  109. rtsafe_memory_pool_sleepy((lv2_rtsafe_memory_pool_handle)pool_ptr);
  110. *pool_handle_ptr = (lv2_rtsafe_memory_pool_handle)pool_ptr;
  111. return true;
  112. }
  113. #define pool_ptr ((struct rtsafe_memory_pool *)pool_handle)
  114. static
  115. void
  116. rtsafe_memory_pool_destroy(
  117. lv2_rtsafe_memory_pool_handle pool_handle)
  118. {
  119. int ret;
  120. struct list_head * node_ptr;
  121. LOG_DEBUG("destroying pool \"%s\"", pool_ptr->name);
  122. /* caller should deallocate all chunks prior releasing pool itself */
  123. if (pool_ptr->used_count != 0)
  124. {
  125. LOG_WARNING("Deallocating non-empty pool \"%s\", leaking %u entries:", pool_ptr->name, pool_ptr->used_count);
  126. list_for_each(node_ptr, &pool_ptr->used)
  127. {
  128. LOG_WARNING(" %p", node_ptr + 1);
  129. }
  130. assert(0);
  131. }
  132. while (pool_ptr->unused_count != 0)
  133. {
  134. assert(!list_empty(&pool_ptr->unused));
  135. node_ptr = pool_ptr->unused.next;
  136. list_del(node_ptr);
  137. pool_ptr->unused_count--;
  138. free(node_ptr);
  139. }
  140. assert(list_empty(&pool_ptr->unused));
  141. if (pool_ptr->enforce_thread_safety)
  142. {
  143. while (!list_empty(&pool_ptr->pending))
  144. {
  145. node_ptr = pool_ptr->pending.next;
  146. list_del(node_ptr);
  147. free(node_ptr);
  148. }
  149. ret = pthread_mutex_destroy(&pool_ptr->mutex);
  150. assert(ret == 0);
  151. }
  152. free(pool_ptr);
  153. // unused variable
  154. (void)ret;
  155. }
  156. /* adjust unused list size */
  157. static
  158. void
  159. rtsafe_memory_pool_sleepy(
  160. lv2_rtsafe_memory_pool_handle pool_handle)
  161. {
  162. struct list_head * node_ptr;
  163. unsigned int count;
  164. LOG_DEBUG("pool \"%s\", sleepy", pool_ptr->name);
  165. if (pool_ptr->enforce_thread_safety)
  166. {
  167. pthread_mutex_lock(&pool_ptr->mutex);
  168. count = pool_ptr->unused_count2;
  169. assert(pool_ptr->min_preallocated < pool_ptr->max_preallocated);
  170. while (count < pool_ptr->min_preallocated)
  171. {
  172. node_ptr = malloc(sizeof(struct list_head) + pool_ptr->data_size);
  173. if (node_ptr == NULL)
  174. {
  175. LOG_DEBUG("malloc() failed (%u)", (unsigned int)pool_ptr->used_size);
  176. break;
  177. }
  178. list_add_tail(node_ptr, &pool_ptr->pending);
  179. count++;
  180. pool_ptr->used_size += pool_ptr->data_size;
  181. }
  182. while (count > pool_ptr->max_preallocated && !list_empty(&pool_ptr->pending))
  183. {
  184. node_ptr = pool_ptr->pending.next;
  185. list_del(node_ptr);
  186. free(node_ptr);
  187. count--;
  188. pool_ptr->used_size -= pool_ptr->data_size;
  189. }
  190. pthread_mutex_unlock(&pool_ptr->mutex);
  191. }
  192. else
  193. {
  194. while (pool_ptr->unused_count < pool_ptr->min_preallocated)
  195. {
  196. node_ptr = malloc(sizeof(struct list_head) + pool_ptr->data_size);
  197. if (node_ptr == NULL)
  198. {
  199. LOG_DEBUG("malloc() failed (%u)", (unsigned int)pool_ptr->used_size);
  200. return;
  201. }
  202. list_add_tail(node_ptr, &pool_ptr->unused);
  203. pool_ptr->unused_count++;
  204. pool_ptr->used_size += pool_ptr->data_size;
  205. }
  206. while (pool_ptr->unused_count > pool_ptr->max_preallocated)
  207. {
  208. assert(!list_empty(&pool_ptr->unused));
  209. node_ptr = pool_ptr->unused.next;
  210. list_del(node_ptr);
  211. pool_ptr->unused_count--;
  212. free(node_ptr);
  213. pool_ptr->used_size -= pool_ptr->data_size;
  214. }
  215. }
  216. }
  217. /* find entry in unused list, fail if it is empty */
  218. static
  219. void *
  220. rtsafe_memory_pool_allocate_atomic(
  221. lv2_rtsafe_memory_pool_handle pool_handle)
  222. {
  223. struct list_head * node_ptr;
  224. LOG_DEBUG("pool \"%s\", allocate (%u, %u)", pool_ptr->name, pool_ptr->used_count, pool_ptr->unused_count);
  225. if (list_empty(&pool_ptr->unused))
  226. {
  227. return NULL;
  228. }
  229. node_ptr = pool_ptr->unused.next;
  230. list_del(node_ptr);
  231. pool_ptr->unused_count--;
  232. pool_ptr->used_count++;
  233. list_add_tail(node_ptr, &pool_ptr->used);
  234. if (pool_ptr->enforce_thread_safety &&
  235. pthread_mutex_trylock(&pool_ptr->mutex) == 0)
  236. {
  237. while (pool_ptr->unused_count < pool_ptr->min_preallocated && !list_empty(&pool_ptr->pending))
  238. {
  239. node_ptr = pool_ptr->pending.next;
  240. list_del(node_ptr);
  241. list_add_tail(node_ptr, &pool_ptr->unused);
  242. pool_ptr->unused_count++;
  243. }
  244. pool_ptr->unused_count2 = pool_ptr->unused_count;
  245. pthread_mutex_unlock(&pool_ptr->mutex);
  246. }
  247. LOG_DEBUG("pool \"%s\", allocated %p (%u)", pool_ptr->name, node_ptr + 1, pool_ptr->used_count);
  248. return (node_ptr + 1);
  249. }
  250. /* move from used to unused list */
  251. static
  252. void
  253. rtsafe_memory_pool_deallocate(
  254. lv2_rtsafe_memory_pool_handle pool_handle,
  255. void * data)
  256. {
  257. struct list_head * node_ptr;
  258. LOG_DEBUG("pool \"%s\", deallocate %p (%u)", pool_ptr->name, (struct list_head *)data - 1, pool_ptr->used_count);
  259. list_del((struct list_head *)data - 1);
  260. list_add_tail((struct list_head *)data - 1, &pool_ptr->unused);
  261. pool_ptr->used_count--;
  262. pool_ptr->unused_count++;
  263. if (pool_ptr->enforce_thread_safety &&
  264. pthread_mutex_trylock(&pool_ptr->mutex) == 0)
  265. {
  266. while (pool_ptr->unused_count > pool_ptr->max_preallocated)
  267. {
  268. assert(!list_empty(&pool_ptr->unused));
  269. node_ptr = pool_ptr->unused.next;
  270. list_del(node_ptr);
  271. list_add_tail(node_ptr, &pool_ptr->pending);
  272. pool_ptr->unused_count--;
  273. }
  274. pool_ptr->unused_count2 = pool_ptr->unused_count;
  275. pthread_mutex_unlock(&pool_ptr->mutex);
  276. }
  277. }
  278. static
  279. void *
  280. rtsafe_memory_pool_allocate_sleepy(
  281. lv2_rtsafe_memory_pool_handle pool_handle)
  282. {
  283. void * data;
  284. LOG_DEBUG("pool \"%s\", allocate sleepy", pool_ptr->name);
  285. do
  286. {
  287. rtsafe_memory_pool_sleepy(pool_handle);
  288. data = rtsafe_memory_pool_allocate_atomic(pool_handle);
  289. }
  290. while (data == NULL);
  291. return data;
  292. }
  293. #undef pool_ptr
  294. static
  295. unsigned char
  296. rtsafe_memory_pool_create2(
  297. const char * pool_name,
  298. size_t data_size,
  299. size_t min_preallocated,
  300. size_t max_preallocated,
  301. lv2_rtsafe_memory_pool_handle * pool_ptr)
  302. {
  303. return rtsafe_memory_pool_create(pool_name, data_size, min_preallocated, max_preallocated, false, pool_ptr);
  304. }
  305. void
  306. rtmempool_allocator_init(
  307. lv2_rtsafe_memory_pool_provider * allocator_ptr)
  308. {
  309. allocator_ptr->create = rtsafe_memory_pool_create2;
  310. allocator_ptr->destroy = rtsafe_memory_pool_destroy;
  311. allocator_ptr->allocate_atomic = rtsafe_memory_pool_allocate_atomic;
  312. allocator_ptr->allocate_sleepy = rtsafe_memory_pool_allocate_sleepy;
  313. allocator_ptr->deallocate = rtsafe_memory_pool_deallocate;
  314. }