xref: /nrf52832-nimble/rt-thread/src/memheap.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2  * Copyright (c) 2006-2018, 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  */
21 
22 #include <rthw.h>
23 #include <rtthread.h>
24 
25 #ifdef RT_USING_MEMHEAP
26 
27 /* dynamic pool magic and mask */
28 #define RT_MEMHEAP_MAGIC        0x1ea01ea0
29 #define RT_MEMHEAP_MASK         0xfffffffe
30 #define RT_MEMHEAP_USED         0x01
31 #define RT_MEMHEAP_FREED        0x00
32 
33 #define RT_MEMHEAP_IS_USED(i)   ((i)->magic & RT_MEMHEAP_USED)
34 #define RT_MEMHEAP_MINIALLOC    12
35 
36 #define RT_MEMHEAP_SIZE         RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
37 #define MEMITEM_SIZE(item)      ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
38 
39 /*
40  * The initialized memory pool will be:
41  * +-----------------------------------+--------------------------+
42  * | whole freed memory block          | Used Memory Block Tailer |
43  * +-----------------------------------+--------------------------+
44  *
45  * block_list --> whole freed memory block
46  *
47  * The length of Used Memory Block Tailer is 0,
48  * which is prevents block merging across list
49  */
rt_memheap_init(struct rt_memheap * memheap,const char * name,void * start_addr,rt_size_t size)50 rt_err_t rt_memheap_init(struct rt_memheap *memheap,
51                          const char        *name,
52                          void              *start_addr,
53                          rt_size_t         size)
54 {
55     struct rt_memheap_item *item;
56 
57     RT_ASSERT(memheap != RT_NULL);
58 
59     /* initialize pool object */
60     rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
61 
62     memheap->start_addr     = start_addr;
63     memheap->pool_size      = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
64     memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
65     memheap->max_used_size  = memheap->pool_size - memheap->available_size;
66 
67     /* initialize the free list header */
68     item            = &(memheap->free_header);
69     item->magic     = RT_MEMHEAP_MAGIC;
70     item->pool_ptr  = memheap;
71     item->next      = RT_NULL;
72     item->prev      = RT_NULL;
73     item->next_free = item;
74     item->prev_free = item;
75 
76     /* set the free list to free list header */
77     memheap->free_list = item;
78 
79     /* initialize the first big memory block */
80     item            = (struct rt_memheap_item *)start_addr;
81     item->magic     = RT_MEMHEAP_MAGIC;
82     item->pool_ptr  = memheap;
83     item->next      = RT_NULL;
84     item->prev      = RT_NULL;
85     item->next_free = item;
86     item->prev_free = item;
87 
88     item->next = (struct rt_memheap_item *)
89                  ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
90     item->prev = item->next;
91 
92     /* block list header */
93     memheap->block_list = item;
94 
95     /* place the big memory block to free list */
96     item->next_free = memheap->free_list->next_free;
97     item->prev_free = memheap->free_list;
98     memheap->free_list->next_free->prev_free = item;
99     memheap->free_list->next_free            = item;
100 
101     /* move to the end of memory pool to build a small tailer block,
102      * which prevents block merging
103      */
104     item = item->next;
105     /* it's a used memory block */
106     item->magic     = RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED;
107     item->pool_ptr  = memheap;
108     item->next      = (struct rt_memheap_item *)start_addr;
109     item->prev      = (struct rt_memheap_item *)start_addr;
110     /* not in free list */
111     item->next_free = item->prev_free = RT_NULL;
112 
113     /* initialize semaphore lock */
114     rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_FIFO);
115 
116     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
117                  ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
118                   start_addr, size, &(memheap->free_header)));
119 
120     return RT_EOK;
121 }
122 RTM_EXPORT(rt_memheap_init);
123 
rt_memheap_detach(struct rt_memheap * heap)124 rt_err_t rt_memheap_detach(struct rt_memheap *heap)
125 {
126     RT_ASSERT(heap);
127     RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
128     RT_ASSERT(rt_object_is_systemobject(&heap->parent));
129 
130     rt_object_detach(&(heap->lock.parent.parent));
131     rt_object_detach(&(heap->parent));
132 
133     /* Return a successful completion. */
134     return RT_EOK;
135 }
136 RTM_EXPORT(rt_memheap_detach);
137 
rt_memheap_alloc(struct rt_memheap * heap,rt_size_t size)138 void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
139 {
140     rt_err_t result;
141     rt_uint32_t free_size;
142     struct rt_memheap_item *header_ptr;
143 
144     RT_ASSERT(heap != RT_NULL);
145     RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
146 
147     /* align allocated size */
148     size = RT_ALIGN(size, RT_ALIGN_SIZE);
149     if (size < RT_MEMHEAP_MINIALLOC)
150         size = RT_MEMHEAP_MINIALLOC;
151 
152     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
153                                     size, RT_NAME_MAX, heap->parent.name));
154 
155     if (size < heap->available_size)
156     {
157         /* search on free list */
158         free_size = 0;
159 
160         /* lock memheap */
161         result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
162         if (result != RT_EOK)
163         {
164             rt_set_errno(result);
165 
166             return RT_NULL;
167         }
168 
169         /* get the first free memory block */
170         header_ptr = heap->free_list->next_free;
171         while (header_ptr != heap->free_list && free_size < size)
172         {
173             /* get current freed memory block size */
174             free_size = MEMITEM_SIZE(header_ptr);
175             if (free_size < size)
176             {
177                 /* move to next free memory block */
178                 header_ptr = header_ptr->next_free;
179             }
180         }
181 
182         /* determine if the memory is available. */
183         if (free_size >= size)
184         {
185             /* a block that satisfies the request has been found. */
186 
187             /* determine if the block needs to be split. */
188             if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
189             {
190                 struct rt_memheap_item *new_ptr;
191 
192                 /* split the block. */
193                 new_ptr = (struct rt_memheap_item *)
194                           (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);
195 
196                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
197                              ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
198                               header_ptr,
199                               header_ptr->next,
200                               header_ptr->prev,
201                               new_ptr));
202 
203                 /* mark the new block as a memory block and freed. */
204                 new_ptr->magic = RT_MEMHEAP_MAGIC;
205 
206                 /* put the pool pointer into the new block. */
207                 new_ptr->pool_ptr = heap;
208 
209                 /* break down the block list */
210                 new_ptr->prev          = header_ptr;
211                 new_ptr->next          = header_ptr->next;
212                 header_ptr->next->prev = new_ptr;
213                 header_ptr->next       = new_ptr;
214 
215                 /* remove header ptr from free list */
216                 header_ptr->next_free->prev_free = header_ptr->prev_free;
217                 header_ptr->prev_free->next_free = header_ptr->next_free;
218                 header_ptr->next_free = RT_NULL;
219                 header_ptr->prev_free = RT_NULL;
220 
221                 /* insert new_ptr to free list */
222                 new_ptr->next_free = heap->free_list->next_free;
223                 new_ptr->prev_free = heap->free_list;
224                 heap->free_list->next_free->prev_free = new_ptr;
225                 heap->free_list->next_free            = new_ptr;
226                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
227                                                 new_ptr->next_free,
228                                                 new_ptr->prev_free));
229 
230                 /* decrement the available byte count.  */
231                 heap->available_size = heap->available_size -
232                                        size -
233                                        RT_MEMHEAP_SIZE;
234                 if (heap->pool_size - heap->available_size > heap->max_used_size)
235                     heap->max_used_size = heap->pool_size - heap->available_size;
236             }
237             else
238             {
239                 /* decrement the entire free size from the available bytes count. */
240                 heap->available_size = heap->available_size - free_size;
241                 if (heap->pool_size - heap->available_size > heap->max_used_size)
242                     heap->max_used_size = heap->pool_size - heap->available_size;
243 
244                 /* remove header_ptr from free list */
245                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
246                              ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
247                               header_ptr,
248                               header_ptr->next_free,
249                               header_ptr->prev_free));
250 
251                 header_ptr->next_free->prev_free = header_ptr->prev_free;
252                 header_ptr->prev_free->next_free = header_ptr->next_free;
253                 header_ptr->next_free = RT_NULL;
254                 header_ptr->prev_free = RT_NULL;
255             }
256 
257             /* Mark the allocated block as not available. */
258             header_ptr->magic |= RT_MEMHEAP_USED;
259 
260             /* release lock */
261             rt_sem_release(&(heap->lock));
262 
263             /* Return a memory address to the caller.  */
264             RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
265                          ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
266                           (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
267                           header_ptr,
268                           size));
269 
270             return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
271         }
272 
273         /* release lock */
274         rt_sem_release(&(heap->lock));
275     }
276 
277     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
278 
279     /* Return the completion status.  */
280     return RT_NULL;
281 }
282 RTM_EXPORT(rt_memheap_alloc);
283 
rt_memheap_realloc(struct rt_memheap * heap,void * ptr,rt_size_t newsize)284 void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize)
285 {
286     rt_err_t result;
287     rt_size_t oldsize;
288     struct rt_memheap_item *header_ptr;
289     struct rt_memheap_item *new_ptr;
290 
291     RT_ASSERT(heap);
292     RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
293 
294     if (newsize == 0)
295     {
296         rt_memheap_free(ptr);
297 
298         return RT_NULL;
299     }
300     /* align allocated size */
301     newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
302     if (newsize < RT_MEMHEAP_MINIALLOC)
303         newsize = RT_MEMHEAP_MINIALLOC;
304 
305     if (ptr == RT_NULL)
306     {
307         return rt_memheap_alloc(heap, newsize);
308     }
309 
310     /* get memory block header and get the size of memory block */
311     header_ptr = (struct rt_memheap_item *)
312                  ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
313     oldsize = MEMITEM_SIZE(header_ptr);
314     /* re-allocate memory */
315     if (newsize > oldsize)
316     {
317         void *new_ptr;
318         struct rt_memheap_item *next_ptr;
319 
320         /* lock memheap */
321         result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
322         if (result != RT_EOK)
323         {
324             rt_set_errno(result);
325             return RT_NULL;
326         }
327 
328         next_ptr = header_ptr->next;
329 
330         /* header_ptr should not be the tail */
331         RT_ASSERT(next_ptr > header_ptr);
332 
333         /* check whether the following free space is enough to expand */
334         if (!RT_MEMHEAP_IS_USED(next_ptr))
335         {
336             rt_int32_t nextsize;
337 
338             nextsize = MEMITEM_SIZE(next_ptr);
339             RT_ASSERT(next_ptr > 0);
340 
341             /* Here is the ASCII art of the situation that we can make use of
342              * the next free node without alloc/memcpy, |*| is the control
343              * block:
344              *
345              *      oldsize           free node
346              * |*|-----------|*|----------------------|*|
347              *         newsize          >= minialloc
348              * |*|----------------|*|-----------------|*|
349              */
350             if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
351             {
352                 /* decrement the entire free size from the available bytes count. */
353                 heap->available_size = heap->available_size - (newsize - oldsize);
354                 if (heap->pool_size - heap->available_size > heap->max_used_size)
355                     heap->max_used_size = heap->pool_size - heap->available_size;
356 
357                 /* remove next_ptr from free list */
358                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
359                              ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
360                               next_ptr,
361                               next_ptr->next_free,
362                               next_ptr->prev_free));
363 
364                 next_ptr->next_free->prev_free = next_ptr->prev_free;
365                 next_ptr->prev_free->next_free = next_ptr->next_free;
366                 next_ptr->next->prev = next_ptr->prev;
367                 next_ptr->prev->next = next_ptr->next;
368 
369                 /* build a new one on the right place */
370                 next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize);
371 
372                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
373                              ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
374                               next_ptr,
375                               next_ptr->next,
376                               next_ptr->prev));
377 
378                 /* mark the new block as a memory block and freed. */
379                 next_ptr->magic = RT_MEMHEAP_MAGIC;
380 
381                 /* put the pool pointer into the new block. */
382                 next_ptr->pool_ptr = heap;
383 
384                 next_ptr->prev          = header_ptr;
385                 next_ptr->next          = header_ptr->next;
386                 header_ptr->next->prev = next_ptr;
387                 header_ptr->next       = next_ptr;
388 
389                 /* insert next_ptr to free list */
390                 next_ptr->next_free = heap->free_list->next_free;
391                 next_ptr->prev_free = heap->free_list;
392                 heap->free_list->next_free->prev_free = next_ptr;
393                 heap->free_list->next_free            = next_ptr;
394                 RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
395                                                 next_ptr->next_free,
396                                                 next_ptr->prev_free));
397 
398                 /* release lock */
399                 rt_sem_release(&(heap->lock));
400 
401                 return ptr;
402             }
403         }
404 
405         /* release lock */
406         rt_sem_release(&(heap->lock));
407 
408         /* re-allocate a memory block */
409         new_ptr = (void *)rt_memheap_alloc(heap, newsize);
410         if (new_ptr != RT_NULL)
411         {
412             rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
413             rt_memheap_free(ptr);
414         }
415 
416         return new_ptr;
417     }
418 
419     /* don't split when there is less than one node space left */
420     if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
421         return ptr;
422 
423     /* lock memheap */
424     result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
425     if (result != RT_EOK)
426     {
427         rt_set_errno(result);
428 
429         return RT_NULL;
430     }
431 
432     /* split the block. */
433     new_ptr = (struct rt_memheap_item *)
434               (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);
435 
436     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
437                  ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
438                   header_ptr,
439                   header_ptr->next,
440                   header_ptr->prev,
441                   new_ptr));
442 
443     /* mark the new block as a memory block and freed. */
444     new_ptr->magic = RT_MEMHEAP_MAGIC;
445     /* put the pool pointer into the new block. */
446     new_ptr->pool_ptr = heap;
447 
448     /* break down the block list */
449     new_ptr->prev          = header_ptr;
450     new_ptr->next          = header_ptr->next;
451     header_ptr->next->prev = new_ptr;
452     header_ptr->next       = new_ptr;
453 
454     /* determine if the block can be merged with the next neighbor. */
455     if (!RT_MEMHEAP_IS_USED(new_ptr->next))
456     {
457         struct rt_memheap_item *free_ptr;
458 
459         /* merge block with next neighbor. */
460         free_ptr = new_ptr->next;
461         heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);
462 
463         RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
464                      ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
465                       header_ptr, header_ptr->next_free, header_ptr->prev_free));
466 
467         free_ptr->next->prev = new_ptr;
468         new_ptr->next   = free_ptr->next;
469 
470         /* remove free ptr from free list */
471         free_ptr->next_free->prev_free = free_ptr->prev_free;
472         free_ptr->prev_free->next_free = free_ptr->next_free;
473     }
474 
475     /* insert the split block to free list */
476     new_ptr->next_free = heap->free_list->next_free;
477     new_ptr->prev_free = heap->free_list;
478     heap->free_list->next_free->prev_free = new_ptr;
479     heap->free_list->next_free            = new_ptr;
480     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
481                                     new_ptr->next_free,
482                                     new_ptr->prev_free));
483 
484     /* increment the available byte count.  */
485     heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
486 
487     /* release lock */
488     rt_sem_release(&(heap->lock));
489 
490     /* return the old memory block */
491     return ptr;
492 }
493 RTM_EXPORT(rt_memheap_realloc);
494 
rt_memheap_free(void * ptr)495 void rt_memheap_free(void *ptr)
496 {
497     rt_err_t result;
498     struct rt_memheap *heap;
499     struct rt_memheap_item *header_ptr, *new_ptr;
500     rt_uint32_t insert_header;
501 
502     /* NULL check */
503     if (ptr == RT_NULL) return;
504 
505     /* set initial status as OK */
506     insert_header = 1;
507     new_ptr       = RT_NULL;
508     header_ptr    = (struct rt_memheap_item *)
509                     ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
510 
511     RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
512                                     ptr, header_ptr));
513 
514     /* check magic */
515     RT_ASSERT((header_ptr->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
516     RT_ASSERT(header_ptr->magic & RT_MEMHEAP_USED);
517     /* check whether this block of memory has been over-written. */
518     RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
519 
520     /* get pool ptr */
521     heap = header_ptr->pool_ptr;
522 
523     RT_ASSERT(heap);
524     RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
525 
526     /* lock memheap */
527     result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
528     if (result != RT_EOK)
529     {
530         rt_set_errno(result);
531 
532         return ;
533     }
534 
535     /* Mark the memory as available. */
536     header_ptr->magic &= ~RT_MEMHEAP_USED;
537     /* Adjust the available number of bytes. */
538     heap->available_size = heap->available_size + MEMITEM_SIZE(header_ptr);
539 
540     /* Determine if the block can be merged with the previous neighbor. */
541     if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
542     {
543         RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
544                                         header_ptr->prev));
545 
546         /* adjust the available number of bytes. */
547         heap->available_size = heap->available_size + RT_MEMHEAP_SIZE;
548 
549         /* yes, merge block with previous neighbor. */
550         (header_ptr->prev)->next = header_ptr->next;
551         (header_ptr->next)->prev = header_ptr->prev;
552 
553         /* move header pointer to previous. */
554         header_ptr = header_ptr->prev;
555         /* don't insert header to free list */
556         insert_header = 0;
557     }
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 = heap->available_size + RT_MEMHEAP_SIZE;
564 
565         /* merge block with next neighbor. */
566         new_ptr = header_ptr->next;
567 
568         RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
569                      ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
570                       new_ptr, new_ptr->next_free, new_ptr->prev_free));
571 
572         new_ptr->next->prev = header_ptr;
573         header_ptr->next    = new_ptr->next;
574 
575         /* remove new ptr from free list */
576         new_ptr->next_free->prev_free = new_ptr->prev_free;
577         new_ptr->prev_free->next_free = new_ptr->next_free;
578     }
579 
580     if (insert_header)
581     {
582         /* no left merge, insert to free list */
583         header_ptr->next_free = heap->free_list->next_free;
584         header_ptr->prev_free = heap->free_list;
585         heap->free_list->next_free->prev_free = header_ptr;
586         heap->free_list->next_free            = header_ptr;
587 
588         RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
589                      ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
590                       header_ptr->next_free, header_ptr->prev_free));
591     }
592 
593     /* release lock */
594     rt_sem_release(&(heap->lock));
595 }
596 RTM_EXPORT(rt_memheap_free);
597 
598 #ifdef RT_USING_MEMHEAP_AS_HEAP
599 static struct rt_memheap _heap;
600 
rt_system_heap_init(void * begin_addr,void * end_addr)601 void rt_system_heap_init(void *begin_addr, void *end_addr)
602 {
603     /* initialize a default heap in the system */
604     rt_memheap_init(&_heap,
605                     "heap",
606                     begin_addr,
607                     (rt_uint32_t)end_addr - (rt_uint32_t)begin_addr);
608 }
609 
rt_malloc(rt_size_t size)610 void *rt_malloc(rt_size_t size)
611 {
612     void *ptr;
613 
614     /* try to allocate in system heap */
615     ptr = rt_memheap_alloc(&_heap, size);
616     if (ptr == RT_NULL)
617     {
618         struct rt_object *object;
619         struct rt_list_node *node;
620         struct rt_memheap *heap;
621         struct rt_object_information *information;
622 
623         /* try to allocate on other memory heap */
624         information = rt_object_get_information(RT_Object_Class_MemHeap);
625         RT_ASSERT(information != RT_NULL);
626         for (node  = information->object_list.next;
627              node != &(information->object_list);
628              node  = node->next)
629         {
630             object = rt_list_entry(node, struct rt_object, list);
631             heap   = (struct rt_memheap *)object;
632 
633             RT_ASSERT(heap);
634             RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
635 
636             /* not allocate in the default system heap */
637             if (heap == &_heap)
638                 continue;
639 
640             ptr = rt_memheap_alloc(heap, size);
641             if (ptr != RT_NULL)
642                 break;
643         }
644     }
645 
646     return ptr;
647 }
648 RTM_EXPORT(rt_malloc);
649 
rt_free(void * rmem)650 void rt_free(void *rmem)
651 {
652     rt_memheap_free(rmem);
653 }
654 RTM_EXPORT(rt_free);
655 
rt_realloc(void * rmem,rt_size_t newsize)656 void *rt_realloc(void *rmem, rt_size_t newsize)
657 {
658     void *new_ptr;
659     struct rt_memheap_item *header_ptr;
660 
661     if (rmem == RT_NULL)
662         return rt_malloc(newsize);
663 
664     if (newsize == 0)
665     {
666         rt_free(rmem);
667         return RT_NULL;
668     }
669 
670     /* get old memory item */
671     header_ptr = (struct rt_memheap_item *)
672                  ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);
673 
674     new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
675     if (new_ptr == RT_NULL && newsize != 0)
676     {
677         /* allocate memory block from other memheap */
678         new_ptr = rt_malloc(newsize);
679         if (new_ptr != RT_NULL && rmem != RT_NULL)
680         {
681             rt_size_t oldsize;
682 
683             /* get the size of old memory block */
684             oldsize = MEMITEM_SIZE(header_ptr);
685             if (newsize > oldsize)
686                 rt_memcpy(new_ptr, rmem, oldsize);
687             else
688                 rt_memcpy(new_ptr, rmem, newsize);
689 
690             rt_free(rmem);
691         }
692     }
693 
694     return new_ptr;
695 }
696 RTM_EXPORT(rt_realloc);
697 
rt_calloc(rt_size_t count,rt_size_t size)698 void *rt_calloc(rt_size_t count, rt_size_t size)
699 {
700     void *ptr;
701     rt_size_t total_size;
702 
703     total_size = count * size;
704     ptr = rt_malloc(total_size);
705     if (ptr != RT_NULL)
706     {
707         /* clean memory */
708         rt_memset(ptr, 0, total_size);
709     }
710 
711     return ptr;
712 }
713 RTM_EXPORT(rt_calloc);
714 
715 #endif
716 
717 #endif
718