ufdt_node_pool.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * Copyright (C) 2017 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "ufdt_node_pool.h"
  17. #include "libufdt_sysdeps.h"
  18. #include "ufdt_types.h"
  19. /* Define DEBUG_DISABLE_POOL to use dto_malloc and dto_free directly */
  20. /* #define DEBUG_DISABLE_POOL */
  21. #define MAX(a, b) ((a) > (b) ? (a) : (b))
  22. #define UFDT_NODE_POOL_ENTRIES_PER_BLOCK 1024
  23. /* UFDT_NODE_POOL_ENTRY_SIZE must be equal to or larger than
  24. sizeof(struct ufdt_node_fdt_node) and sizeof(struct ufdt_node_fdt_prop) */
  25. #define UFDT_NODE_POOL_ENTRY_SIZE \
  26. MAX(sizeof(struct ufdt_node_fdt_node), sizeof(struct ufdt_node_fdt_prop))
  27. /* A block is a header appended UFDT_NODE_POOL_ENTRIES_PER_BLOCK entries */
  28. #define UFDT_NODE_POOL_BLOCK_SIZE \
  29. (sizeof(struct ufdt_node_pool_block_header) + \
  30. UFDT_NODE_POOL_ENTRY_SIZE * UFDT_NODE_POOL_ENTRIES_PER_BLOCK)
  31. /*
  32. * The data structure:
  33. *
  34. * pool block block
  35. * +--------------+ +--------------------+ +-----------------+
  36. * | *first_block |---->| block_header: | | ... | ...
  37. * | ... | | *next_block |---->| |---->
  38. * +--------------+ | *first_free_entry |--\ | ... |
  39. * | ... | |
  40. * +--------------------+ |
  41. * | entry_header: |<-/
  42. * | *next |--\
  43. * +--------------------+ |
  44. * | ... |<-/
  45. * | |--\
  46. * +--------------------+ |
  47. * | ... | v
  48. */
  49. struct ufdt_node_pool_entry_header {
  50. struct ufdt_node_pool_entry_header *next;
  51. };
  52. struct ufdt_node_pool_block_header {
  53. struct ufdt_node_pool_block_header *next_block;
  54. struct ufdt_node_pool_entry_header *first_free_entry;
  55. int alloc_entry_cnt;
  56. };
  57. void ufdt_node_pool_construct(struct ufdt_node_pool *pool) {
  58. pool->first_block = NULL;
  59. pool->last_block_ptr = &pool->first_block;
  60. }
  61. void ufdt_node_pool_destruct(struct ufdt_node_pool *pool) {
  62. int is_leak = 0;
  63. struct ufdt_node_pool_block_header *block = pool->first_block;
  64. while (block != NULL) {
  65. if (block->alloc_entry_cnt != 0) is_leak = 1;
  66. struct ufdt_node_pool_block_header *next_block = block->next_block;
  67. dto_free(block);
  68. block = next_block;
  69. }
  70. if (is_leak) {
  71. dto_error("Some nodes aren't freed before ufdt_node_pool_destruct().\n");
  72. }
  73. pool->first_block = NULL;
  74. pool->last_block_ptr = NULL;
  75. }
  76. static struct ufdt_node_pool_block_header *_ufdt_node_pool_create_block() {
  77. char *block_buf = (char *)dto_malloc(UFDT_NODE_POOL_BLOCK_SIZE);
  78. char *block_buf_start = block_buf + sizeof(struct ufdt_node_pool_block_header);
  79. char *block_buf_end = block_buf + UFDT_NODE_POOL_BLOCK_SIZE;
  80. struct ufdt_node_pool_block_header *block =
  81. (struct ufdt_node_pool_block_header *)block_buf;
  82. // Setup all entries to be a one way link list
  83. struct ufdt_node_pool_entry_header **next_ptr = &block->first_free_entry;
  84. for (char *entry_buf = block_buf_start; entry_buf < block_buf_end;
  85. entry_buf += UFDT_NODE_POOL_ENTRY_SIZE) {
  86. struct ufdt_node_pool_entry_header *entry =
  87. (struct ufdt_node_pool_entry_header *)entry_buf;
  88. *next_ptr = entry;
  89. next_ptr = &entry->next;
  90. }
  91. *next_ptr = NULL;
  92. block->next_block = NULL;
  93. block->alloc_entry_cnt = 0;
  94. return block;
  95. }
  96. static void _ufdt_node_pool_destory_block(
  97. struct ufdt_node_pool_block_header *block) {
  98. dto_free(block);
  99. }
  100. static void *_ufdt_node_pool_block_alloc(
  101. struct ufdt_node_pool_block_header *block) {
  102. // take the first free enrtry
  103. struct ufdt_node_pool_entry_header *entry = block->first_free_entry;
  104. block->first_free_entry = entry->next;
  105. block->alloc_entry_cnt++;
  106. return entry;
  107. }
  108. static void _ufdt_node_pool_block_free(struct ufdt_node_pool_block_header *block,
  109. void *node) {
  110. // put the node to the first free enrtry
  111. struct ufdt_node_pool_entry_header *entry = node;
  112. entry->next = block->first_free_entry;
  113. block->first_free_entry = entry;
  114. block->alloc_entry_cnt--;
  115. }
  116. static void _ufdt_node_pool_preppend_block(
  117. struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
  118. struct ufdt_node_pool_block_header *origin_first_block = pool->first_block;
  119. block->next_block = origin_first_block;
  120. pool->first_block = block;
  121. if (origin_first_block == NULL) {
  122. pool->last_block_ptr = &block->next_block;
  123. }
  124. }
  125. static void _ufdt_node_pool_append_block(
  126. struct ufdt_node_pool *pool, struct ufdt_node_pool_block_header *block) {
  127. block->next_block = NULL;
  128. *pool->last_block_ptr = block;
  129. pool->last_block_ptr = &block->next_block;
  130. }
  131. static void _ufdt_node_pool_remove_block(
  132. struct ufdt_node_pool *pool,
  133. struct ufdt_node_pool_block_header **block_ptr) {
  134. struct ufdt_node_pool_block_header *block = *block_ptr;
  135. struct ufdt_node_pool_block_header *next_block = block->next_block;
  136. *block_ptr = next_block;
  137. if (next_block == NULL) {
  138. pool->last_block_ptr = block_ptr;
  139. }
  140. block->next_block = NULL;
  141. }
  142. void *ufdt_node_pool_alloc(struct ufdt_node_pool *pool) {
  143. #ifdef DEBUG_DISABLE_POOL
  144. return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
  145. #endif
  146. // return dto_malloc(UFDT_NODE_POOL_ENTRY_SIZE);
  147. // If there is no free block, create a new one
  148. struct ufdt_node_pool_block_header *block = pool->first_block;
  149. if (block == NULL || block->first_free_entry == NULL) {
  150. block = _ufdt_node_pool_create_block();
  151. _ufdt_node_pool_preppend_block(pool, block);
  152. }
  153. void *node = _ufdt_node_pool_block_alloc(block);
  154. // Move the block to the last if there is no free entry
  155. if (block->first_free_entry == NULL && *pool->last_block_ptr != block) {
  156. _ufdt_node_pool_remove_block(pool, &pool->first_block);
  157. _ufdt_node_pool_append_block(pool, block);
  158. }
  159. return node;
  160. }
  161. static struct ufdt_node_pool_block_header **_ufdt_node_pool_search_block(
  162. struct ufdt_node_pool *pool, void *node) {
  163. struct ufdt_node_pool_block_header **block_ptr = &pool->first_block;
  164. while (*block_ptr != NULL) {
  165. struct ufdt_node_pool_block_header *block = *block_ptr;
  166. const char *block_buf_start =
  167. (char *)block + sizeof(struct ufdt_node_pool_block_header);
  168. const char *block_buf_end = (char *)block + UFDT_NODE_POOL_BLOCK_SIZE;
  169. if ((char *)node >= block_buf_start && (char *)node < block_buf_end) {
  170. break;
  171. }
  172. block_ptr = &block->next_block;
  173. }
  174. return block_ptr;
  175. }
  176. void ufdt_node_pool_free(struct ufdt_node_pool *pool, void *node) {
  177. #ifdef DEBUG_DISABLE_POOL
  178. return dto_free(node);
  179. #endif
  180. struct ufdt_node_pool_block_header **block_ptr =
  181. _ufdt_node_pool_search_block(pool, node);
  182. if (*block_ptr == NULL) {
  183. dto_error("Given node is not in the pool.\n");
  184. return;
  185. }
  186. struct ufdt_node_pool_block_header *block = *block_ptr;
  187. _ufdt_node_pool_block_free(block, node);
  188. _ufdt_node_pool_remove_block(pool, block_ptr);
  189. /* Delay free block: free the block only if the block is all freed and
  190. there has at least one another free block */
  191. if (block->alloc_entry_cnt == 0 && pool->first_block != NULL &&
  192. pool->first_block->first_free_entry != NULL) {
  193. _ufdt_node_pool_destory_block(block);
  194. return;
  195. }
  196. _ufdt_node_pool_preppend_block(pool, block);
  197. }