memheap.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /*
  2. * File : memheap.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2012, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2012-04-10 Bernard first implementation
  13. * 2012-10-16 Bernard add the mutex lock for heap object.
  14. * 2012-12-29 Bernard memheap can be used as system heap.
  15. * change mutex lock to semaphore lock.
  16. * 2013-04-10 Bernard add rt_memheap_realloc function.
  17. * 2013-05-24 Bernard fix the rt_memheap_realloc issue.
  18. */
  19. #include <rthw.h>
  20. #include <rtthread.h>
  21. #ifdef RT_USING_MEMHEAP
  22. /* dynamic pool magic and mask */
  23. #define RT_MEMHEAP_MAGIC 0x1ea01ea0
  24. #define RT_MEMHEAP_MASK 0xfffffffe
  25. #define RT_MEMHEAP_USED 0x01
  26. #define RT_MEMHEAP_FREED 0x00
  27. #define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED)
  28. #define RT_MEMHEAP_MINIALLOC 12
  29. #define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
  30. #define MEMITEM_SIZE(item) ((rt_uint32_t)item->next - (rt_uint32_t)item - RT_MEMHEAP_SIZE)
  31. /*
  32. * The initialized memory pool will be:
  33. * +-----------------------------------+--------------------------+
  34. * | whole freed memory block | Used Memory Block Tailer |
  35. * +-----------------------------------+--------------------------+
  36. *
  37. * block_list --> whole freed memory block
  38. *
  39. * The length of Used Memory Block Tailer is 0,
  40. * which is prevents block merging across list
  41. */
  42. rt_err_t rt_memheap_init(struct rt_memheap *memheap,
  43. const char *name,
  44. void *start_addr,
  45. rt_uint32_t size)
  46. {
  47. struct rt_memheap_item *item;
  48. RT_ASSERT(memheap != RT_NULL);
  49. /* initialize pool object */
  50. rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
  51. memheap->start_addr = start_addr;
  52. memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  53. memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
  54. memheap->max_used_size = memheap->pool_size - memheap->available_size;
  55. /* initialize the free list header */
  56. item = &(memheap->free_header);
  57. item->magic = RT_MEMHEAP_MAGIC;
  58. item->pool_ptr = memheap;
  59. item->next = RT_NULL;
  60. item->prev = RT_NULL;
  61. item->next_free = item;
  62. item->prev_free = item;
  63. /* set the free list to free list header */
  64. memheap->free_list = item;
  65. /* initialize the first big memory block */
  66. item = (struct rt_memheap_item *)start_addr;
  67. item->magic = RT_MEMHEAP_MAGIC;
  68. item->pool_ptr = memheap;
  69. item->next = RT_NULL;
  70. item->prev = RT_NULL;
  71. item->next_free = item;
  72. item->prev_free = item;
  73. item->next = (struct rt_memheap_item *)
  74. ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
  75. item->prev = item->next;
  76. /* block list header */
  77. memheap->block_list = item;
  78. /* place the big memory block to free list */
  79. item->next_free = memheap->free_list->next_free;
  80. item->prev_free = memheap->free_list;
  81. memheap->free_list->next_free->prev_free = item;
  82. memheap->free_list->next_free = item;
  83. /* move to the end of memory pool to build a small tailer block,
  84. * which prevents block merging
  85. */
  86. item = item->next;
  87. /* it's a used memory block */
  88. item->magic = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
  89. item->pool_ptr = memheap;
  90. item->next = (struct rt_memheap_item *)start_addr;
  91. item->prev = (struct rt_memheap_item *)start_addr;
  92. /* not in free list */
  93. item->next_free = item->prev_free = RT_NULL;
  94. /* initialize semaphore lock */
  95. rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO);
  96. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  97. ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x",
  98. start_addr, size, &(memheap->free_header)));
  99. return RT_EOK;
  100. }
  101. RTM_EXPORT(rt_memheap_init);
  102. rt_err_t rt_memheap_detach(struct rt_memheap *heap)
  103. {
  104. RT_ASSERT(heap);
  105. rt_object_detach(&(heap->lock.parent.parent));
  106. rt_object_detach(&(heap->parent));
  107. /* Return a successful completion. */
  108. return RT_EOK;
  109. }
  110. RTM_EXPORT(rt_memheap_detach);
  111. void *rt_memheap_alloc(struct rt_memheap *heap, rt_uint32_t size)
  112. {
  113. rt_err_t result;
  114. rt_uint32_t free_size;
  115. struct rt_memheap_item *header_ptr;
  116. RT_ASSERT(heap != RT_NULL);
  117. /* align allocated size */
  118. size = RT_ALIGN(size, RT_ALIGN_SIZE);
  119. if (size < RT_MEMHEAP_MINIALLOC)
  120. size = RT_MEMHEAP_MINIALLOC;
  121. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
  122. size, RT_NAME_MAX, heap->parent.name));
  123. if (size < heap->available_size)
  124. {
  125. /* search on free list */
  126. free_size = 0;
  127. /* lock memheap */
  128. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  129. if (result != RT_EOK)
  130. {
  131. rt_set_errno(result);
  132. return RT_NULL;
  133. }
  134. /* get the first free memory block */
  135. header_ptr = heap->free_list->next_free;
  136. while (header_ptr != heap->free_list && free_size < size)
  137. {
  138. /* get current freed memory block size */
  139. free_size = MEMITEM_SIZE(header_ptr);
  140. if (free_size < size)
  141. {
  142. /* move to next free memory block */
  143. header_ptr = header_ptr->next_free;
  144. }
  145. }
  146. /* determine if the memory is available. */
  147. if (free_size >= size)
  148. {
  149. /* a block that satisfies the request has been found. */
  150. /* determine if the block needs to be split. */
  151. if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
  152. {
  153. struct rt_memheap_item *new_ptr;
  154. /* split the block. */
  155. new_ptr = (struct rt_memheap_item *)
  156. (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
  157. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  158. ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]",
  159. header_ptr,
  160. header_ptr->next,
  161. header_ptr->prev,
  162. new_ptr));
  163. /* mark the new block as a memory block and freed. */
  164. new_ptr->magic = RT_MEMHEAP_MAGIC;
  165. /* put the pool pointer into the new block. */
  166. new_ptr->pool_ptr = heap;
  167. /* break down the block list */
  168. new_ptr->prev = header_ptr;
  169. new_ptr->next = header_ptr->next;
  170. header_ptr->next->prev = new_ptr;
  171. header_ptr->next = new_ptr;
  172. /* remove header ptr from free list */
  173. header_ptr->next_free->prev_free = header_ptr->prev_free;
  174. header_ptr->prev_free->next_free = header_ptr->next_free;
  175. header_ptr->next_free = RT_NULL;
  176. header_ptr->prev_free = RT_NULL;
  177. /* insert new_ptr to free list */
  178. new_ptr->next_free = heap->free_list->next_free;
  179. new_ptr->prev_free = heap->free_list;
  180. heap->free_list->next_free->prev_free = new_ptr;
  181. heap->free_list->next_free = new_ptr;
  182. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
  183. new_ptr->next_free,
  184. new_ptr->prev_free));
  185. /* decrement the available byte count. */
  186. heap->available_size = heap->available_size -
  187. size -
  188. RT_MEMHEAP_SIZE;
  189. if (heap->pool_size - heap->available_size > heap->max_used_size)
  190. heap->max_used_size = heap->pool_size - heap->available_size;
  191. }
  192. else
  193. {
  194. /* decrement the entire free size from the available bytes count. */
  195. heap->available_size = heap->available_size - free_size;
  196. if (heap->pool_size - heap->available_size > heap->max_used_size)
  197. heap->max_used_size = heap->pool_size - heap->available_size;
  198. /* remove header_ptr from free list */
  199. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  200. ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
  201. header_ptr,
  202. header_ptr->next_free,
  203. header_ptr->prev_free));
  204. header_ptr->next_free->prev_free = header_ptr->prev_free;
  205. header_ptr->prev_free->next_free = header_ptr->next_free;
  206. header_ptr->next_free = RT_NULL;
  207. header_ptr->prev_free = RT_NULL;
  208. }
  209. /* Mark the allocated block as not available. */
  210. header_ptr->magic |= RT_MEMHEAP_USED;
  211. /* release lock */
  212. rt_sem_release(&(heap->lock));
  213. /* Return a memory address to the caller. */
  214. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  215. ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d",
  216. (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
  217. header_ptr,
  218. size);
  219. return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE));
  220. }
  221. /* release lock */
  222. rt_sem_release(&(heap->lock));
  223. }
  224. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
  225. /* Return the completion status. */
  226. return RT_NULL;
  227. }
  228. RTM_EXPORT(rt_memheap_alloc);
  229. void *rt_memheap_realloc(struct rt_memheap* heap, void* ptr, rt_size_t newsize)
  230. {
  231. rt_err_t result;
  232. rt_size_t oldsize;
  233. struct rt_memheap_item *header_ptr;
  234. struct rt_memheap_item *new_ptr;
  235. if (newsize == 0)
  236. {
  237. rt_memheap_free(ptr);
  238. return RT_NULL;
  239. }
  240. /* align allocated size */
  241. newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
  242. if (newsize < RT_MEMHEAP_MINIALLOC)
  243. newsize = RT_MEMHEAP_MINIALLOC;
  244. if (ptr == RT_NULL)
  245. {
  246. return rt_memheap_alloc(heap, newsize);
  247. }
  248. /* get memory block header and get the size of memory block */
  249. header_ptr = (struct rt_memheap_item*)((rt_uint8_t *)ptr -
  250. RT_MEMHEAP_SIZE);
  251. oldsize = MEMITEM_SIZE(header_ptr);
  252. /* re-allocate memory */
  253. if (newsize > oldsize)
  254. {
  255. void* new_ptr;
  256. /* re-allocate a memory block */
  257. new_ptr = (void*)rt_memheap_alloc(heap, newsize);
  258. if (new_ptr != RT_NULL)
  259. {
  260. rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
  261. rt_memheap_free(ptr);
  262. }
  263. return new_ptr;
  264. }
  265. /* lock memheap */
  266. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  267. if (result != RT_EOK)
  268. {
  269. rt_set_errno(result);
  270. return RT_NULL;
  271. }
  272. /* split the block. */
  273. new_ptr = (struct rt_memheap_item *)
  274. (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
  275. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  276. ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]",
  277. header_ptr,
  278. header_ptr->next,
  279. header_ptr->prev,
  280. new_ptr));
  281. /* mark the new block as a memory block and freed. */
  282. new_ptr->magic = RT_MEMHEAP_MAGIC;
  283. /* put the pool pointer into the new block. */
  284. new_ptr->pool_ptr = heap;
  285. /* break down the block list */
  286. new_ptr->prev = header_ptr;
  287. new_ptr->next = header_ptr->next;
  288. header_ptr->next->prev = new_ptr;
  289. header_ptr->next = new_ptr;
  290. /* determine if the block can be merged with the next neighbor. */
  291. if (!RT_MEMHEAP_IS_USED(new_ptr->next))
  292. {
  293. struct rt_memheap_item *free_ptr;
  294. /* merge block with next neighbor. */
  295. free_ptr = new_ptr->next;
  296. heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
  297. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  298. ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x",
  299. header_ptr, header_ptr->next_free, header_ptr->prev_free));
  300. free_ptr->next->prev = new_ptr;
  301. new_ptr->next = free_ptr->next;
  302. /* remove free ptr from free list */
  303. free_ptr->next_free->prev_free = free_ptr->prev_free;
  304. free_ptr->prev_free->next_free = free_ptr->next_free;
  305. }
  306. /* insert the split block to free list */
  307. new_ptr->next_free = heap->free_list->next_free;
  308. new_ptr->prev_free = heap->free_list;
  309. heap->free_list->next_free->prev_free = new_ptr;
  310. heap->free_list->next_free = new_ptr;
  311. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x",
  312. new_ptr->next_free,
  313. new_ptr->prev_free));
  314. /* increment the available byte count. */
  315. heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
  316. /* release lock */
  317. rt_sem_release(&(heap->lock));
  318. /* return the old memory block */
  319. return ptr;
  320. }
  321. RTM_EXPORT(rt_memheap_realloc);
  322. void rt_memheap_free(void *ptr)
  323. {
  324. rt_err_t result;
  325. struct rt_memheap *heap;
  326. struct rt_memheap_item *header_ptr, *new_ptr;
  327. rt_uint32_t insert_header;
  328. /* set initial status as OK */
  329. insert_header = 1;
  330. new_ptr = RT_NULL;
  331. header_ptr = (struct rt_memheap_item *)((rt_uint8_t *)ptr -
  332. RT_MEMHEAP_SIZE);
  333. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]",
  334. ptr, header_ptr));
  335. /* check magic */
  336. RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
  337. /* get pool ptr */
  338. heap = header_ptr->pool_ptr;
  339. /* lock memheap */
  340. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  341. if (result != RT_EOK)
  342. {
  343. rt_set_errno(result);
  344. return ;
  345. }
  346. /* Mark the memory as available. */
  347. header_ptr->magic &= ~RT_MEMHEAP_USED;
  348. /* Adjust the available number of bytes. */
  349. heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr);
  350. /* Determine if the block can be merged with the previous neighbor. */
  351. if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
  352. {
  353. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x",
  354. header_ptr->prev));
  355. /* adjust the available number of bytes. */
  356. heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
  357. /* yes, merge block with previous neighbor. */
  358. (header_ptr->prev)->next = header_ptr->next;
  359. (header_ptr->next)->prev = header_ptr->prev;
  360. /* move header pointer to previous. */
  361. header_ptr = header_ptr->prev;
  362. /* don't insert header to free list */
  363. insert_header = 0;
  364. }
  365. /* determine if the block can be merged with the next neighbor. */
  366. if (!RT_MEMHEAP_IS_USED(header_ptr->next))
  367. {
  368. /* adjust the available number of bytes. */
  369. heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
  370. /* merge block with next neighbor. */
  371. new_ptr = header_ptr->next;
  372. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  373. ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x",
  374. new_ptr, new_ptr->next_free, new_ptr->prev_free));
  375. new_ptr->next->prev = header_ptr;
  376. header_ptr->next = new_ptr->next;
  377. /* remove new ptr from free list */
  378. new_ptr->next_free->prev_free = new_ptr->prev_free;
  379. new_ptr->prev_free->next_free = new_ptr->next_free;
  380. }
  381. if (insert_header)
  382. {
  383. /* no left merge, insert to free list */
  384. header_ptr->next_free = heap->free_list->next_free;
  385. header_ptr->prev_free = heap->free_list;
  386. heap->free_list->next_free->prev_free = header_ptr;
  387. heap->free_list->next_free = header_ptr;
  388. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  389. ("insert to free list: next_free 0x%08x, prev_free 0x%08x",
  390. header_ptr->next_free, header_ptr->prev_free));
  391. }
  392. /* release lock */
  393. rt_sem_release(&(heap->lock));
  394. }
  395. RTM_EXPORT(rt_memheap_free);
  396. #ifdef RT_USING_MEMHEAP_AS_HEAP
  397. static struct rt_memheap _heap;
  398. void rt_system_heap_init(void *begin_addr, void *end_addr)
  399. {
  400. /* initialize a default heap in the system */
  401. rt_memheap_init(&_heap,
  402. "heap",
  403. begin_addr,
  404. (rt_uint32_t)end_addr - (rt_uint32_t)begin_addr);
  405. }
  406. void *rt_malloc(rt_size_t size)
  407. {
  408. void* ptr;
  409. /* try to allocate in system heap */
  410. ptr = rt_memheap_alloc(&_heap, size);
  411. if (ptr == RT_NULL)
  412. {
  413. struct rt_object *object;
  414. struct rt_list_node *node;
  415. struct rt_memheap *heap;
  416. struct rt_object_information *information;
  417. extern struct rt_object_information rt_object_container[];
  418. /* try to allocate on other memory heap */
  419. information = &rt_object_container[RT_Object_Class_MemHeap];
  420. for (node = information->object_list.next;
  421. node != &(information->object_list);
  422. node = node->next)
  423. {
  424. object = rt_list_entry(node, struct rt_object, list);
  425. heap = (struct rt_memheap *)object;
  426. /* not allocate in the default system heap */
  427. if (heap == &_heap)
  428. continue;
  429. ptr = rt_memheap_alloc(heap, size);
  430. if (ptr != RT_NULL)
  431. break;
  432. }
  433. }
  434. return ptr;
  435. }
  436. RTM_EXPORT(rt_malloc);
  437. void rt_free(void *rmem)
  438. {
  439. rt_memheap_free(rmem);
  440. }
  441. RTM_EXPORT(rt_free);
  442. void *rt_realloc(void *rmem, rt_size_t newsize)
  443. {
  444. void *new_ptr;
  445. struct rt_memheap_item *header_ptr;
  446. if (rmem == RT_NULL) return rt_malloc(newsize);
  447. /* get old memory item */
  448. header_ptr = (struct rt_memheap_item *)((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
  449. new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
  450. if (new_ptr == RT_NULL && newsize != 0)
  451. {
  452. /* allocate memory block from other memheap */
  453. new_ptr = rt_malloc(newsize);
  454. if (new_ptr != RT_NULL && rmem != RT_NULL)
  455. {
  456. rt_size_t oldsize;
  457. /* get the size of old memory block */
  458. oldsize = MEMITEM_SIZE(header_ptr);
  459. if (newsize > oldsize) rt_memcpy(new_ptr, rmem, oldsize);
  460. else rt_memcpy(new_ptr, rmem, newsize);
  461. }
  462. }
  463. return new_ptr;
  464. }
  465. RTM_EXPORT(rt_realloc);
  466. void *rt_calloc(rt_size_t count, rt_size_t size)
  467. {
  468. void *ptr;
  469. rt_size_t total_size;
  470. total_size = count * size;
  471. ptr = rt_malloc(total_size);
  472. if (ptr != RT_NULL)
  473. {
  474. /* clean memory */
  475. rt_memset(ptr, 0, total_size);
  476. }
  477. return ptr;
  478. }
  479. RTM_EXPORT(rt_calloc);
  480. #endif
  481. #endif