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.

358 lines
7.8KB

  1. /* -*- Mode: C ; c-basic-offset: 2 -*- */
  2. /*****************************************************************************
  3. *
  4. * Non-sleeping memory allocation
  5. *
  6. * Copyright (C) 2006,2007 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 <stdlib.h>
  23. #include <assert.h>
  24. #include "memory_atomic.h"
  25. #include "list.h"
  26. #define TRUE 1
  27. #define FALSE 0
  28. struct rtsafe_memory_pool
  29. {
  30. size_t data_size;
  31. size_t min_preallocated;
  32. size_t max_preallocated;
  33. struct list_head used;
  34. unsigned int used_count;
  35. struct list_head unused;
  36. unsigned int unused_count;
  37. };
  38. #define RTSAFE_GROUPS_PREALLOCATE 1024
  39. int
  40. rtsafe_memory_pool_create(
  41. size_t data_size,
  42. size_t min_preallocated,
  43. size_t max_preallocated,
  44. rtsafe_memory_pool_handle * pool_handle_ptr)
  45. {
  46. struct rtsafe_memory_pool * pool_ptr;
  47. assert(min_preallocated <= max_preallocated);
  48. pool_ptr = malloc(sizeof(struct rtsafe_memory_pool));
  49. if (pool_ptr == NULL)
  50. {
  51. return FALSE;
  52. }
  53. pool_ptr->data_size = data_size;
  54. pool_ptr->min_preallocated = min_preallocated;
  55. pool_ptr->max_preallocated = max_preallocated;
  56. INIT_LIST_HEAD(&pool_ptr->used);
  57. pool_ptr->used_count = 0;
  58. INIT_LIST_HEAD(&pool_ptr->unused);
  59. pool_ptr->unused_count = 0;
  60. rtsafe_memory_pool_sleepy((rtsafe_memory_pool_handle)pool_ptr);
  61. *pool_handle_ptr = pool_ptr;
  62. return TRUE;
  63. }
  64. #define pool_ptr ((struct rtsafe_memory_pool *)pool_handle)
  65. void
  66. rtsafe_memory_pool_destroy(
  67. rtsafe_memory_pool_handle pool_handle)
  68. {
  69. struct list_head * node_ptr;
  70. assert(pool_ptr->used_count == 0); /* called should deallocate all chunks prior releasing pool itself */
  71. assert(list_empty(&pool_ptr->used));
  72. while (pool_ptr->unused_count != 0)
  73. {
  74. assert(!list_empty(&pool_ptr->unused));
  75. node_ptr = pool_ptr->unused.next;
  76. list_del(node_ptr);
  77. pool_ptr->unused_count--;
  78. free(node_ptr);
  79. }
  80. assert(list_empty(&pool_ptr->unused));
  81. free(pool_ptr);
  82. }
  83. /* adjust unused list size */
  84. void
  85. rtsafe_memory_pool_sleepy(
  86. rtsafe_memory_pool_handle pool_handle)
  87. {
  88. struct list_head * node_ptr;
  89. while (pool_ptr->unused_count < pool_ptr->min_preallocated)
  90. {
  91. node_ptr = malloc(sizeof(struct list_head) + pool_ptr->data_size);
  92. if (node_ptr == NULL)
  93. {
  94. return;
  95. }
  96. list_add_tail(node_ptr, &pool_ptr->unused);
  97. pool_ptr->unused_count++;
  98. }
  99. while (pool_ptr->unused_count > pool_ptr->max_preallocated)
  100. {
  101. assert(!list_empty(&pool_ptr->unused));
  102. node_ptr = pool_ptr->unused.next;
  103. list_del(node_ptr);
  104. pool_ptr->unused_count--;
  105. free(node_ptr);
  106. }
  107. }
  108. /* find entry in unused list, fail if it is empty */
  109. void *
  110. rtsafe_memory_pool_allocate(
  111. rtsafe_memory_pool_handle pool_handle)
  112. {
  113. struct list_head * node_ptr;
  114. if (list_empty(&pool_ptr->unused))
  115. {
  116. return NULL;
  117. }
  118. node_ptr = pool_ptr->unused.next;
  119. list_del(node_ptr);
  120. pool_ptr->unused_count--;
  121. pool_ptr->used_count++;
  122. return (node_ptr + 1);
  123. }
  124. /* move from used to unused list */
  125. void
  126. rtsafe_memory_pool_deallocate(
  127. rtsafe_memory_pool_handle pool_handle,
  128. void * data)
  129. {
  130. list_add_tail((struct list_head *)data - 1, &pool_ptr->unused);
  131. pool_ptr->used_count--;
  132. pool_ptr->unused_count++;
  133. }
  134. void *
  135. rtsafe_memory_pool_allocate_sleepy(
  136. rtsafe_memory_pool_handle pool_handle)
  137. {
  138. void * data;
  139. do
  140. {
  141. rtsafe_memory_pool_sleepy(pool_handle);
  142. data = rtsafe_memory_pool_allocate(pool_handle);
  143. }
  144. while (data == NULL);
  145. return data;
  146. }
  147. /* max alloc is DATA_MIN * (2 ^ POOLS_COUNT) - DATA_SUB */
  148. #define DATA_MIN 1024
  149. #define DATA_SUB 100 /* alloc slightly smaller chunks in hope to not allocating additional page for control data */
  150. struct rtsafe_memory_pool_generic
  151. {
  152. size_t size;
  153. rtsafe_memory_pool_handle pool;
  154. };
  155. struct rtsafe_memory
  156. {
  157. struct rtsafe_memory_pool_generic * pools;
  158. size_t pools_count;
  159. };
  160. int
  161. rtsafe_memory_init(
  162. size_t max_size,
  163. size_t prealloc_min,
  164. size_t prealloc_max,
  165. rtsafe_memory_handle * handle_ptr)
  166. {
  167. size_t i;
  168. size_t size;
  169. struct rtsafe_memory * memory_ptr;
  170. //LOG_DEBUG("rtsafe_memory_init() called.");
  171. memory_ptr = malloc(sizeof(struct rtsafe_memory));
  172. if (memory_ptr == NULL)
  173. {
  174. goto fail;
  175. }
  176. size = DATA_MIN;
  177. memory_ptr->pools_count = 1;
  178. while ((size << memory_ptr->pools_count) < max_size + DATA_SUB)
  179. {
  180. memory_ptr->pools_count++;
  181. if (memory_ptr->pools_count > sizeof(size_t) * 8)
  182. {
  183. assert(0); /* chances that caller really need such huge size are close to zero */
  184. goto fail_free;
  185. }
  186. }
  187. memory_ptr->pools = malloc(memory_ptr->pools_count * sizeof(struct rtsafe_memory_pool_generic));
  188. if (memory_ptr->pools == NULL)
  189. {
  190. goto fail_free;
  191. }
  192. size = DATA_MIN;
  193. for (i = 0 ; i < memory_ptr->pools_count ; i++)
  194. {
  195. memory_ptr->pools[i].size = size - DATA_SUB;
  196. if (!rtsafe_memory_pool_create(
  197. memory_ptr->pools[i].size,
  198. prealloc_min,
  199. prealloc_max,
  200. &memory_ptr->pools[i].pool))
  201. {
  202. while (i > 0)
  203. {
  204. i--;
  205. rtsafe_memory_pool_destroy(memory_ptr->pools[i].pool);
  206. }
  207. goto fail_free_pools;
  208. }
  209. size = size << 1;
  210. }
  211. *handle_ptr = (rtsafe_memory_handle)memory_ptr;
  212. return TRUE;
  213. fail_free_pools:
  214. free(memory_ptr->pools);
  215. fail_free:
  216. free(memory_ptr);
  217. fail:
  218. return FALSE;
  219. }
  220. #define memory_ptr ((struct rtsafe_memory *)handle_ptr)
  221. void
  222. rtsafe_memory_uninit(
  223. rtsafe_memory_handle handle_ptr)
  224. {
  225. unsigned int i;
  226. //LOG_DEBUG("rtsafe_memory_uninit() called.");
  227. for (i = 0 ; i < memory_ptr->pools_count ; i++)
  228. {
  229. //LOG_DEBUG("Destroying pool for size %u", (unsigned int)memory_ptr->pools[i].size);
  230. rtsafe_memory_pool_destroy(memory_ptr->pools[i].pool);
  231. }
  232. free(memory_ptr->pools);
  233. free(memory_ptr);
  234. }
  235. void *
  236. rtsafe_memory_allocate(
  237. rtsafe_memory_handle handle_ptr,
  238. size_t size)
  239. {
  240. rtsafe_memory_pool_handle * data_ptr;
  241. size_t i;
  242. //LOG_DEBUG("rtsafe_memory_allocate() called.");
  243. /* pool handle is stored just before user data to ease deallocation */
  244. size += sizeof(rtsafe_memory_pool_handle);
  245. for (i = 0 ; i < memory_ptr->pools_count ; i++)
  246. {
  247. if (size <= memory_ptr->pools[i].size)
  248. {
  249. //LOG_DEBUG("Using chunk with size %u.", (unsigned int)memory_ptr->pools[i].size);
  250. data_ptr = rtsafe_memory_pool_allocate(memory_ptr->pools[i].pool);
  251. if (data_ptr == NULL)
  252. {
  253. //LOG_DEBUG("rtsafe_memory_pool_allocate() failed.");
  254. return FALSE;
  255. }
  256. *data_ptr = memory_ptr->pools[i].pool;
  257. //LOG_DEBUG("rtsafe_memory_allocate() returning %p", (data_ptr + 1));
  258. return (data_ptr + 1);
  259. }
  260. }
  261. /* data size too big, increase POOLS_COUNT */
  262. //LOG_WARNING("Data size is too big");
  263. return FALSE;
  264. }
  265. void
  266. rtsafe_memory_sleepy(
  267. rtsafe_memory_handle handle_ptr)
  268. {
  269. unsigned int i;
  270. for (i = 0 ; i < memory_ptr->pools_count ; i++)
  271. {
  272. rtsafe_memory_pool_sleepy(memory_ptr->pools[i].pool);
  273. }
  274. }
  275. void
  276. rtsafe_memory_deallocate(
  277. void * data)
  278. {
  279. //LOG_DEBUG("rtsafe_memory_deallocate(%p) called.", data);
  280. rtsafe_memory_pool_deallocate(
  281. *((rtsafe_memory_pool_handle *)data -1),
  282. (rtsafe_memory_pool_handle *)data - 1);
  283. }