RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
memheap.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7/*
8 * File : memheap.c
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 * 2013-07-11 Grissiom fix the memory block splitting issue.
19 * 2013-07-15 Grissiom optimize rt_memheap_realloc
20 * 2021-06-03 Flybreak Fix the crash problem after opening Oz optimization on ac6.
21 * 2023-03-01 Bernard Fix the alignment issue for minimal size
22 */
23
24#include <rthw.h>
25#include <rtthread.h>
26
27#ifdef RT_USING_MEMHEAP
28
29#define DBG_TAG "kernel.memheap"
30#define DBG_LVL DBG_INFO
31#include <rtdbg.h>
32
33/* dynamic pool magic and mask */
34#define RT_MEMHEAP_MAGIC 0x1ea01ea0
35#define RT_MEMHEAP_MASK 0xFFFFFFFE
36#define RT_MEMHEAP_USED 0x01
37#define RT_MEMHEAP_FREED 0x00
38
39#define RT_MEMHEAP_IS_USED(i) ((i)->magic & RT_MEMHEAP_USED)
40#define RT_MEMHEAP_MINIALLOC RT_ALIGN(12, RT_ALIGN_SIZE)
41
42#define RT_MEMHEAP_SIZE RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
43#define MEMITEM_SIZE(item) ((rt_uintptr_t)item->next - (rt_uintptr_t)item - RT_MEMHEAP_SIZE)
44#define MEMITEM(ptr) (struct rt_memheap_item*)((rt_uint8_t*)ptr - RT_MEMHEAP_SIZE)
45
46static void _remove_next_ptr(volatile struct rt_memheap_item *next_ptr)
47{
48 /* Fix the crash problem after opening Oz optimization on ac6 */
49 /* Fix IAR compiler warning */
50 next_ptr->next_free->prev_free = next_ptr->prev_free;
51 next_ptr->prev_free->next_free = next_ptr->next_free;
52 next_ptr->next->prev = next_ptr->prev;
53 next_ptr->prev->next = next_ptr->next;
54}
55
79rt_err_t rt_memheap_init(struct rt_memheap *memheap,
80 const char *name,
81 void *start_addr,
82 rt_size_t size)
83{
84 struct rt_memheap_item *item;
85
86 RT_ASSERT(memheap != RT_NULL);
87
88 /* initialize pool object */
89 rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
90
91 memheap->start_addr = start_addr;
92 memheap->pool_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
93 memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
94 memheap->max_used_size = memheap->pool_size - memheap->available_size;
95
96 /* initialize the free list header */
97 item = &(memheap->free_header);
98 item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
99 item->pool_ptr = memheap;
100 item->next = RT_NULL;
101 item->prev = RT_NULL;
102 item->next_free = item;
103 item->prev_free = item;
104
105 /* set the free list to free list header */
106 memheap->free_list = item;
107
108 /* initialize the first big memory block */
109 item = (struct rt_memheap_item *)start_addr;
110 item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
111 item->pool_ptr = memheap;
112 item->next = RT_NULL;
113 item->prev = RT_NULL;
114 item->next_free = item;
115 item->prev_free = item;
116
117#ifdef RT_USING_MEMTRACE
118 rt_memset(item->owner_thread_name, ' ', sizeof(item->owner_thread_name));
119#endif /* RT_USING_MEMTRACE */
120
121 item->next = (struct rt_memheap_item *)
122 ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
123 item->prev = item->next;
124
125 /* block list header */
126 memheap->block_list = item;
127
128 /* place the big memory block to free list */
129 item->next_free = memheap->free_list->next_free;
130 item->prev_free = memheap->free_list;
131 memheap->free_list->next_free->prev_free = item;
132 memheap->free_list->next_free = item;
133
134 /* move to the end of memory pool to build a small tailer block,
135 * which prevents block merging
136 */
137 item = item->next;
138 /* it's a used memory block */
139 item->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
140 item->pool_ptr = memheap;
141 item->next = (struct rt_memheap_item *)start_addr;
142 item->prev = (struct rt_memheap_item *)start_addr;
143 /* not in free list */
144 item->next_free = item->prev_free = RT_NULL;
145
146 /* initialize semaphore lock */
147 rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_PRIO);
148 memheap->locked = RT_FALSE;
149
150 LOG_D("memory heap: start addr 0x%08x, size %d, free list header 0x%08x",
151 start_addr, size, &(memheap->free_header));
152
153 return RT_EOK;
154}
155RTM_EXPORT(rt_memheap_init);
156
164rt_err_t rt_memheap_detach(struct rt_memheap *heap)
165{
166 RT_ASSERT(heap);
168 RT_ASSERT(rt_object_is_systemobject(&heap->parent));
169
170 rt_sem_detach(&heap->lock);
171 rt_object_detach(&(heap->parent));
172
173 /* Return a successful completion. */
174 return RT_EOK;
175}
176RTM_EXPORT(rt_memheap_detach);
177
187void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
188{
189 rt_err_t result;
190 rt_size_t free_size;
191 struct rt_memheap_item *header_ptr;
192
193 RT_ASSERT(heap != RT_NULL);
195
196 /* align allocated size */
197 size = RT_ALIGN(size, RT_ALIGN_SIZE);
198 if (size < RT_MEMHEAP_MINIALLOC)
199 size = RT_MEMHEAP_MINIALLOC;
200
201 LOG_D("allocate %d on heap:%8.*s",
202 size, RT_NAME_MAX, heap->parent.name);
203
204 if (size < heap->available_size)
205 {
206 /* search on free list */
207 free_size = 0;
208
209 /* lock memheap */
210 if (heap->locked == RT_FALSE)
211 {
212 result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
213 if (result != RT_EOK)
214 {
215 rt_set_errno(result);
216
217 return RT_NULL;
218 }
219 }
220
221 /* get the first free memory block */
222 header_ptr = heap->free_list->next_free;
223 while (header_ptr != heap->free_list && free_size < size)
224 {
225 /* get current freed memory block size */
226 free_size = MEMITEM_SIZE(header_ptr);
227 if (free_size < size)
228 {
229 /* move to next free memory block */
230 header_ptr = header_ptr->next_free;
231 }
232 }
233
234 /* determine if the memory is available. */
235 if (free_size >= size)
236 {
237 /* a block that satisfies the request has been found. */
238
239 /* determine if the block needs to be split. */
240 if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
241 {
242 struct rt_memheap_item *new_ptr;
243
244 /* split the block. */
245 new_ptr = (struct rt_memheap_item *)
246 (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
247
248 LOG_D("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]",
249 header_ptr,
250 header_ptr->next,
251 header_ptr->prev,
252 new_ptr);
253
254 /* mark the new block as a memory block and freed. */
255 new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
256
257 /* put the pool pointer into the new block. */
258 new_ptr->pool_ptr = heap;
259
260#ifdef RT_USING_MEMTRACE
261 rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
262#endif /* RT_USING_MEMTRACE */
263
264 /* break down the block list */
265 new_ptr->prev = header_ptr;
266 new_ptr->next = header_ptr->next;
267 header_ptr->next->prev = new_ptr;
268 header_ptr->next = new_ptr;
269
270 /* remove header ptr from free list */
271 header_ptr->next_free->prev_free = header_ptr->prev_free;
272 header_ptr->prev_free->next_free = header_ptr->next_free;
273 header_ptr->next_free = RT_NULL;
274 header_ptr->prev_free = RT_NULL;
275
276 /* insert new_ptr to free list */
277 new_ptr->next_free = heap->free_list->next_free;
278 new_ptr->prev_free = heap->free_list;
279 heap->free_list->next_free->prev_free = new_ptr;
280 heap->free_list->next_free = new_ptr;
281 LOG_D("new ptr: next_free 0x%08x, prev_free 0x%08x",
282 new_ptr->next_free,
283 new_ptr->prev_free);
284
285 /* decrement the available byte count. */
286 heap->available_size = heap->available_size -
287 size -
288 RT_MEMHEAP_SIZE;
289 if (heap->pool_size - heap->available_size > heap->max_used_size)
290 heap->max_used_size = heap->pool_size - heap->available_size;
291 }
292 else
293 {
294 /* decrement the entire free size from the available bytes count. */
295 heap->available_size = heap->available_size - free_size;
296 if (heap->pool_size - heap->available_size > heap->max_used_size)
297 heap->max_used_size = heap->pool_size - heap->available_size;
298
299 /* remove header_ptr from free list */
300 LOG_D("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
301 header_ptr,
302 header_ptr->next_free,
303 header_ptr->prev_free);
304
305 header_ptr->next_free->prev_free = header_ptr->prev_free;
306 header_ptr->prev_free->next_free = header_ptr->next_free;
307 header_ptr->next_free = RT_NULL;
308 header_ptr->prev_free = RT_NULL;
309 }
310
311 /* Mark the allocated block as not available. */
312 header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
313
314#ifdef RT_USING_MEMTRACE
315 if (rt_thread_self())
316 rt_memcpy(header_ptr->owner_thread_name, rt_thread_self()->parent.name, sizeof(header_ptr->owner_thread_name));
317 else
318 rt_memcpy(header_ptr->owner_thread_name, "NONE", sizeof(header_ptr->owner_thread_name));
319#endif /* RT_USING_MEMTRACE */
320
321 if (heap->locked == RT_FALSE)
322 {
323 /* release lock */
324 rt_sem_release(&(heap->lock));
325 }
326
327 /* Return a memory address to the caller. */
328 LOG_D("alloc mem: memory[0x%08x], heap[0x%08x], size: %d",
329 (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
330 header_ptr,
331 size);
332
333 return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
334 }
335
336 if (heap->locked == RT_FALSE)
337 {
338 /* release lock */
339 rt_sem_release(&(heap->lock));
340 }
341 }
342
343 LOG_D("allocate memory: failed");
344
345 /* Return the completion status. */
346 return RT_NULL;
347}
348RTM_EXPORT(rt_memheap_alloc);
349
362void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize)
363{
364 rt_err_t result;
365 rt_size_t oldsize;
366 struct rt_memheap_item *header_ptr;
367 struct rt_memheap_item *new_ptr;
368
369 RT_ASSERT(heap);
371
372 if (newsize == 0)
373 {
374 rt_memheap_free(ptr);
375
376 return RT_NULL;
377 }
378 /* align allocated size */
379 newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
380 if (newsize < RT_MEMHEAP_MINIALLOC)
381 newsize = RT_MEMHEAP_MINIALLOC;
382
383 if (ptr == RT_NULL)
384 {
385 return rt_memheap_alloc(heap, newsize);
386 }
387
388 /* get memory block header and get the size of memory block */
389 header_ptr = (struct rt_memheap_item *)
390 ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
391 oldsize = MEMITEM_SIZE(header_ptr);
392 /* re-allocate memory */
393 if (newsize > oldsize)
394 {
395 void *new_ptr;
396 volatile struct rt_memheap_item *next_ptr;
397
398 if (heap->locked == RT_FALSE)
399 {
400 /* lock memheap */
401 result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
402 if (result != RT_EOK)
403 {
404 rt_set_errno(result);
405 return RT_NULL;
406 }
407 }
408
409 next_ptr = header_ptr->next;
410
411 /* header_ptr should not be the tail */
412 RT_ASSERT(next_ptr > header_ptr);
413
414 /* check whether the following free space is enough to expand */
415 if (!RT_MEMHEAP_IS_USED(next_ptr))
416 {
417 rt_int32_t nextsize;
418
419 nextsize = MEMITEM_SIZE(next_ptr);
420 RT_ASSERT(next_ptr > 0);
421
422 /* Here is the ASCII art of the situation that we can make use of
423 * the next free node without alloc/memcpy, |*| is the control
424 * block:
425 *
426 * oldsize free node
427 * |*|-----------|*|----------------------|*|
428 * newsize >= minialloc
429 * |*|----------------|*|-----------------|*|
430 */
431 if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
432 {
433 /* decrement the entire free size from the available bytes count. */
434 heap->available_size = heap->available_size - (newsize - oldsize);
435 if (heap->pool_size - heap->available_size > heap->max_used_size)
436 heap->max_used_size = heap->pool_size - heap->available_size;
437
438 /* remove next_ptr from free list */
439 LOG_D("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
440 next_ptr,
441 next_ptr->next_free,
442 next_ptr->prev_free);
443
444 _remove_next_ptr(next_ptr);
445
446 /* build a new one on the right place */
447 next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize);
448
449 LOG_D("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
450 next_ptr,
451 next_ptr->next,
452 next_ptr->prev);
453
454 /* mark the new block as a memory block and freed. */
455 next_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
456
457 /* put the pool pointer into the new block. */
458 next_ptr->pool_ptr = heap;
459
460#ifdef RT_USING_MEMTRACE
461 rt_memset((void *)next_ptr->owner_thread_name, ' ', sizeof(next_ptr->owner_thread_name));
462#endif /* RT_USING_MEMTRACE */
463
464 next_ptr->prev = header_ptr;
465 next_ptr->next = header_ptr->next;
466 header_ptr->next->prev = (struct rt_memheap_item *)next_ptr;
467 header_ptr->next = (struct rt_memheap_item *)next_ptr;
468
469 /* insert next_ptr to free list */
470 next_ptr->next_free = heap->free_list->next_free;
471 next_ptr->prev_free = heap->free_list;
472 heap->free_list->next_free->prev_free = (struct rt_memheap_item *)next_ptr;
473 heap->free_list->next_free = (struct rt_memheap_item *)next_ptr;
474 LOG_D("new ptr: next_free 0x%08x, prev_free 0x%08x",
475 next_ptr->next_free,
476 next_ptr->prev_free);
477 if (heap->locked == RT_FALSE)
478 {
479 /* release lock */
480 rt_sem_release(&(heap->lock));
481 }
482
483 return ptr;
484 }
485 }
486
487 if (heap->locked == RT_FALSE)
488 {
489 /* release lock */
490 rt_sem_release(&(heap->lock));
491 }
492
493 /* re-allocate a memory block */
494 new_ptr = (void *)rt_memheap_alloc(heap, newsize);
495 if (new_ptr != RT_NULL)
496 {
497 rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
498 rt_memheap_free(ptr);
499 }
500
501 return new_ptr;
502 }
503
504 /* don't split when there is less than one node space left */
505 if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
506 return ptr;
507
508 if (heap->locked == RT_FALSE)
509 {
510 /* lock memheap */
511 result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
512 if (result != RT_EOK)
513 {
514 rt_set_errno(result);
515
516 return RT_NULL;
517 }
518 }
519
520 /* split the block. */
521 new_ptr = (struct rt_memheap_item *)
522 (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
523
524 LOG_D("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]",
525 header_ptr,
526 header_ptr->next,
527 header_ptr->prev,
528 new_ptr);
529
530 /* mark the new block as a memory block and freed. */
531 new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
532 /* put the pool pointer into the new block. */
533 new_ptr->pool_ptr = heap;
534
535#ifdef RT_USING_MEMTRACE
536 rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
537#endif /* RT_USING_MEMTRACE */
538
539 /* break down the block list */
540 new_ptr->prev = header_ptr;
541 new_ptr->next = header_ptr->next;
542 header_ptr->next->prev = new_ptr;
543 header_ptr->next = new_ptr;
544
545 /* determine if the block can be merged with the next neighbor. */
546 if (!RT_MEMHEAP_IS_USED(new_ptr->next))
547 {
548 struct rt_memheap_item *free_ptr;
549
550 /* merge block with next neighbor. */
551 free_ptr = new_ptr->next;
552 heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
553
554 LOG_D("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x",
555 header_ptr, header_ptr->next_free, header_ptr->prev_free);
556
557 free_ptr->next->prev = new_ptr;
558 new_ptr->next = free_ptr->next;
559
560 /* remove free ptr from free list */
561 free_ptr->next_free->prev_free = free_ptr->prev_free;
562 free_ptr->prev_free->next_free = free_ptr->next_free;
563 }
564
565 /* insert the split block to free list */
566 new_ptr->next_free = heap->free_list->next_free;
567 new_ptr->prev_free = heap->free_list;
568 heap->free_list->next_free->prev_free = new_ptr;
569 heap->free_list->next_free = new_ptr;
570 LOG_D("new free ptr: next_free 0x%08x, prev_free 0x%08x",
571 new_ptr->next_free,
572 new_ptr->prev_free);
573
574 /* increment the available byte count. */
575 heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
576
577 if (heap->locked == RT_FALSE)
578 {
579 /* release lock */
580 rt_sem_release(&(heap->lock));
581 }
582
583 /* return the old memory block */
584 return ptr;
585}
586RTM_EXPORT(rt_memheap_realloc);
587
594void rt_memheap_free(void *ptr)
595{
596 rt_err_t result;
597 struct rt_memheap *heap;
598 struct rt_memheap_item *header_ptr, *new_ptr;
599 rt_bool_t insert_header;
600
601 /* NULL check */
602 if (ptr == RT_NULL) return;
603
604 /* set initial status as OK */
605 insert_header = RT_TRUE;
606 new_ptr = RT_NULL;
607 header_ptr = (struct rt_memheap_item *)
608 ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
609
610 LOG_D("free memory: memory[0x%08x], block[0x%08x]",
611 ptr, header_ptr);
612
613 /* check magic */
614 if (header_ptr->magic != (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED) ||
615 (header_ptr->next->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)
616 {
617 LOG_D("bad magic:0x%08x @ memheap",
618 header_ptr->magic);
619 RT_ASSERT(header_ptr->magic == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED));
620 /* check whether this block of memory has been over-written. */
621 RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
622 }
623
624 /* get pool ptr */
625 heap = header_ptr->pool_ptr;
626
627 RT_ASSERT(heap);
629
630 if (heap->locked == RT_FALSE)
631 {
632 /* lock memheap */
633 result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
634 if (result != RT_EOK)
635 {
636 rt_set_errno(result);
637
638 return ;
639 }
640 }
641
642 /* Mark the memory as available. */
643 header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
644 /* Adjust the available number of bytes. */
645 heap->available_size += MEMITEM_SIZE(header_ptr);
646
647 /* Determine if the block can be merged with the previous neighbor. */
648 if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
649 {
650 LOG_D("merge: left node 0x%08x",
651 header_ptr->prev);
652
653 /* adjust the available number of bytes. */
654 heap->available_size += RT_MEMHEAP_SIZE;
655
656 /* yes, merge block with previous neighbor. */
657 (header_ptr->prev)->next = header_ptr->next;
658 (header_ptr->next)->prev = header_ptr->prev;
659
660 /* move header pointer to previous. */
661 header_ptr = header_ptr->prev;
662 /* don't insert header to free list */
663 insert_header = RT_FALSE;
664 }
665
666 /* determine if the block can be merged with the next neighbor. */
667 if (!RT_MEMHEAP_IS_USED(header_ptr->next))
668 {
669 /* adjust the available number of bytes. */
670 heap->available_size += RT_MEMHEAP_SIZE;
671
672 /* merge block with next neighbor. */
673 new_ptr = header_ptr->next;
674
675 LOG_D("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x",
676 new_ptr, new_ptr->next_free, new_ptr->prev_free);
677
678 new_ptr->next->prev = header_ptr;
679 header_ptr->next = new_ptr->next;
680
681 /* remove new ptr from free list */
682 new_ptr->next_free->prev_free = new_ptr->prev_free;
683 new_ptr->prev_free->next_free = new_ptr->next_free;
684 }
685
686 if (insert_header)
687 {
688 struct rt_memheap_item *n = heap->free_list->next_free;;
689#if defined(RT_MEMHEAP_BEST_MODE)
690 rt_size_t blk_size = MEMITEM_SIZE(header_ptr);
691 for (;n != heap->free_list; n = n->next_free)
692 {
693 rt_size_t m = MEMITEM_SIZE(n);
694 if (blk_size <= m)
695 {
696 break;
697 }
698 }
699#endif
700 /* no left merge, insert to free list */
701 header_ptr->next_free = n;
702 header_ptr->prev_free = n->prev_free;
703 n->prev_free->next_free = header_ptr;
704 n->prev_free = header_ptr;
705
706 LOG_D("insert to free list: next_free 0x%08x, prev_free 0x%08x",
707 header_ptr->next_free, header_ptr->prev_free);
708 }
709
710#ifdef RT_USING_MEMTRACE
711 rt_memset(header_ptr->owner_thread_name, ' ', sizeof(header_ptr->owner_thread_name));
712#endif /* RT_USING_MEMTRACE */
713
714 if (heap->locked == RT_FALSE)
715 {
716 /* release lock */
717 rt_sem_release(&(heap->lock));
718 }
719}
720RTM_EXPORT(rt_memheap_free);
721
735void rt_memheap_info(struct rt_memheap *heap,
736 rt_size_t *total,
737 rt_size_t *used,
738 rt_size_t *max_used)
739{
740 rt_err_t result;
741
742 if (heap->locked == RT_FALSE)
743 {
744 /* lock memheap */
745 result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
746 if (result != RT_EOK)
747 {
748 rt_set_errno(result);
749 return;
750 }
751 }
752
753 if (total != RT_NULL)
754 *total = heap->pool_size;
755
756 if (used != RT_NULL)
757 *used = heap->pool_size - heap->available_size;
758
759 if (max_used != RT_NULL)
760 *max_used = heap->max_used_size;
761
762 if (heap->locked == RT_FALSE)
763 {
764 /* release lock */
765 rt_sem_release(&(heap->lock));
766 }
767}
768
769#ifdef RT_USING_MEMHEAP_AS_HEAP
770/*
771 * rt_malloc port function
772*/
773void *_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
774{
775 void *ptr;
776
777 /* try to allocate in system heap */
778 ptr = rt_memheap_alloc(heap, size);
779#ifdef RT_USING_MEMHEAP_AUTO_BINDING
780 if (ptr == RT_NULL)
781 {
782 struct rt_object *object;
783 struct rt_list_node *node;
784 struct rt_memheap *_heap;
785 struct rt_object_information *information;
786
787 /* try to allocate on other memory heap */
789 RT_ASSERT(information != RT_NULL);
790 for (node = information->object_list.next;
791 node != &(information->object_list);
792 node = node->next)
793 {
794 object = rt_list_entry(node, struct rt_object, list);
795 _heap = (struct rt_memheap *)object;
796
797 /* not allocate in the default system heap */
798 if (heap == _heap)
799 continue;
800
801 ptr = rt_memheap_alloc(_heap, size);
802 if (ptr != RT_NULL)
803 break;
804 }
805 }
806#endif /* RT_USING_MEMHEAP_AUTO_BINDING */
807 return ptr;
808}
809
810/*
811 * rt_free port function
812*/
813void _memheap_free(void *rmem)
814{
815 rt_memheap_free(rmem);
816}
817
818/*
819 * rt_realloc port function
820*/
821void *_memheap_realloc(struct rt_memheap *heap, void *rmem, rt_size_t newsize)
822{
823 void *new_ptr;
824 struct rt_memheap_item *header_ptr;
825
826 if (rmem == RT_NULL)
827 return _memheap_alloc(heap, newsize);
828
829 if (newsize == 0)
830 {
831 _memheap_free(rmem);
832 return RT_NULL;
833 }
834
835 /* get old memory item */
836 header_ptr = (struct rt_memheap_item *)
837 ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
838
839 new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
840 if (new_ptr == RT_NULL && newsize != 0)
841 {
842 /* allocate memory block from other memheap */
843 new_ptr = _memheap_alloc(heap, newsize);
844 if (new_ptr != RT_NULL && rmem != RT_NULL)
845 {
846 rt_size_t oldsize;
847
848 /* get the size of old memory block */
849 oldsize = MEMITEM_SIZE(header_ptr);
850 if (newsize > oldsize)
851 rt_memcpy(new_ptr, rmem, oldsize);
852 else
853 rt_memcpy(new_ptr, rmem, newsize);
854
855 _memheap_free(rmem);
856 }
857 }
858
859 return new_ptr;
860}
861#endif
862
863#ifdef RT_USING_MEMTRACE
864static int memheapcheck(int argc, char *argv[])
865{
866 struct rt_object_information *info;
867 struct rt_list_node *list;
868 struct rt_memheap *heap;
869 struct rt_list_node *node;
870 struct rt_memheap_item *item;
871 rt_bool_t has_bad = RT_FALSE;
872 rt_base_t level;
873 char *name;
874
875 name = argc > 1 ? argv[1] : RT_NULL;
876 level = rt_hw_interrupt_disable();
878 list = &info->object_list;
879 for (node = list->next; node != list; node = node->next)
880 {
881 heap = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
882 /* find the specified object */
883 if (name != RT_NULL && rt_strncmp(name, heap->parent.name, RT_NAME_MAX) != 0)
884 continue;
885 /* check memheap */
886 for (item = heap->block_list; item->next != heap->block_list; item = item->next)
887 {
888 /* check magic */
889 if (!((item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED) ||
890 (item->magic & (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)) == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED)))
891 {
892 has_bad = RT_TRUE;
893 break;
894 }
895 /* check pool_ptr */
896 if (heap != item->pool_ptr)
897 {
898 has_bad = RT_TRUE;
899 break;
900 }
901 /* check next and prev */
902 if (!((rt_uintptr_t)item->next <= (rt_uintptr_t)((rt_uintptr_t)heap->start_addr + heap->pool_size) &&
903 (rt_uintptr_t)item->prev >= (rt_uintptr_t)heap->start_addr) &&
904 (rt_uintptr_t)item->next == RT_ALIGN((rt_uintptr_t)item->next, RT_ALIGN_SIZE) &&
905 (rt_uintptr_t)item->prev == RT_ALIGN((rt_uintptr_t)item->prev, RT_ALIGN_SIZE))
906 {
907 has_bad = RT_TRUE;
908 break;
909 }
910 /* check item */
911 if (item->next == item->next->prev)
912 {
913 has_bad = RT_TRUE;
914 break;
915 }
916 }
917 }
919 if (has_bad)
920 {
921 rt_kprintf("Memory block wrong:\n");
922 rt_kprintf("name: %s\n", heap->parent.name);
923 rt_kprintf("item: 0x%p\n", item);
924 }
925 return 0;
926}
927MSH_CMD_EXPORT(memheapcheck, check memory for memheap);
928
929static int memheaptrace(int argc, char *argv[])
930{
931 struct rt_object_information *info;
932 struct rt_list_node *list;
933 struct rt_memheap *mh;
934 struct rt_list_node *node;
935 char *name;
936
937 name = argc > 1 ? argv[1] : RT_NULL;
939 list = &info->object_list;
940 for (node = list->next; node != list; node = node->next)
941 {
942 struct rt_memheap_item *header_ptr;
943 long block_size;
944
945 mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
946 /* find the specified object */
947 if (name != RT_NULL && rt_strncmp(name, mh->parent.name, RT_NAME_MAX) != 0)
948 continue;
949 /* memheap dump */
950 rt_kprintf("\nmemory heap address:\n");
951 rt_kprintf("name : %s\n", mh->parent.name);
952 rt_kprintf("heap_ptr: 0x%p\n", mh->start_addr);
953 rt_kprintf("free : 0x%08x\n", mh->available_size);
954 rt_kprintf("max_used: 0x%08x\n", mh->max_used_size);
955 rt_kprintf("size : 0x%08x\n", mh->pool_size);
956 rt_kprintf("\n--memory used information --\n");
957 /* memheap item */
958 for (header_ptr = mh->block_list;
959 header_ptr->next != mh->block_list;
960 header_ptr = header_ptr->next)
961 {
962 if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)
963 {
964 rt_kprintf("[0x%p - incorrect magic: 0x%08x\n",
965 header_ptr, header_ptr->magic);
966 break;
967 }
968 /* get current memory block size */
969 block_size = MEMITEM_SIZE(header_ptr);
970 if (block_size < 0)
971 break;
972
973 rt_kprintf("[0x%p - ", header_ptr);
974 if (block_size < 1024)
975 rt_kprintf("%5d", block_size);
976 else if (block_size < 1024 * 1024)
977 rt_kprintf("%4dK", block_size / 1024);
978 else if (block_size < 1024 * 1024 * 100)
979 rt_kprintf("%2d.%dM", block_size / (1024 * 1024), (block_size % (1024 * 1024) * 10) / (1024 * 1024));
980 else
981 rt_kprintf("%4dM", block_size / (1024 * 1024));
982 /* dump thread name */
983 rt_kprintf("] %c%c%c%c\n",
984 header_ptr->owner_thread_name[0],
985 header_ptr->owner_thread_name[1],
986 header_ptr->owner_thread_name[2],
987 header_ptr->owner_thread_name[3]);
988 }
989 }
990 return 0;
991}
992
993#ifdef RT_USING_FINSH
994#include <finsh.h>
995MSH_CMD_EXPORT(memheaptrace, dump memory trace for memheap);
996#endif /* RT_USING_FINSH */
997#endif /* RT_USING_MEMTRACE */
998#endif /* RT_USING_MEMHEAP */
#define RT_ALIGN(size, align)
#define RT_ALIGN_DOWN(size, align)
#define RT_IPC_FLAG_PRIO
#define RT_WAITING_FOREVER
void rt_object_init(struct rt_object *object, enum rt_object_class_type type, const char *name)
This function will initialize an object and add it to object system management.
rt_bool_t rt_object_is_systemobject(rt_object_t object)
This function will judge the object is system object or not.
struct rt_object_information * rt_object_get_information(enum rt_object_class_type type)
This function will return the specified type of object information.
rt_uint8_t rt_object_get_type(rt_object_t object)
This function will return the type of object without RT_Object_Class_Static flag.
void rt_object_detach(rt_object_t object)
This function will detach a static object from object system, and the memory of static object is not ...
@ RT_Object_Class_MemHeap
#define rt_kprintf(...)
#define rt_list_entry(node, type, member)
get the struct for this entry
#define RT_ASSERT(EX)
rt_thread_t rt_thread_self(void)
This function will return self thread object.
#define MSH_CMD_EXPORT(...)
rt_err_t rt_sem_init(rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag)
This function will initialize a static semaphore object.
定义 ipc.c:376
rt_err_t rt_sem_detach(rt_sem_t sem)
This function will detach a static semaphore object.
定义 ipc.c:413
rt_err_t rt_sem_take(rt_sem_t sem, rt_int32_t time)
定义 ipc.c:644
rt_err_t rt_sem_release(rt_sem_t sem)
This function will release a semaphore. If there is thread suspended on the semaphore,...
定义 ipc.c:695
#define LOG_D(...)
void rt_hw_interrupt_enable(rt_base_t level)
rt_base_t rt_hw_interrupt_disable(void)
#define RTM_EXPORT(symbol)
定义 rtm.h:33
rt_int32_t rt_base_t
rt_base_t rt_uintptr_t
int rt_bool_t
rt_base_t rt_err_t
unsigned char rt_uint8_t
#define RT_TRUE
rt_ubase_t rt_size_t
#define RT_FALSE
#define RT_NULL
signed int rt_int32_t
struct rt_list_node * next