finsh_heap.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2010-03-22 Bernard first version
  9. */
  10. #include <finsh.h>
  11. #include "finsh_var.h"
  12. ALIGN(RT_ALIGN_SIZE)
  13. uint8_t finsh_heap[FINSH_HEAP_MAX];
  14. struct finsh_block_header
  15. {
  16. uint32_t length;
  17. struct finsh_block_header* next;
  18. };
  19. #define BLOCK_HEADER(x) (struct finsh_block_header*)(x)
  20. #define finsh_block_get_header(data) (struct finsh_block_header*)((uint8_t*)data - sizeof(struct finsh_block_header))
  21. #define finsh_block_get_data(header) (uint8_t*)((struct finsh_block_header*)header + 1)
  22. #define HEAP_ALIGN_SIZE(size) (((size) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT-1))
  23. static struct finsh_block_header* free_list;
  24. static struct finsh_block_header* allocate_list;
  25. static void finsh_heap_gc(void);
  26. static void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header);
  27. static void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header);
  28. static void finsh_block_split(struct finsh_block_header* header, size_t size);
  29. static void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header);
  30. int finsh_heap_init(void)
  31. {
  32. /* clear heap to zero */
  33. memset(&finsh_heap[0], 0, sizeof(finsh_heap));
  34. /* init free and alloc list */
  35. free_list = BLOCK_HEADER(&finsh_heap[0]);
  36. free_list->length = FINSH_HEAP_MAX - sizeof(struct finsh_block_header);
  37. free_list->next = NULL;
  38. allocate_list = NULL;
  39. return 0;
  40. }
  41. /**
  42. * allocate a block from heap
  43. */
  44. void* finsh_heap_allocate(size_t size)
  45. {
  46. struct finsh_block_header* header;
  47. size = HEAP_ALIGN_SIZE(size);
  48. /* find the first fit block */
  49. for (header = free_list;
  50. ((header != NULL) && (header->length <= size + sizeof(struct finsh_block_header)));
  51. header = header->next) ;
  52. if (header == NULL)
  53. {
  54. finsh_heap_gc();
  55. /* find the first fit block */
  56. for (header = free_list;
  57. ((header != NULL) && (header->length < size + sizeof(struct finsh_block_header)));
  58. header = header->next) ;
  59. /* there is no memory */
  60. if (header == NULL) return NULL;
  61. }
  62. /* split block */
  63. finsh_block_split(header, size);
  64. /* remove from free list */
  65. finsh_block_remove(&free_list, header);
  66. header->next = NULL;
  67. /* insert to allocate list */
  68. finsh_block_insert(&allocate_list, header);
  69. memset(finsh_block_get_data(header), 0, size);
  70. return finsh_block_get_data(header);
  71. }
  72. /**
  73. * release the allocated block
  74. */
  75. void finsh_heap_free(void*ptr)
  76. {
  77. struct finsh_block_header* header;
  78. /* get block header */
  79. header = finsh_block_get_header(ptr);
  80. /* remove from allocate list */
  81. finsh_block_remove(&allocate_list, header);
  82. /* insert to free list */
  83. finsh_block_insert(&free_list, header);
  84. finsh_block_merge(&free_list, header);
  85. }
  86. /**
  87. * garbage collector
  88. */
  89. static void finsh_heap_gc(void)
  90. {
  91. int i;
  92. struct finsh_block_header *header, *temp;
  93. temp = NULL;
  94. /* find the first fit block */
  95. for (header = allocate_list; header != NULL; )
  96. {
  97. for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
  98. {
  99. if (global_variable[i].type != finsh_type_unknown)
  100. {
  101. if (global_variable[i].value.ptr == finsh_block_get_data(header))
  102. break;
  103. }
  104. }
  105. temp = header;
  106. header = header->next;
  107. /* this block is an unused block, release it */
  108. if (i == FINSH_VARIABLE_MAX)
  109. {
  110. finsh_heap_free(finsh_block_get_data(temp));
  111. }
  112. }
  113. }
  114. /**
  115. * insert a block to list
  116. */
  117. void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header)
  118. {
  119. struct finsh_block_header* node;
  120. if (*list == NULL)
  121. {
  122. *list = header;
  123. return;
  124. }
  125. /* find out insert point */
  126. node = *list;
  127. if (node > header)
  128. {
  129. /* insert node in the header of list */
  130. header->next = node;
  131. *list = header;
  132. return;
  133. }
  134. else
  135. {
  136. for (node = *list; node; node = node->next)
  137. {
  138. if (node->next > header) break;
  139. if (node->next == NULL) break;
  140. }
  141. }
  142. /* insert node */
  143. if (node->next != NULL) header->next = node->next;
  144. node->next = header;
  145. }
  146. /**
  147. * remove block from list
  148. */
  149. void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header)
  150. {
  151. struct finsh_block_header* node;
  152. node = *list;
  153. if (node == header)
  154. {
  155. /* remove list header */
  156. *list = header->next;
  157. header->next = NULL;
  158. return;
  159. }
  160. for (node = *list; node != NULL; node = node->next)
  161. {
  162. if (node->next == header)
  163. {
  164. node->next = header->next;
  165. break;
  166. }
  167. }
  168. }
  169. /**
  170. * split block
  171. */
  172. void finsh_block_split(struct finsh_block_header* header, size_t size)
  173. {
  174. struct finsh_block_header* next;
  175. /*
  176. * split header into two node:
  177. * header->next->...
  178. */
  179. next = BLOCK_HEADER((uint8_t*)header + sizeof(struct finsh_block_header) + size);
  180. next->length = header->length - sizeof(struct finsh_block_header) - size;
  181. header->length = size;
  182. next->next = header->next;
  183. header->next = next;
  184. }
  185. void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header)
  186. {
  187. struct finsh_block_header* prev_node;
  188. struct finsh_block_header* next_node;
  189. next_node = header->next;
  190. if (*list == header) prev_node = NULL;
  191. else
  192. {
  193. /* find out the previous header */
  194. for (prev_node = *list; prev_node; prev_node =prev_node->next)
  195. {
  196. if (prev_node->next == header)
  197. break;
  198. }
  199. }
  200. /* try merge node */
  201. /* merge to previous node */
  202. if (prev_node != NULL &&
  203. ((uint8_t*)prev_node + prev_node->length + sizeof(struct finsh_block_header)
  204. == (uint8_t*)header))
  205. {
  206. /* is it close to next node? */
  207. if ((next_node != NULL) &&
  208. ((uint8_t*)header + header->length + sizeof(struct finsh_block_header)
  209. == (uint8_t*)next_node))
  210. {
  211. /* merge three node */
  212. prev_node->length += header->length + next_node->length +
  213. 2 * sizeof(struct finsh_block_header);
  214. prev_node->next = next_node->next;
  215. }
  216. else
  217. {
  218. prev_node->length += header->length + sizeof(struct finsh_block_header);
  219. prev_node->next = header->next;
  220. }
  221. }
  222. else /* merge to last node */
  223. if ( (next_node != NULL) &&
  224. ((uint8_t*)header + header->length + sizeof(struct finsh_block_header)
  225. == (uint8_t*)next_node))
  226. {
  227. header->length += next_node->length + sizeof(struct finsh_block_header);
  228. header->next = next_node->next;
  229. }
  230. }