finsh_heap.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * heap management in finsh shell.
  3. *
  4. * COPYRIGHT (C) 2006 - 2013, RT-Thread Development Team
  5. *
  6. * This file is part of RT-Thread (http://www.rt-thread.org)
  7. * Maintainer: bernard.xiong <bernard.xiong at gmail.com>
  8. *
  9. * All rights reserved.
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program; if not, write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  24. *
  25. * Change Logs:
  26. * Date Author Notes
  27. * 2010-03-22 Bernard first version
  28. */
  29. #include <finsh.h>
  30. #include "finsh_var.h"
  31. ALIGN(RT_ALIGN_SIZE)
  32. u_char finsh_heap[FINSH_HEAP_MAX];
  33. struct finsh_block_header
  34. {
  35. u_long length;
  36. struct finsh_block_header* next;
  37. };
  38. #define BLOCK_HEADER(x) (struct finsh_block_header*)(x)
  39. #define finsh_block_get_header(data) (struct finsh_block_header*)((u_char*)data - sizeof(struct finsh_block_header))
  40. #define finsh_block_get_data(header) (u_char*)((struct finsh_block_header*)header + 1)
  41. #define HEAP_ALIGN_SIZE(size) (((size) + HEAP_ALIGNMENT - 1) & ~(HEAP_ALIGNMENT-1))
  42. static struct finsh_block_header* free_list;
  43. static struct finsh_block_header* allocate_list;
  44. static void finsh_heap_gc(void);
  45. static void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header);
  46. static void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header);
  47. static void finsh_block_split(struct finsh_block_header* header, size_t size);
  48. static void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header);
  49. int finsh_heap_init(void)
  50. {
  51. /* clear heap to zero */
  52. memset(&finsh_heap[0], 0, sizeof(finsh_heap));
  53. /* init free and alloc list */
  54. free_list = BLOCK_HEADER(&finsh_heap[0]);
  55. free_list->length = FINSH_HEAP_MAX - sizeof(struct finsh_block_header);
  56. free_list->next = NULL;
  57. allocate_list = NULL;
  58. return 0;
  59. }
  60. /**
  61. * allocate a block from heap
  62. */
  63. void* finsh_heap_allocate(size_t size)
  64. {
  65. struct finsh_block_header* header;
  66. size = HEAP_ALIGN_SIZE(size);
  67. /* find the first fit block */
  68. for (header = free_list;
  69. ((header != NULL) && (header->length <= size + sizeof(struct finsh_block_header)));
  70. header = header->next) ;
  71. if (header == NULL)
  72. {
  73. finsh_heap_gc();
  74. /* find the first fit block */
  75. for (header = free_list;
  76. ((header != NULL) && (header->length < size + sizeof(struct finsh_block_header)));
  77. header = header->next) ;
  78. /* there is no memory */
  79. if (header == NULL) return NULL;
  80. }
  81. /* split block */
  82. finsh_block_split(header, size);
  83. /* remove from free list */
  84. finsh_block_remove(&free_list, header);
  85. header->next = NULL;
  86. /* insert to allocate list */
  87. finsh_block_insert(&allocate_list, header);
  88. memset(finsh_block_get_data(header), 0, size);
  89. return finsh_block_get_data(header);
  90. }
  91. /**
  92. * release the allocated block
  93. */
  94. void finsh_heap_free(void*ptr)
  95. {
  96. struct finsh_block_header* header;
  97. /* get block header */
  98. header = finsh_block_get_header(ptr);
  99. /* remove from allocate list */
  100. finsh_block_remove(&allocate_list, header);
  101. /* insert to free list */
  102. finsh_block_insert(&free_list, header);
  103. finsh_block_merge(&free_list, header);
  104. }
  105. /**
  106. * garbage collector
  107. */
  108. static void finsh_heap_gc(void)
  109. {
  110. int i;
  111. struct finsh_block_header *header, *temp;
  112. temp = NULL;
  113. /* find the first fit block */
  114. for (header = allocate_list; header != NULL; )
  115. {
  116. for (i = 0; i < FINSH_VARIABLE_MAX; i ++)
  117. {
  118. if (global_variable[i].type != finsh_type_unknown)
  119. {
  120. if (global_variable[i].value.ptr == finsh_block_get_data(header))
  121. break;
  122. }
  123. }
  124. temp = header;
  125. header = header->next;
  126. /* this block is an unused block, release it */
  127. if (i == FINSH_VARIABLE_MAX)
  128. {
  129. finsh_heap_free(finsh_block_get_data(temp));
  130. }
  131. }
  132. }
  133. /**
  134. * insert a block to list
  135. */
  136. void finsh_block_insert(struct finsh_block_header** list, struct finsh_block_header* header)
  137. {
  138. struct finsh_block_header* node;
  139. if (*list == NULL)
  140. {
  141. *list = header;
  142. return;
  143. }
  144. /* find out insert point */
  145. node = *list;
  146. if (node > header)
  147. {
  148. /* insert node in the header of list */
  149. header->next = node;
  150. *list = header;
  151. return;
  152. }
  153. else
  154. {
  155. for (node = *list; node; node = node->next)
  156. {
  157. if (node->next > header) break;
  158. if (node->next == NULL) break;
  159. }
  160. }
  161. /* insert node */
  162. if (node->next != NULL) header->next = node->next;
  163. node->next = header;
  164. }
  165. /**
  166. * remove block from list
  167. */
  168. void finsh_block_remove(struct finsh_block_header** list, struct finsh_block_header* header)
  169. {
  170. struct finsh_block_header* node;
  171. node = *list;
  172. if (node == header)
  173. {
  174. /* remove list header */
  175. *list = header->next;
  176. header->next = NULL;
  177. return;
  178. }
  179. for (node = *list; node != NULL; node = node->next)
  180. {
  181. if (node->next == header)
  182. {
  183. node->next = header->next;
  184. break;
  185. }
  186. }
  187. }
  188. /**
  189. * split block
  190. */
  191. void finsh_block_split(struct finsh_block_header* header, size_t size)
  192. {
  193. struct finsh_block_header* next;
  194. /*
  195. * split header into two node:
  196. * header->next->...
  197. */
  198. next = BLOCK_HEADER((u_char*)header + sizeof(struct finsh_block_header) + size);
  199. next->length = header->length - sizeof(struct finsh_block_header) - size;
  200. header->length = size;
  201. next->next = header->next;
  202. header->next = next;
  203. }
  204. void finsh_block_merge(struct finsh_block_header** list, struct finsh_block_header* header)
  205. {
  206. struct finsh_block_header* prev_node;
  207. struct finsh_block_header* next_node;
  208. next_node = header->next;
  209. if (*list == header) prev_node = NULL;
  210. else
  211. {
  212. /* find out the previous header */
  213. for (prev_node = *list; prev_node; prev_node =prev_node->next)
  214. {
  215. if (prev_node->next == header)
  216. break;
  217. }
  218. }
  219. /* try merge node */
  220. /* merge to previous node */
  221. if (prev_node != NULL &&
  222. ((u_char*)prev_node + prev_node->length + sizeof(struct finsh_block_header)
  223. == (u_char*)header))
  224. {
  225. /* is it close to next node? */
  226. if ((next_node != NULL) &&
  227. ((u_char*)header + header->length + sizeof(struct finsh_block_header)
  228. == (u_char*)next_node))
  229. {
  230. /* merge three node */
  231. prev_node->length += header->length + next_node->length +
  232. 2 * sizeof(struct finsh_block_header);
  233. prev_node->next = next_node->next;
  234. }
  235. else
  236. {
  237. prev_node->length += header->length + sizeof(struct finsh_block_header);
  238. prev_node->next = header->next;
  239. }
  240. }
  241. else /* merge to last node */
  242. if ( (next_node != NULL) &&
  243. ((u_char*)header + header->length + sizeof(struct finsh_block_header)
  244. == (u_char*)next_node))
  245. {
  246. header->length += next_node->length + sizeof(struct finsh_block_header);
  247. header->next = next_node->next;
  248. }
  249. }