memheap.c 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * File : memheap.c
  8. *
  9. * Change Logs:
  10. * Date Author Notes
  11. * 2012-04-10 Bernard first implementation
  12. * 2012-10-16 Bernard add the mutex lock for heap object.
  13. * 2012-12-29 Bernard memheap can be used as system heap.
  14. * change mutex lock to semaphore lock.
  15. * 2013-04-10 Bernard add rt_memheap_realloc function.
  16. * 2013-05-24 Bernard fix the rt_memheap_realloc issue.
  17. * 2013-07-11 Grissiom fix the memory block splitting issue.
  18. * 2013-07-15 Grissiom optimize rt_memheap_realloc
  19. * 2021-06-03 Flybreak Fix the crash problem after opening Oz optimization on ac6.
  20. * 2023-03-01 Bernard Fix the alignment issue for minimal size
  21. */
  22. #include <rthw.h>
  23. #include <rtthread.h>
  24. #ifdef RT_USING_MEMHEAP
  25. /* dynamic pool magic and mask */
  26. #define RT_MEMHEAP_MAGIC 0x1ea01ea0
  27. #define RT_MEMHEAP_MASK 0xFFFFFFFE
  28. #define RT_MEMHEAP_USED 0x01
  29. #define RT_MEMHEAP_FREED 0x00
  30. #define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED)
  31. #define RT_MEMHEAP_MINIALLOC RT_ALIGN(12, RT_ALIGN_SIZE)
  32. #define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
  33. #define MEMITEM_SIZE(item) ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
  34. #define MEMITEM(ptr) (struct rt_memheap_item*)((rt_uint8_t*)ptr - RT_MEMHEAP_SIZE)
  35. static void _remove_next_ptr(volatile struct rt_memheap_item *next_ptr)
  36. {
  37. /* Fix the crash problem after opening Oz optimization on ac6 */
  38. /* Fix IAR compiler warning */
  39. next_ptr->next_free->prev_free = next_ptr->prev_free;
  40. next_ptr->prev_free->next_free = next_ptr->next_free;
  41. next_ptr->next->prev = next_ptr->prev;
  42. next_ptr->prev->next = next_ptr->next;
  43. }
  44. /**
  45. * @brief This function initializes a piece of memory called memheap.
  46. *
  47. * @note The initialized memory pool will be:
  48. * +-----------------------------------+--------------------------+
  49. * | whole freed memory block | Used Memory Block Tailer |
  50. * +-----------------------------------+--------------------------+
  51. *
  52. * block_list --> whole freed memory block
  53. *
  54. * The length of Used Memory Block Tailer is 0,
  55. * which is prevents block merging across list
  56. *
  57. * @param memheap is a pointer of the memheap object.
  58. *
  59. * @param name is the name of the memheap.
  60. *
  61. * @param start_addr is the start address of the memheap.
  62. *
  63. * @param size is the size of the memheap.
  64. *
  65. * @return RT_EOK
  66. */
  67. rt_err_t rt_memheap_init(struct rt_memheap *memheap,
  68. const char *name,
  69. void *start_addr,
  70. rt_size_t size)
  71. {
  72. struct rt_memheap_item *item;
  73. RT_ASSERT(memheap != RT_NULL);
  74. /* initialize pool object */
  75. rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
  76. memheap->start_addr = start_addr;
  77. memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
  78. memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
  79. memheap->max_used_size = memheap->pool_size - memheap->available_size;
  80. /* initialize the free list header */
  81. item = &(memheap->free_header);
  82. item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  83. item->pool_ptr = memheap;
  84. item->next = RT_NULL;
  85. item->prev = RT_NULL;
  86. item->next_free = item;
  87. item->prev_free = item;
  88. /* set the free list to free list header */
  89. memheap->free_list = item;
  90. /* initialize the first big memory block */
  91. item = (struct rt_memheap_item *)start_addr;
  92. item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  93. item->pool_ptr = memheap;
  94. item->next = RT_NULL;
  95. item->prev = RT_NULL;
  96. item->next_free = item;
  97. item->prev_free = item;
  98. #ifdef RT_USING_MEMTRACE
  99. rt_memset(item->owner_thread_name, ' ', sizeof(item->owner_thread_name));
  100. #endif /* RT_USING_MEMTRACE */
  101. item->next = (struct rt_memheap_item *)
  102. ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
  103. item->prev = item->next;
  104. /* block list header */
  105. memheap->block_list = item;
  106. /* place the big memory block to free list */
  107. item->next_free = memheap->free_list->next_free;
  108. item->prev_free = memheap->free_list;
  109. memheap->free_list->next_free->prev_free = item;
  110. memheap->free_list->next_free = item;
  111. /* move to the end of memory pool to build a small tailer block,
  112. * which prevents block merging
  113. */
  114. item = item->next;
  115. /* it's a used memory block */
  116. item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
  117. item->pool_ptr = memheap;
  118. item->next = (struct rt_memheap_item *)start_addr;
  119. item->prev = (struct rt_memheap_item *)start_addr;
  120. /* not in free list */
  121. item->next_free = item->prev_free = RT_NULL;
  122. /* initialize semaphore lock */
  123. rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_PRIO);
  124. memheap->locked = RT_FALSE;
  125. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  126. ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
  127. start_addr, size, &(memheap->free_header)));
  128. return RT_EOK;
  129. }
  130. RTM_EXPORT(rt_memheap_init);
  131. /**
  132. * @brief This function will remove a memheap from the system.
  133. *
  134. * @param heap is a pointer of memheap object.
  135. *
  136. * @return RT_EOK
  137. */
  138. rt_err_t rt_memheap_detach(struct rt_memheap *heap)
  139. {
  140. RT_ASSERT(heap);
  141. RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
  142. RT_ASSERT(rt_object_is_systemobject(&heap->parent));
  143. rt_sem_detach(&heap->lock);
  144. rt_object_detach(&(heap->parent));
  145. /* Return a successful completion. */
  146. return RT_EOK;
  147. }
  148. RTM_EXPORT(rt_memheap_detach);
  149. /**
  150. * @brief Allocate a block of memory with a minimum of 'size' bytes on memheap.
  151. *
  152. * @param heap is a pointer for memheap object.
  153. *
  154. * @param size is the minimum size of the requested block in bytes.
  155. *
  156. * @return the pointer to allocated memory or NULL if no free memory was found.
  157. */
  158. void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
  159. {
  160. rt_err_t result;
  161. rt_size_t free_size;
  162. struct rt_memheap_item *header_ptr;
  163. RT_ASSERT(heap != RT_NULL);
  164. RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
  165. /* align allocated size */
  166. size = RT_ALIGN(size, RT_ALIGN_SIZE);
  167. if (size < RT_MEMHEAP_MINIALLOC)
  168. size = RT_MEMHEAP_MINIALLOC;
  169. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
  170. size, RT_NAME_MAX, heap->parent.name));
  171. if (size < heap->available_size)
  172. {
  173. /* search on free list */
  174. free_size = 0;
  175. /* lock memheap */
  176. if (heap->locked == RT_FALSE)
  177. {
  178. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  179. if (result != RT_EOK)
  180. {
  181. rt_set_errno(result);
  182. return RT_NULL;
  183. }
  184. }
  185. /* get the first free memory block */
  186. header_ptr = heap->free_list->next_free;
  187. while (header_ptr != heap->free_list && free_size < size)
  188. {
  189. /* get current freed memory block size */
  190. free_size = MEMITEM_SIZE(header_ptr);
  191. if (free_size < size)
  192. {
  193. /* move to next free memory block */
  194. header_ptr = header_ptr->next_free;
  195. }
  196. }
  197. /* determine if the memory is available. */
  198. if (free_size >= size)
  199. {
  200. /* a block that satisfies the request has been found. */
  201. /* determine if the block needs to be split. */
  202. if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
  203. {
  204. struct rt_memheap_item *new_ptr;
  205. /* split the block. */
  206. new_ptr = (struct rt_memheap_item *)
  207. (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
  208. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  209. ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
  210. header_ptr,
  211. header_ptr->next,
  212. header_ptr->prev,
  213. new_ptr));
  214. /* mark the new block as a memory block and freed. */
  215. new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  216. /* put the pool pointer into the new block. */
  217. new_ptr->pool_ptr = heap;
  218. #ifdef RT_USING_MEMTRACE
  219. rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
  220. #endif /* RT_USING_MEMTRACE */
  221. /* break down the block list */
  222. new_ptr->prev = header_ptr;
  223. new_ptr->next = header_ptr->next;
  224. header_ptr->next->prev = new_ptr;
  225. header_ptr->next = new_ptr;
  226. /* remove header ptr from free list */
  227. header_ptr->next_free->prev_free = header_ptr->prev_free;
  228. header_ptr->prev_free->next_free = header_ptr->next_free;
  229. header_ptr->next_free = RT_NULL;
  230. header_ptr->prev_free = RT_NULL;
  231. /* insert new_ptr to free list */
  232. new_ptr->next_free = heap->free_list->next_free;
  233. new_ptr->prev_free = heap->free_list;
  234. heap->free_list->next_free->prev_free = new_ptr;
  235. heap->free_list->next_free = new_ptr;
  236. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
  237. new_ptr->next_free,
  238. new_ptr->prev_free));
  239. /* decrement the available byte count. */
  240. heap->available_size = heap->available_size -
  241. size -
  242. RT_MEMHEAP_SIZE;
  243. if (heap->pool_size - heap->available_size > heap->max_used_size)
  244. heap->max_used_size = heap->pool_size - heap->available_size;
  245. }
  246. else
  247. {
  248. /* decrement the entire free size from the available bytes count. */
  249. heap->available_size = heap->available_size - free_size;
  250. if (heap->pool_size - heap->available_size > heap->max_used_size)
  251. heap->max_used_size = heap->pool_size - heap->available_size;
  252. /* remove header_ptr from free list */
  253. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  254. ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
  255. header_ptr,
  256. header_ptr->next_free,
  257. header_ptr->prev_free));
  258. header_ptr->next_free->prev_free = header_ptr->prev_free;
  259. header_ptr->prev_free->next_free = header_ptr->next_free;
  260. header_ptr->next_free = RT_NULL;
  261. header_ptr->prev_free = RT_NULL;
  262. }
  263. /* Mark the allocated block as not available. */
  264. header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
  265. #ifdef RT_USING_MEMTRACE
  266. if (rt_thread_self())
  267. rt_memcpy(header_ptr->owner_thread_name, rt_thread_self()->name, sizeof(header_ptr->owner_thread_name));
  268. else
  269. rt_memcpy(header_ptr->owner_thread_name, "NONE", sizeof(header_ptr->owner_thread_name));
  270. #endif /* RT_USING_MEMTRACE */
  271. if (heap->locked == RT_FALSE)
  272. {
  273. /* release lock */
  274. rt_sem_release(&(heap->lock));
  275. }
  276. /* Return a memory address to the caller. */
  277. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  278. ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
  279. (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
  280. header_ptr,
  281. size));
  282. return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
  283. }
  284. if (heap->locked == RT_FALSE)
  285. {
  286. /* release lock */
  287. rt_sem_release(&(heap->lock));
  288. }
  289. }
  290. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
  291. /* Return the completion status. */
  292. return RT_NULL;
  293. }
  294. RTM_EXPORT(rt_memheap_alloc);
  295. /**
  296. * @brief This function will change the size of previously allocated memory block.
  297. *
  298. * @param heap is a pointer to the memheap object, which will reallocate
  299. * memory from the block
  300. *
  301. * @param ptr is a pointer to start address of memory.
  302. *
  303. * @param newsize is the required new size.
  304. *
  305. * @return the changed memory block address.
  306. */
  307. void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize)
  308. {
  309. rt_err_t result;
  310. rt_size_t oldsize;
  311. struct rt_memheap_item *header_ptr;
  312. struct rt_memheap_item *new_ptr;
  313. RT_ASSERT(heap);
  314. RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
  315. if (newsize == 0)
  316. {
  317. rt_memheap_free(ptr);
  318. return RT_NULL;
  319. }
  320. /* align allocated size */
  321. newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
  322. if (newsize < RT_MEMHEAP_MINIALLOC)
  323. newsize = RT_MEMHEAP_MINIALLOC;
  324. if (ptr == RT_NULL)
  325. {
  326. return rt_memheap_alloc(heap, newsize);
  327. }
  328. /* get memory block header and get the size of memory block */
  329. header_ptr = (struct rt_memheap_item *)
  330. ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
  331. oldsize = MEMITEM_SIZE(header_ptr);
  332. /* re-allocate memory */
  333. if (newsize > oldsize)
  334. {
  335. void *new_ptr;
  336. volatile struct rt_memheap_item *next_ptr;
  337. if (heap->locked == RT_FALSE)
  338. {
  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 RT_NULL;
  345. }
  346. }
  347. next_ptr = header_ptr->next;
  348. /* header_ptr should not be the tail */
  349. RT_ASSERT(next_ptr > header_ptr);
  350. /* check whether the following free space is enough to expand */
  351. if (!RT_MEMHEAP_IS_USED(next_ptr))
  352. {
  353. rt_int32_t nextsize;
  354. nextsize = MEMITEM_SIZE(next_ptr);
  355. RT_ASSERT(next_ptr > 0);
  356. /* Here is the ASCII art of the situation that we can make use of
  357. * the next free node without alloc/memcpy, |*| is the control
  358. * block:
  359. *
  360. * oldsize free node
  361. * |*|-----------|*|----------------------|*|
  362. * newsize >= minialloc
  363. * |*|----------------|*|-----------------|*|
  364. */
  365. if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
  366. {
  367. /* decrement the entire free size from the available bytes count. */
  368. heap->available_size = heap->available_size - (newsize - oldsize);
  369. if (heap->pool_size - heap->available_size > heap->max_used_size)
  370. heap->max_used_size = heap->pool_size - heap->available_size;
  371. /* remove next_ptr from free list */
  372. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  373. ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
  374. next_ptr,
  375. next_ptr->next_free,
  376. next_ptr->prev_free));
  377. _remove_next_ptr(next_ptr);
  378. /* build a new one on the right place */
  379. next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize);
  380. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  381. ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
  382. next_ptr,
  383. next_ptr->next,
  384. next_ptr->prev));
  385. /* mark the new block as a memory block and freed. */
  386. next_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  387. /* put the pool pointer into the new block. */
  388. next_ptr->pool_ptr = heap;
  389. #ifdef RT_USING_MEMTRACE
  390. rt_memset((void *)next_ptr->owner_thread_name, ' ', sizeof(next_ptr->owner_thread_name));
  391. #endif /* RT_USING_MEMTRACE */
  392. next_ptr->prev = header_ptr;
  393. next_ptr->next = header_ptr->next;
  394. header_ptr->next->prev = (struct rt_memheap_item *)next_ptr;
  395. header_ptr->next = (struct rt_memheap_item *)next_ptr;
  396. /* insert next_ptr to free list */
  397. next_ptr->next_free = heap->free_list->next_free;
  398. next_ptr->prev_free = heap->free_list;
  399. heap->free_list->next_free->prev_free = (struct rt_memheap_item *)next_ptr;
  400. heap->free_list->next_free = (struct rt_memheap_item *)next_ptr;
  401. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
  402. next_ptr->next_free,
  403. next_ptr->prev_free));
  404. if (heap->locked == RT_FALSE)
  405. {
  406. /* release lock */
  407. rt_sem_release(&(heap->lock));
  408. }
  409. return ptr;
  410. }
  411. }
  412. if (heap->locked == RT_FALSE)
  413. {
  414. /* release lock */
  415. rt_sem_release(&(heap->lock));
  416. }
  417. /* re-allocate a memory block */
  418. new_ptr = (void *)rt_memheap_alloc(heap, newsize);
  419. if (new_ptr != RT_NULL)
  420. {
  421. rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
  422. rt_memheap_free(ptr);
  423. }
  424. return new_ptr;
  425. }
  426. /* don't split when there is less than one node space left */
  427. if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
  428. return ptr;
  429. if (heap->locked == RT_FALSE)
  430. {
  431. /* lock memheap */
  432. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  433. if (result != RT_EOK)
  434. {
  435. rt_set_errno(result);
  436. return RT_NULL;
  437. }
  438. }
  439. /* split the block. */
  440. new_ptr = (struct rt_memheap_item *)
  441. (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
  442. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  443. ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
  444. header_ptr,
  445. header_ptr->next,
  446. header_ptr->prev,
  447. new_ptr));
  448. /* mark the new block as a memory block and freed. */
  449. new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  450. /* put the pool pointer into the new block. */
  451. new_ptr->pool_ptr = heap;
  452. #ifdef RT_USING_MEMTRACE
  453. rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
  454. #endif /* RT_USING_MEMTRACE */
  455. /* break down the block list */
  456. new_ptr->prev = header_ptr;
  457. new_ptr->next = header_ptr->next;
  458. header_ptr->next->prev = new_ptr;
  459. header_ptr->next = new_ptr;
  460. /* determine if the block can be merged with the next neighbor. */
  461. if (!RT_MEMHEAP_IS_USED(new_ptr->next))
  462. {
  463. struct rt_memheap_item *free_ptr;
  464. /* merge block with next neighbor. */
  465. free_ptr = new_ptr->next;
  466. heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
  467. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  468. ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
  469. header_ptr, header_ptr->next_free, header_ptr->prev_free));
  470. free_ptr->next->prev = new_ptr;
  471. new_ptr->next = free_ptr->next;
  472. /* remove free ptr from free list */
  473. free_ptr->next_free->prev_free = free_ptr->prev_free;
  474. free_ptr->prev_free->next_free = free_ptr->next_free;
  475. }
  476. /* insert the split block to free list */
  477. new_ptr->next_free = heap->free_list->next_free;
  478. new_ptr->prev_free = heap->free_list;
  479. heap->free_list->next_free->prev_free = new_ptr;
  480. heap->free_list->next_free = new_ptr;
  481. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
  482. new_ptr->next_free,
  483. new_ptr->prev_free));
  484. /* increment the available byte count. */
  485. heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
  486. if (heap->locked == RT_FALSE)
  487. {
  488. /* release lock */
  489. rt_sem_release(&(heap->lock));
  490. }
  491. /* return the old memory block */
  492. return ptr;
  493. }
  494. RTM_EXPORT(rt_memheap_realloc);
  495. /**
  496. * @brief This function will release the allocated memory block by
  497. * rt_malloc. The released memory block is taken back to system heap.
  498. *
  499. * @param ptr the address of memory which will be released.
  500. */
  501. void rt_memheap_free(void *ptr)
  502. {
  503. rt_err_t result;
  504. struct rt_memheap *heap;
  505. struct rt_memheap_item *header_ptr, *new_ptr;
  506. rt_bool_t insert_header;
  507. /* NULL check */
  508. if (ptr == RT_NULL) return;
  509. /* set initial status as OK */
  510. insert_header = RT_TRUE;
  511. new_ptr = RT_NULL;
  512. header_ptr = (struct rt_memheap_item *)
  513. ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
  514. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
  515. ptr, header_ptr));
  516. /* check magic */
  517. if (header_ptr->magic != (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED) ||
  518. (header_ptr->next->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)
  519. {
  520. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("bad magic:0x%08x @ memheap\n",
  521. header_ptr->magic));
  522. RT_ASSERT(header_ptr->magic == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED));
  523. /* check whether this block of memory has been over-written. */
  524. RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
  525. }
  526. /* get pool ptr */
  527. heap = header_ptr->pool_ptr;
  528. RT_ASSERT(heap);
  529. RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
  530. if (heap->locked == RT_FALSE)
  531. {
  532. /* lock memheap */
  533. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  534. if (result != RT_EOK)
  535. {
  536. rt_set_errno(result);
  537. return ;
  538. }
  539. }
  540. /* Mark the memory as available. */
  541. header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
  542. /* Adjust the available number of bytes. */
  543. heap->available_size += MEMITEM_SIZE(header_ptr);
  544. /* Determine if the block can be merged with the previous neighbor. */
  545. if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
  546. {
  547. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
  548. header_ptr->prev));
  549. /* adjust the available number of bytes. */
  550. heap->available_size += RT_MEMHEAP_SIZE;
  551. /* yes, merge block with previous neighbor. */
  552. (header_ptr->prev)->next = header_ptr->next;
  553. (header_ptr->next)->prev = header_ptr->prev;
  554. /* move header pointer to previous. */
  555. header_ptr = header_ptr->prev;
  556. /* don't insert header to free list */
  557. insert_header = RT_FALSE;
  558. }
  559. /* determine if the block can be merged with the next neighbor. */
  560. if (!RT_MEMHEAP_IS_USED(header_ptr->next))
  561. {
  562. /* adjust the available number of bytes. */
  563. heap->available_size += RT_MEMHEAP_SIZE;
  564. /* merge block with next neighbor. */
  565. new_ptr = header_ptr->next;
  566. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  567. ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
  568. new_ptr, new_ptr->next_free, new_ptr->prev_free));
  569. new_ptr->next->prev = header_ptr;
  570. header_ptr->next = new_ptr->next;
  571. /* remove new ptr from free list */
  572. new_ptr->next_free->prev_free = new_ptr->prev_free;
  573. new_ptr->prev_free->next_free = new_ptr->next_free;
  574. }
  575. if (insert_header)
  576. {
  577. struct rt_memheap_item *n = heap->free_list->next_free;;
  578. #if defined(RT_MEMHEAP_BEST_MODE)
  579. rt_size_t blk_size = MEMITEM_SIZE(header_ptr);
  580. for (;n != heap->free_list; n = n->next_free)
  581. {
  582. rt_size_t m = MEMITEM_SIZE(n);
  583. if (blk_size <= m)
  584. {
  585. break;
  586. }
  587. }
  588. #endif
  589. /* no left merge, insert to free list */
  590. header_ptr->next_free = n;
  591. header_ptr->prev_free = n->prev_free;
  592. n->prev_free->next_free = header_ptr;
  593. n->prev_free = header_ptr;
  594. RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
  595. ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
  596. header_ptr->next_free, header_ptr->prev_free));
  597. }
  598. #ifdef RT_USING_MEMTRACE
  599. rt_memset(header_ptr->owner_thread_name, ' ', sizeof(header_ptr->owner_thread_name));
  600. #endif /* RT_USING_MEMTRACE */
  601. if (heap->locked == RT_FALSE)
  602. {
  603. /* release lock */
  604. rt_sem_release(&(heap->lock));
  605. }
  606. }
  607. RTM_EXPORT(rt_memheap_free);
  608. /**
  609. * @brief This function will caculate the total memory, the used memory, and
  610. * the max used memory.
  611. *
  612. * @param heap is a pointer to the memheap object, which will reallocate
  613. * memory from the block
  614. *
  615. * @param total is a pointer to get the total size of the memory.
  616. *
  617. * @param used is a pointer to get the size of memory used.
  618. *
  619. * @param max_used is a pointer to get the maximum memory used.
  620. */
  621. void rt_memheap_info(struct rt_memheap *heap,
  622. rt_size_t *total,
  623. rt_size_t *used,
  624. rt_size_t *max_used)
  625. {
  626. rt_err_t result;
  627. if (heap->locked == RT_FALSE)
  628. {
  629. /* lock memheap */
  630. result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
  631. if (result != RT_EOK)
  632. {
  633. rt_set_errno(result);
  634. return;
  635. }
  636. }
  637. if (total != RT_NULL)
  638. *total = heap->pool_size;
  639. if (used != RT_NULL)
  640. *used = heap->pool_size - heap->available_size;
  641. if (max_used != RT_NULL)
  642. *max_used = heap->max_used_size;
  643. if (heap->locked == RT_FALSE)
  644. {
  645. /* release lock */
  646. rt_sem_release(&(heap->lock));
  647. }
  648. }
  649. #ifdef RT_USING_MEMHEAP_AS_HEAP
  650. /*
  651. * rt_malloc port function
  652. */
  653. void *_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
  654. {
  655. void *ptr;
  656. /* try to allocate in system heap */
  657. ptr = rt_memheap_alloc(heap, size);
  658. #ifdef RT_USING_MEMHEAP_AUTO_BINDING
  659. if (ptr == RT_NULL)
  660. {
  661. struct rt_object *object;
  662. struct rt_list_node *node;
  663. struct rt_memheap *_heap;
  664. struct rt_object_information *information;
  665. /* try to allocate on other memory heap */
  666. information = rt_object_get_information(RT_Object_Class_MemHeap);
  667. RT_ASSERT(information != RT_NULL);
  668. for (node = information->object_list.next;
  669. node != &(information->object_list);
  670. node = node->next)
  671. {
  672. object = rt_list_entry(node, struct rt_object, list);
  673. _heap = (struct rt_memheap *)object;
  674. /* not allocate in the default system heap */
  675. if (heap == _heap)
  676. continue;
  677. ptr = rt_memheap_alloc(_heap, size);
  678. if (ptr != RT_NULL)
  679. break;
  680. }
  681. }
  682. #endif /* RT_USING_MEMHEAP_AUTO_BINDING */
  683. return ptr;
  684. }
  685. /*
  686. * rt_free port function
  687. */
  688. void _memheap_free(void *rmem)
  689. {
  690. rt_memheap_free(rmem);
  691. }
  692. /*
  693. * rt_realloc port function
  694. */
  695. void *_memheap_realloc(struct rt_memheap *heap, void *rmem, rt_size_t newsize)
  696. {
  697. void *new_ptr;
  698. struct rt_memheap_item *header_ptr;
  699. if (rmem == RT_NULL)
  700. return _memheap_alloc(heap, newsize);
  701. if (newsize == 0)
  702. {
  703. _memheap_free(rmem);
  704. return RT_NULL;
  705. }
  706. /* get old memory item */
  707. header_ptr = (struct rt_memheap_item *)
  708. ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
  709. new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
  710. if (new_ptr == RT_NULL && newsize != 0)
  711. {
  712. /* allocate memory block from other memheap */
  713. new_ptr = _memheap_alloc(heap, newsize);
  714. if (new_ptr != RT_NULL && rmem != RT_NULL)
  715. {
  716. rt_size_t oldsize;
  717. /* get the size of old memory block */
  718. oldsize = MEMITEM_SIZE(header_ptr);
  719. if (newsize > oldsize)
  720. rt_memcpy(new_ptr, rmem, oldsize);
  721. else
  722. rt_memcpy(new_ptr, rmem, newsize);
  723. _memheap_free(rmem);
  724. }
  725. }
  726. return new_ptr;
  727. }
  728. #endif
  729. #ifdef RT_USING_MEMTRACE
  730. int memheapcheck(int argc, char *argv[])
  731. {
  732. struct rt_object_information *info;
  733. struct rt_list_node *list;
  734. struct rt_memheap *heap;
  735. struct rt_list_node *node;
  736. struct rt_memheap_item *item;
  737. rt_bool_t has_bad = RT_FALSE;
  738. rt_base_t level;
  739. char *name;
  740. name = argc > 1 ? argv[1] : RT_NULL;
  741. level = rt_hw_interrupt_disable();
  742. info = rt_object_get_information(RT_Object_Class_MemHeap);
  743. list = &info->object_list;
  744. for (node = list->next; node != list; node = node->next)
  745. {
  746. heap = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
  747. /* find the specified object */
  748. if (name != RT_NULL && rt_strncmp(name, heap->parent.name, RT_NAME_MAX) != 0)
  749. continue;
  750. /* check memheap */
  751. for (item = heap->block_list; item->next != heap->block_list; item = item->next)
  752. {
  753. /* check magic */
  754. if (!((item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED) ||
  755. (item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)))
  756. {
  757. has_bad = RT_TRUE;
  758. break;
  759. }
  760. /* check pool_ptr */
  761. if (heap != item->pool_ptr)
  762. {
  763. has_bad = RT_TRUE;
  764. break;
  765. }
  766. /* check next and prev */
  767. if (!((rt_ubase_t)item->next <= (rt_ubase_t)((rt_ubase_t)heap->start_addr + heap->pool_size) &&
  768. (rt_ubase_t)item->prev >= (rt_ubase_t)heap->start_addr) &&
  769. (rt_ubase_t)item->next == RT_ALIGN((rt_ubase_t)item->next, RT_ALIGN_SIZE) &&
  770. (rt_ubase_t)item->prev == RT_ALIGN((rt_ubase_t)item->prev, RT_ALIGN_SIZE))
  771. {
  772. has_bad = RT_TRUE;
  773. break;
  774. }
  775. /* check item */
  776. if (item->next == item->next->prev)
  777. {
  778. has_bad = RT_TRUE;
  779. break;
  780. }
  781. }
  782. }
  783. rt_hw_interrupt_enable(level);
  784. if (has_bad)
  785. {
  786. rt_kprintf("Memory block wrong:\n");
  787. rt_kprintf("name: %s\n", heap->parent.name);
  788. rt_kprintf("item: 0x%p\n", item);
  789. }
  790. return 0;
  791. }
  792. MSH_CMD_EXPORT(memheapcheck, check memory for memheap);
  793. int memheaptrace(int argc, char *argv[])
  794. {
  795. struct rt_object_information *info;
  796. struct rt_list_node *list;
  797. struct rt_memheap *mh;
  798. struct rt_list_node *node;
  799. char *name;
  800. name = argc > 1 ? argv[1] : RT_NULL;
  801. info = rt_object_get_information(RT_Object_Class_MemHeap);
  802. list = &info->object_list;
  803. for (node = list->next; node != list; node = node->next)
  804. {
  805. struct rt_memheap_item *header_ptr;
  806. long block_size;
  807. mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
  808. /* find the specified object */
  809. if (name != RT_NULL && rt_strncmp(name, mh->parent.name, RT_NAME_MAX) != 0)
  810. continue;
  811. /* memheap dump */
  812. rt_kprintf("\nmemory heap address:\n");
  813. rt_kprintf("name : %s\n", mh->parent.name);
  814. rt_kprintf("heap_ptr: 0x%p\n", mh->start_addr);
  815. rt_kprintf("free : 0x%08x\n", mh->available_size);
  816. rt_kprintf("max_used: 0x%08x\n", mh->max_used_size);
  817. rt_kprintf("size : 0x%08x\n", mh->pool_size);
  818. rt_kprintf("\n--memory used information --\n");
  819. /* memheap item */
  820. for (header_ptr = mh->block_list;
  821. header_ptr->next != mh->block_list;
  822. header_ptr = header_ptr->next)
  823. {
  824. if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)
  825. {
  826. rt_kprintf("[0x%p - incorrect magic: 0x%08x\n",
  827. header_ptr, header_ptr->magic);
  828. break;
  829. }
  830. /* get current memory block size */
  831. block_size = MEMITEM_SIZE(header_ptr);
  832. if (block_size < 0)
  833. break;
  834. rt_kprintf("[0x%p - ", header_ptr);
  835. if (block_size < 1024)
  836. rt_kprintf("%5d", block_size);
  837. else if (block_size < 1024 * 1024)
  838. rt_kprintf("%4dK", block_size / 1024);
  839. else if (block_size < 1024 * 1024 * 100)
  840. rt_kprintf("%2d.%dM", block_size / (1024 * 1024), (block_size % (1024 * 1024) * 10) / (1024 * 1024));
  841. else
  842. rt_kprintf("%4dM", block_size / (1024 * 1024));
  843. /* dump thread name */
  844. rt_kprintf("] %c%c%c%c\n",
  845. header_ptr->owner_thread_name[0],
  846. header_ptr->owner_thread_name[1],
  847. header_ptr->owner_thread_name[2],
  848. header_ptr->owner_thread_name[3]);
  849. }
  850. }
  851. return 0;
  852. }
  853. #ifdef RT_USING_FINSH
  854. #include <finsh.h>
  855. MSH_CMD_EXPORT(memheaptrace, dump memory trace for memheap);
  856. #endif /* RT_USING_FINSH */
  857. #endif /* RT_USING_MEMTRACE */
  858. #endif /* RT_USING_MEMHEAP */