generic_alloc_impl.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. /*
  2. * Copyright (c) 2016, Blender Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "Apache License")
  5. * with the following modification; you may not use this file except in
  6. * compliance with the Apache License and the following modification to it:
  7. * Section 6. Trademarks. is deleted and replaced with:
  8. *
  9. * 6. Trademarks. This License does not grant permission to use the trade
  10. * names, trademarks, service marks, or product names of the Licensor
  11. * and its affiliates, except as required to comply with Section 4(c) of
  12. * the License and to reproduce the content of the NOTICE file.
  13. *
  14. * You may obtain a copy of the Apache License at
  15. *
  16. * http://www.apache.org/licenses/LICENSE-2.0
  17. *
  18. * Unless required by applicable law or agreed to in writing, software
  19. * distributed under the Apache License with the above modification is
  20. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  21. * KIND, either express or implied. See the Apache License for the specific
  22. * language governing permissions and limitations under the Apache License.
  23. */
  24. /**
  25. * Simple Memory Chunking Allocator
  26. * ================================
  27. *
  28. * Defines need to be set:
  29. * - #TPOOL_IMPL_PREFIX: Prefix to use for the API.
  30. * - #TPOOL_ALLOC_TYPE: Struct type this pool handles.
  31. * - #TPOOL_STRUCT: Name for pool struct name.
  32. * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined.
  33. *
  34. * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``.
  35. *
  36. * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function.
  37. *
  38. * - *_pool_create()
  39. * - *_pool_destroy()
  40. * - *_pool_clear()
  41. *
  42. * - *_pool_elem_alloc()
  43. * - *_pool_elem_calloc()
  44. * - *_pool_elem_free()
  45. */
  46. /* check we're not building directly */
  47. #if !defined(TPOOL_IMPL_PREFIX) || \
  48. !defined(TPOOL_ALLOC_TYPE) || \
  49. !defined(TPOOL_STRUCT)
  50. # error "This file can't be compiled directly, include in another source file"
  51. #endif
  52. #define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2
  53. #define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2)
  54. #define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id)
  55. /* local identifiers */
  56. #define pool_create _TPOOL_PREFIX(pool_create)
  57. #define pool_destroy _TPOOL_PREFIX(pool_destroy)
  58. #define pool_clear _TPOOL_PREFIX(pool_clear)
  59. #define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc)
  60. #define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc)
  61. #define pool_elem_free _TPOOL_PREFIX(pool_elem_free)
  62. /* private identifiers (only for this file, undefine after) */
  63. #define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk)
  64. #define TPoolChunk _TPOOL_PREFIX(TPoolChunk)
  65. #define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree)
  66. #ifndef TPOOL_CHUNK_SIZE
  67. #define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */
  68. #define _TPOOL_CHUNK_SIZE_UNDEF
  69. #endif
  70. #ifndef UNLIKELY
  71. # ifdef __GNUC__
  72. # define UNLIKELY(x) __builtin_expect(!!(x), 0)
  73. # else
  74. # define UNLIKELY(x) (x)
  75. # endif
  76. #endif
  77. #ifdef __GNUC__
  78. # define MAYBE_UNUSED __attribute__((unused))
  79. #else
  80. # define MAYBE_UNUSED
  81. #endif
  82. struct TPoolChunk {
  83. struct TPoolChunk *prev;
  84. unsigned int size;
  85. unsigned int bufsize;
  86. TPOOL_ALLOC_TYPE buf[0];
  87. };
  88. struct TPoolChunkElemFree {
  89. struct TPoolChunkElemFree *next;
  90. };
  91. struct TPOOL_STRUCT {
  92. /* Always keep at least one chunk (never NULL) */
  93. struct TPoolChunk *chunk;
  94. /* when NULL, allocate a new chunk */
  95. struct TPoolChunkElemFree *free;
  96. };
  97. /**
  98. * Number of elems to include per #TPoolChunk when no reserved size is passed,
  99. * or we allocate past the reserved number.
  100. *
  101. * \note Optimize number for 64kb allocs.
  102. */
  103. #define _TPOOL_CHUNK_DEFAULT_NUM \
  104. (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE))
  105. /** \name Internal Memory Management
  106. * \{ */
  107. static struct TPoolChunk *pool_alloc_chunk(
  108. unsigned int tot_elems, struct TPoolChunk *chunk_prev)
  109. {
  110. struct TPoolChunk *chunk = malloc(
  111. sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems));
  112. chunk->prev = chunk_prev;
  113. chunk->bufsize = tot_elems;
  114. chunk->size = 0;
  115. return chunk;
  116. }
  117. static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool)
  118. {
  119. TPOOL_ALLOC_TYPE *elem;
  120. if (pool->free) {
  121. elem = (TPOOL_ALLOC_TYPE *)pool->free;
  122. pool->free = pool->free->next;
  123. }
  124. else {
  125. struct TPoolChunk *chunk = pool->chunk;
  126. if (UNLIKELY(chunk->size == chunk->bufsize)) {
  127. chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk);
  128. }
  129. elem = &chunk->buf[chunk->size++];
  130. }
  131. return elem;
  132. }
  133. MAYBE_UNUSED
  134. static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool)
  135. {
  136. TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool);
  137. memset(elem, 0, sizeof(*elem));
  138. return elem;
  139. }
  140. static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem)
  141. {
  142. struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem;
  143. elem_free->next = pool->free;
  144. pool->free = elem_free;
  145. }
  146. static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve)
  147. {
  148. pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL);
  149. pool->free = NULL;
  150. }
  151. MAYBE_UNUSED
  152. static void pool_clear(struct TPOOL_STRUCT *pool)
  153. {
  154. /* Remove all except the last chunk */
  155. while (pool->chunk->prev) {
  156. struct TPoolChunk *chunk_prev = pool->chunk->prev;
  157. free(pool->chunk);
  158. pool->chunk = chunk_prev;
  159. }
  160. pool->chunk->size = 0;
  161. pool->free = NULL;
  162. }
  163. static void pool_destroy(struct TPOOL_STRUCT *pool)
  164. {
  165. struct TPoolChunk *chunk = pool->chunk;
  166. do {
  167. struct TPoolChunk *chunk_prev;
  168. chunk_prev = chunk->prev;
  169. free(chunk);
  170. chunk = chunk_prev;
  171. } while (chunk);
  172. pool->chunk = NULL;
  173. pool->free = NULL;
  174. }
  175. /** \} */
  176. #undef _TPOOL_CHUNK_DEFAULT_NUM
  177. #undef _CONCAT_AUX
  178. #undef _CONCAT
  179. #undef _TPOOL_PREFIX
  180. #undef TPoolChunk
  181. #undef TPoolChunkElemFree
  182. #ifdef _TPOOL_CHUNK_SIZE_UNDEF
  183. # undef TPOOL_CHUNK_SIZE
  184. # undef _TPOOL_CHUNK_SIZE_UNDEF
  185. #endif