xref: /nrf52832-nimble/rt-thread/src/mem.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2008-7-12      Bernard      the first version
9*10465441SEvalZero  * 2010-06-09     Bernard      fix the end stub of heap
10*10465441SEvalZero  *                             fix memory check in rt_realloc function
11*10465441SEvalZero  * 2010-07-13     Bernard      fix RT_ALIGN issue found by kuronca
12*10465441SEvalZero  * 2010-10-14     Bernard      fix rt_realloc issue when realloc a NULL pointer.
13*10465441SEvalZero  * 2017-07-14     armink       fix rt_realloc issue when new size is 0
14*10465441SEvalZero  * 2018-10-02     Bernard      Add 64bit support
15*10465441SEvalZero  */
16*10465441SEvalZero 
17*10465441SEvalZero /*
18*10465441SEvalZero  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
19*10465441SEvalZero  * All rights reserved.
20*10465441SEvalZero  *
21*10465441SEvalZero  * Redistribution and use in source and binary forms, with or without modification,
22*10465441SEvalZero  * are permitted provided that the following conditions are met:
23*10465441SEvalZero  *
24*10465441SEvalZero  * 1. Redistributions of source code must retain the above copyright notice,
25*10465441SEvalZero  *    this list of conditions and the following disclaimer.
26*10465441SEvalZero  * 2. Redistributions in binary form must reproduce the above copyright notice,
27*10465441SEvalZero  *    this list of conditions and the following disclaimer in the documentation
28*10465441SEvalZero  *    and/or other materials provided with the distribution.
29*10465441SEvalZero  * 3. The name of the author may not be used to endorse or promote products
30*10465441SEvalZero  *    derived from this software without specific prior written permission.
31*10465441SEvalZero  *
32*10465441SEvalZero  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
33*10465441SEvalZero  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
34*10465441SEvalZero  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
35*10465441SEvalZero  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
36*10465441SEvalZero  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
37*10465441SEvalZero  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
38*10465441SEvalZero  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
39*10465441SEvalZero  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40*10465441SEvalZero  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41*10465441SEvalZero  * OF SUCH DAMAGE.
42*10465441SEvalZero  *
43*10465441SEvalZero  * This file is part of the lwIP TCP/IP stack.
44*10465441SEvalZero  *
45*10465441SEvalZero  * Author: Adam Dunkels <[email protected]>
46*10465441SEvalZero  *         Simon Goldschmidt
47*10465441SEvalZero  *
48*10465441SEvalZero  */
49*10465441SEvalZero 
50*10465441SEvalZero #include <rthw.h>
51*10465441SEvalZero #include <rtthread.h>
52*10465441SEvalZero 
53*10465441SEvalZero #ifndef RT_USING_MEMHEAP_AS_HEAP
54*10465441SEvalZero 
55*10465441SEvalZero /* #define RT_MEM_DEBUG */
56*10465441SEvalZero #define RT_MEM_STATS
57*10465441SEvalZero 
58*10465441SEvalZero #if defined (RT_USING_HEAP) && defined (RT_USING_SMALL_MEM)
59*10465441SEvalZero #ifdef RT_USING_HOOK
60*10465441SEvalZero static void (*rt_malloc_hook)(void *ptr, rt_size_t size);
61*10465441SEvalZero static void (*rt_free_hook)(void *ptr);
62*10465441SEvalZero 
63*10465441SEvalZero /**
64*10465441SEvalZero  * @addtogroup Hook
65*10465441SEvalZero  */
66*10465441SEvalZero 
67*10465441SEvalZero /**@{*/
68*10465441SEvalZero 
69*10465441SEvalZero /**
70*10465441SEvalZero  * This function will set a hook function, which will be invoked when a memory
71*10465441SEvalZero  * block is allocated from heap memory.
72*10465441SEvalZero  *
73*10465441SEvalZero  * @param hook the hook function
74*10465441SEvalZero  */
rt_malloc_sethook(void (* hook)(void * ptr,rt_size_t size))75*10465441SEvalZero void rt_malloc_sethook(void (*hook)(void *ptr, rt_size_t size))
76*10465441SEvalZero {
77*10465441SEvalZero     rt_malloc_hook = hook;
78*10465441SEvalZero }
79*10465441SEvalZero 
80*10465441SEvalZero /**
81*10465441SEvalZero  * This function will set a hook function, which will be invoked when a memory
82*10465441SEvalZero  * block is released to heap memory.
83*10465441SEvalZero  *
84*10465441SEvalZero  * @param hook the hook function
85*10465441SEvalZero  */
rt_free_sethook(void (* hook)(void * ptr))86*10465441SEvalZero void rt_free_sethook(void (*hook)(void *ptr))
87*10465441SEvalZero {
88*10465441SEvalZero     rt_free_hook = hook;
89*10465441SEvalZero }
90*10465441SEvalZero 
91*10465441SEvalZero /**@}*/
92*10465441SEvalZero 
93*10465441SEvalZero #endif
94*10465441SEvalZero 
95*10465441SEvalZero #define HEAP_MAGIC 0x1ea0
96*10465441SEvalZero struct heap_mem
97*10465441SEvalZero {
98*10465441SEvalZero     /* magic and used flag */
99*10465441SEvalZero     rt_uint16_t magic;
100*10465441SEvalZero     rt_uint16_t used;
101*10465441SEvalZero #ifdef ARCH_CPU_64BIT
102*10465441SEvalZero     rt_uint32_t resv;
103*10465441SEvalZero #endif
104*10465441SEvalZero 
105*10465441SEvalZero     rt_size_t next, prev;
106*10465441SEvalZero 
107*10465441SEvalZero #ifdef RT_USING_MEMTRACE
108*10465441SEvalZero #ifdef ARCH_CPU_64BIT
109*10465441SEvalZero     rt_uint8_t thread[8];
110*10465441SEvalZero #else
111*10465441SEvalZero     rt_uint8_t thread[4];   /* thread name */
112*10465441SEvalZero #endif
113*10465441SEvalZero #endif
114*10465441SEvalZero };
115*10465441SEvalZero 
116*10465441SEvalZero /** pointer to the heap: for alignment, heap_ptr is now a pointer instead of an array */
117*10465441SEvalZero static rt_uint8_t *heap_ptr;
118*10465441SEvalZero 
119*10465441SEvalZero /** the last entry, always unused! */
120*10465441SEvalZero static struct heap_mem *heap_end;
121*10465441SEvalZero 
122*10465441SEvalZero #ifdef ARCH_CPU_64BIT
123*10465441SEvalZero #define MIN_SIZE 24
124*10465441SEvalZero #else
125*10465441SEvalZero #define MIN_SIZE 12
126*10465441SEvalZero #endif
127*10465441SEvalZero 
128*10465441SEvalZero #define MIN_SIZE_ALIGNED     RT_ALIGN(MIN_SIZE, RT_ALIGN_SIZE)
129*10465441SEvalZero #define SIZEOF_STRUCT_MEM    RT_ALIGN(sizeof(struct heap_mem), RT_ALIGN_SIZE)
130*10465441SEvalZero 
131*10465441SEvalZero static struct heap_mem *lfree;   /* pointer to the lowest free block */
132*10465441SEvalZero 
133*10465441SEvalZero static struct rt_semaphore heap_sem;
134*10465441SEvalZero static rt_size_t mem_size_aligned;
135*10465441SEvalZero 
136*10465441SEvalZero #ifdef RT_MEM_STATS
137*10465441SEvalZero static rt_size_t used_mem, max_mem;
138*10465441SEvalZero #endif
139*10465441SEvalZero #ifdef RT_USING_MEMTRACE
rt_mem_setname(struct heap_mem * mem,const char * name)140*10465441SEvalZero rt_inline void rt_mem_setname(struct heap_mem *mem, const char *name)
141*10465441SEvalZero {
142*10465441SEvalZero     int index;
143*10465441SEvalZero     for (index = 0; index < sizeof(mem->thread); index ++)
144*10465441SEvalZero     {
145*10465441SEvalZero         if (name[index] == '\0') break;
146*10465441SEvalZero         mem->thread[index] = name[index];
147*10465441SEvalZero     }
148*10465441SEvalZero 
149*10465441SEvalZero     for (; index < sizeof(mem->thread); index ++)
150*10465441SEvalZero     {
151*10465441SEvalZero         mem->thread[index] = ' ';
152*10465441SEvalZero     }
153*10465441SEvalZero }
154*10465441SEvalZero #endif
155*10465441SEvalZero 
plug_holes(struct heap_mem * mem)156*10465441SEvalZero static void plug_holes(struct heap_mem *mem)
157*10465441SEvalZero {
158*10465441SEvalZero     struct heap_mem *nmem;
159*10465441SEvalZero     struct heap_mem *pmem;
160*10465441SEvalZero 
161*10465441SEvalZero     RT_ASSERT((rt_uint8_t *)mem >= heap_ptr);
162*10465441SEvalZero     RT_ASSERT((rt_uint8_t *)mem < (rt_uint8_t *)heap_end);
163*10465441SEvalZero     RT_ASSERT(mem->used == 0);
164*10465441SEvalZero 
165*10465441SEvalZero     /* plug hole forward */
166*10465441SEvalZero     nmem = (struct heap_mem *)&heap_ptr[mem->next];
167*10465441SEvalZero     if (mem != nmem &&
168*10465441SEvalZero         nmem->used == 0 &&
169*10465441SEvalZero         (rt_uint8_t *)nmem != (rt_uint8_t *)heap_end)
170*10465441SEvalZero     {
171*10465441SEvalZero         /* if mem->next is unused and not end of heap_ptr,
172*10465441SEvalZero          * combine mem and mem->next
173*10465441SEvalZero          */
174*10465441SEvalZero         if (lfree == nmem)
175*10465441SEvalZero         {
176*10465441SEvalZero             lfree = mem;
177*10465441SEvalZero         }
178*10465441SEvalZero         mem->next = nmem->next;
179*10465441SEvalZero         ((struct heap_mem *)&heap_ptr[nmem->next])->prev = (rt_uint8_t *)mem - heap_ptr;
180*10465441SEvalZero     }
181*10465441SEvalZero 
182*10465441SEvalZero     /* plug hole backward */
183*10465441SEvalZero     pmem = (struct heap_mem *)&heap_ptr[mem->prev];
184*10465441SEvalZero     if (pmem != mem && pmem->used == 0)
185*10465441SEvalZero     {
186*10465441SEvalZero         /* if mem->prev is unused, combine mem and mem->prev */
187*10465441SEvalZero         if (lfree == mem)
188*10465441SEvalZero         {
189*10465441SEvalZero             lfree = pmem;
190*10465441SEvalZero         }
191*10465441SEvalZero         pmem->next = mem->next;
192*10465441SEvalZero         ((struct heap_mem *)&heap_ptr[mem->next])->prev = (rt_uint8_t *)pmem - heap_ptr;
193*10465441SEvalZero     }
194*10465441SEvalZero }
195*10465441SEvalZero 
196*10465441SEvalZero /**
197*10465441SEvalZero  * @ingroup SystemInit
198*10465441SEvalZero  *
199*10465441SEvalZero  * This function will initialize system heap memory.
200*10465441SEvalZero  *
201*10465441SEvalZero  * @param begin_addr the beginning address of system heap memory.
202*10465441SEvalZero  * @param end_addr the end address of system heap memory.
203*10465441SEvalZero  */
rt_system_heap_init(void * begin_addr,void * end_addr)204*10465441SEvalZero void rt_system_heap_init(void *begin_addr, void *end_addr)
205*10465441SEvalZero {
206*10465441SEvalZero     struct heap_mem *mem;
207*10465441SEvalZero     rt_ubase_t begin_align = RT_ALIGN((rt_ubase_t)begin_addr, RT_ALIGN_SIZE);
208*10465441SEvalZero     rt_ubase_t end_align   = RT_ALIGN_DOWN((rt_ubase_t)end_addr, RT_ALIGN_SIZE);
209*10465441SEvalZero 
210*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
211*10465441SEvalZero 
212*10465441SEvalZero     /* alignment addr */
213*10465441SEvalZero     if ((end_align > (2 * SIZEOF_STRUCT_MEM)) &&
214*10465441SEvalZero         ((end_align - 2 * SIZEOF_STRUCT_MEM) >= begin_align))
215*10465441SEvalZero     {
216*10465441SEvalZero         /* calculate the aligned memory size */
217*10465441SEvalZero         mem_size_aligned = end_align - begin_align - 2 * SIZEOF_STRUCT_MEM;
218*10465441SEvalZero     }
219*10465441SEvalZero     else
220*10465441SEvalZero     {
221*10465441SEvalZero         rt_kprintf("mem init, error begin address 0x%x, and end address 0x%x\n",
222*10465441SEvalZero                    (rt_ubase_t)begin_addr, (rt_ubase_t)end_addr);
223*10465441SEvalZero 
224*10465441SEvalZero         return;
225*10465441SEvalZero     }
226*10465441SEvalZero 
227*10465441SEvalZero     /* point to begin address of heap */
228*10465441SEvalZero     heap_ptr = (rt_uint8_t *)begin_align;
229*10465441SEvalZero 
230*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_MEM, ("mem init, heap begin address 0x%x, size %d\n",
231*10465441SEvalZero                                 (rt_ubase_t)heap_ptr, mem_size_aligned));
232*10465441SEvalZero 
233*10465441SEvalZero     /* initialize the start of the heap */
234*10465441SEvalZero     mem        = (struct heap_mem *)heap_ptr;
235*10465441SEvalZero     mem->magic = HEAP_MAGIC;
236*10465441SEvalZero     mem->next  = mem_size_aligned + SIZEOF_STRUCT_MEM;
237*10465441SEvalZero     mem->prev  = 0;
238*10465441SEvalZero     mem->used  = 0;
239*10465441SEvalZero #ifdef RT_USING_MEMTRACE
240*10465441SEvalZero     rt_mem_setname(mem, "INIT");
241*10465441SEvalZero #endif
242*10465441SEvalZero 
243*10465441SEvalZero     /* initialize the end of the heap */
244*10465441SEvalZero     heap_end        = (struct heap_mem *)&heap_ptr[mem->next];
245*10465441SEvalZero     heap_end->magic = HEAP_MAGIC;
246*10465441SEvalZero     heap_end->used  = 1;
247*10465441SEvalZero     heap_end->next  = mem_size_aligned + SIZEOF_STRUCT_MEM;
248*10465441SEvalZero     heap_end->prev  = mem_size_aligned + SIZEOF_STRUCT_MEM;
249*10465441SEvalZero #ifdef RT_USING_MEMTRACE
250*10465441SEvalZero     rt_mem_setname(heap_end, "INIT");
251*10465441SEvalZero #endif
252*10465441SEvalZero 
253*10465441SEvalZero     rt_sem_init(&heap_sem, "heap", 1, RT_IPC_FLAG_FIFO);
254*10465441SEvalZero 
255*10465441SEvalZero     /* initialize the lowest-free pointer to the start of the heap */
256*10465441SEvalZero     lfree = (struct heap_mem *)heap_ptr;
257*10465441SEvalZero }
258*10465441SEvalZero 
259*10465441SEvalZero /**
260*10465441SEvalZero  * @addtogroup MM
261*10465441SEvalZero  */
262*10465441SEvalZero 
263*10465441SEvalZero /**@{*/
264*10465441SEvalZero 
265*10465441SEvalZero /**
266*10465441SEvalZero  * Allocate a block of memory with a minimum of 'size' bytes.
267*10465441SEvalZero  *
268*10465441SEvalZero  * @param size is the minimum size of the requested block in bytes.
269*10465441SEvalZero  *
270*10465441SEvalZero  * @return pointer to allocated memory or NULL if no free memory was found.
271*10465441SEvalZero  */
rt_malloc(rt_size_t size)272*10465441SEvalZero void *rt_malloc(rt_size_t size)
273*10465441SEvalZero {
274*10465441SEvalZero     rt_size_t ptr, ptr2;
275*10465441SEvalZero     struct heap_mem *mem, *mem2;
276*10465441SEvalZero 
277*10465441SEvalZero     if (size == 0)
278*10465441SEvalZero         return RT_NULL;
279*10465441SEvalZero 
280*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
281*10465441SEvalZero 
282*10465441SEvalZero     if (size != RT_ALIGN(size, RT_ALIGN_SIZE))
283*10465441SEvalZero         RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d, but align to %d\n",
284*10465441SEvalZero                                     size, RT_ALIGN(size, RT_ALIGN_SIZE)));
285*10465441SEvalZero     else
286*10465441SEvalZero         RT_DEBUG_LOG(RT_DEBUG_MEM, ("malloc size %d\n", size));
287*10465441SEvalZero 
288*10465441SEvalZero     /* alignment size */
289*10465441SEvalZero     size = RT_ALIGN(size, RT_ALIGN_SIZE);
290*10465441SEvalZero 
291*10465441SEvalZero     if (size > mem_size_aligned)
292*10465441SEvalZero     {
293*10465441SEvalZero         RT_DEBUG_LOG(RT_DEBUG_MEM, ("no memory\n"));
294*10465441SEvalZero 
295*10465441SEvalZero         return RT_NULL;
296*10465441SEvalZero     }
297*10465441SEvalZero 
298*10465441SEvalZero     /* every data block must be at least MIN_SIZE_ALIGNED long */
299*10465441SEvalZero     if (size < MIN_SIZE_ALIGNED)
300*10465441SEvalZero         size = MIN_SIZE_ALIGNED;
301*10465441SEvalZero 
302*10465441SEvalZero     /* take memory semaphore */
303*10465441SEvalZero     rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
304*10465441SEvalZero 
305*10465441SEvalZero     for (ptr = (rt_uint8_t *)lfree - heap_ptr;
306*10465441SEvalZero          ptr < mem_size_aligned - size;
307*10465441SEvalZero          ptr = ((struct heap_mem *)&heap_ptr[ptr])->next)
308*10465441SEvalZero     {
309*10465441SEvalZero         mem = (struct heap_mem *)&heap_ptr[ptr];
310*10465441SEvalZero 
311*10465441SEvalZero         if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size)
312*10465441SEvalZero         {
313*10465441SEvalZero             /* mem is not used and at least perfect fit is possible:
314*10465441SEvalZero              * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
315*10465441SEvalZero 
316*10465441SEvalZero             if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >=
317*10465441SEvalZero                 (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED))
318*10465441SEvalZero             {
319*10465441SEvalZero                 /* (in addition to the above, we test if another struct heap_mem (SIZEOF_STRUCT_MEM) containing
320*10465441SEvalZero                  * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
321*10465441SEvalZero                  * -> split large block, create empty remainder,
322*10465441SEvalZero                  * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
323*10465441SEvalZero                  * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
324*10465441SEvalZero                  * struct heap_mem would fit in but no data between mem2 and mem2->next
325*10465441SEvalZero                  * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
326*10465441SEvalZero                  *       region that couldn't hold data, but when mem->next gets freed,
327*10465441SEvalZero                  *       the 2 regions would be combined, resulting in more free memory
328*10465441SEvalZero                  */
329*10465441SEvalZero                 ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
330*10465441SEvalZero 
331*10465441SEvalZero                 /* create mem2 struct */
332*10465441SEvalZero                 mem2       = (struct heap_mem *)&heap_ptr[ptr2];
333*10465441SEvalZero                 mem2->magic = HEAP_MAGIC;
334*10465441SEvalZero                 mem2->used = 0;
335*10465441SEvalZero                 mem2->next = mem->next;
336*10465441SEvalZero                 mem2->prev = ptr;
337*10465441SEvalZero #ifdef RT_USING_MEMTRACE
338*10465441SEvalZero                 rt_mem_setname(mem2, "    ");
339*10465441SEvalZero #endif
340*10465441SEvalZero 
341*10465441SEvalZero                 /* and insert it between mem and mem->next */
342*10465441SEvalZero                 mem->next = ptr2;
343*10465441SEvalZero                 mem->used = 1;
344*10465441SEvalZero 
345*10465441SEvalZero                 if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM)
346*10465441SEvalZero                 {
347*10465441SEvalZero                     ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
348*10465441SEvalZero                 }
349*10465441SEvalZero #ifdef RT_MEM_STATS
350*10465441SEvalZero                 used_mem += (size + SIZEOF_STRUCT_MEM);
351*10465441SEvalZero                 if (max_mem < used_mem)
352*10465441SEvalZero                     max_mem = used_mem;
353*10465441SEvalZero #endif
354*10465441SEvalZero             }
355*10465441SEvalZero             else
356*10465441SEvalZero             {
357*10465441SEvalZero                 /* (a mem2 struct does no fit into the user data space of mem and mem->next will always
358*10465441SEvalZero                  * be used at this point: if not we have 2 unused structs in a row, plug_holes should have
359*10465441SEvalZero                  * take care of this).
360*10465441SEvalZero                  * -> near fit or excact fit: do not split, no mem2 creation
361*10465441SEvalZero                  * also can't move mem->next directly behind mem, since mem->next
362*10465441SEvalZero                  * will always be used at this point!
363*10465441SEvalZero                  */
364*10465441SEvalZero                 mem->used = 1;
365*10465441SEvalZero #ifdef RT_MEM_STATS
366*10465441SEvalZero                 used_mem += mem->next - ((rt_uint8_t *)mem - heap_ptr);
367*10465441SEvalZero                 if (max_mem < used_mem)
368*10465441SEvalZero                     max_mem = used_mem;
369*10465441SEvalZero #endif
370*10465441SEvalZero             }
371*10465441SEvalZero             /* set memory block magic */
372*10465441SEvalZero             mem->magic = HEAP_MAGIC;
373*10465441SEvalZero #ifdef RT_USING_MEMTRACE
374*10465441SEvalZero             if (rt_thread_self())
375*10465441SEvalZero                 rt_mem_setname(mem, rt_thread_self()->name);
376*10465441SEvalZero             else
377*10465441SEvalZero                 rt_mem_setname(mem, "NONE");
378*10465441SEvalZero #endif
379*10465441SEvalZero 
380*10465441SEvalZero             if (mem == lfree)
381*10465441SEvalZero             {
382*10465441SEvalZero                 /* Find next free block after mem and update lowest free pointer */
383*10465441SEvalZero                 while (lfree->used && lfree != heap_end)
384*10465441SEvalZero                     lfree = (struct heap_mem *)&heap_ptr[lfree->next];
385*10465441SEvalZero 
386*10465441SEvalZero                 RT_ASSERT(((lfree == heap_end) || (!lfree->used)));
387*10465441SEvalZero             }
388*10465441SEvalZero 
389*10465441SEvalZero             rt_sem_release(&heap_sem);
390*10465441SEvalZero             RT_ASSERT((rt_ubase_t)mem + SIZEOF_STRUCT_MEM + size <= (rt_ubase_t)heap_end);
391*10465441SEvalZero             RT_ASSERT((rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM) % RT_ALIGN_SIZE == 0);
392*10465441SEvalZero             RT_ASSERT((((rt_ubase_t)mem) & (RT_ALIGN_SIZE - 1)) == 0);
393*10465441SEvalZero 
394*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_MEM,
395*10465441SEvalZero                          ("allocate memory at 0x%x, size: %d\n",
396*10465441SEvalZero                           (rt_ubase_t)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM),
397*10465441SEvalZero                           (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
398*10465441SEvalZero 
399*10465441SEvalZero             RT_OBJECT_HOOK_CALL(rt_malloc_hook,
400*10465441SEvalZero                                 (((void *)((rt_uint8_t *)mem + SIZEOF_STRUCT_MEM)), size));
401*10465441SEvalZero 
402*10465441SEvalZero             /* return the memory data except mem struct */
403*10465441SEvalZero             return (rt_uint8_t *)mem + SIZEOF_STRUCT_MEM;
404*10465441SEvalZero         }
405*10465441SEvalZero     }
406*10465441SEvalZero 
407*10465441SEvalZero     rt_sem_release(&heap_sem);
408*10465441SEvalZero 
409*10465441SEvalZero     return RT_NULL;
410*10465441SEvalZero }
411*10465441SEvalZero RTM_EXPORT(rt_malloc);
412*10465441SEvalZero 
413*10465441SEvalZero /**
414*10465441SEvalZero  * This function will change the previously allocated memory block.
415*10465441SEvalZero  *
416*10465441SEvalZero  * @param rmem pointer to memory allocated by rt_malloc
417*10465441SEvalZero  * @param newsize the required new size
418*10465441SEvalZero  *
419*10465441SEvalZero  * @return the changed memory block address
420*10465441SEvalZero  */
rt_realloc(void * rmem,rt_size_t newsize)421*10465441SEvalZero void *rt_realloc(void *rmem, rt_size_t newsize)
422*10465441SEvalZero {
423*10465441SEvalZero     rt_size_t size;
424*10465441SEvalZero     rt_size_t ptr, ptr2;
425*10465441SEvalZero     struct heap_mem *mem, *mem2;
426*10465441SEvalZero     void *nmem;
427*10465441SEvalZero 
428*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
429*10465441SEvalZero 
430*10465441SEvalZero     /* alignment size */
431*10465441SEvalZero     newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
432*10465441SEvalZero     if (newsize > mem_size_aligned)
433*10465441SEvalZero     {
434*10465441SEvalZero         RT_DEBUG_LOG(RT_DEBUG_MEM, ("realloc: out of memory\n"));
435*10465441SEvalZero 
436*10465441SEvalZero         return RT_NULL;
437*10465441SEvalZero     }
438*10465441SEvalZero     else if (newsize == 0)
439*10465441SEvalZero     {
440*10465441SEvalZero         rt_free(rmem);
441*10465441SEvalZero         return RT_NULL;
442*10465441SEvalZero     }
443*10465441SEvalZero 
444*10465441SEvalZero     /* allocate a new memory block */
445*10465441SEvalZero     if (rmem == RT_NULL)
446*10465441SEvalZero         return rt_malloc(newsize);
447*10465441SEvalZero 
448*10465441SEvalZero     rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
449*10465441SEvalZero 
450*10465441SEvalZero     if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr ||
451*10465441SEvalZero         (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end)
452*10465441SEvalZero     {
453*10465441SEvalZero         /* illegal memory */
454*10465441SEvalZero         rt_sem_release(&heap_sem);
455*10465441SEvalZero 
456*10465441SEvalZero         return rmem;
457*10465441SEvalZero     }
458*10465441SEvalZero 
459*10465441SEvalZero     mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
460*10465441SEvalZero 
461*10465441SEvalZero     ptr = (rt_uint8_t *)mem - heap_ptr;
462*10465441SEvalZero     size = mem->next - ptr - SIZEOF_STRUCT_MEM;
463*10465441SEvalZero     if (size == newsize)
464*10465441SEvalZero     {
465*10465441SEvalZero         /* the size is the same as */
466*10465441SEvalZero         rt_sem_release(&heap_sem);
467*10465441SEvalZero 
468*10465441SEvalZero         return rmem;
469*10465441SEvalZero     }
470*10465441SEvalZero 
471*10465441SEvalZero     if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size)
472*10465441SEvalZero     {
473*10465441SEvalZero         /* split memory block */
474*10465441SEvalZero #ifdef RT_MEM_STATS
475*10465441SEvalZero         used_mem -= (size - newsize);
476*10465441SEvalZero #endif
477*10465441SEvalZero 
478*10465441SEvalZero         ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
479*10465441SEvalZero         mem2 = (struct heap_mem *)&heap_ptr[ptr2];
480*10465441SEvalZero         mem2->magic = HEAP_MAGIC;
481*10465441SEvalZero         mem2->used = 0;
482*10465441SEvalZero         mem2->next = mem->next;
483*10465441SEvalZero         mem2->prev = ptr;
484*10465441SEvalZero #ifdef RT_USING_MEMTRACE
485*10465441SEvalZero         rt_mem_setname(mem2, "    ");
486*10465441SEvalZero #endif
487*10465441SEvalZero         mem->next = ptr2;
488*10465441SEvalZero         if (mem2->next != mem_size_aligned + SIZEOF_STRUCT_MEM)
489*10465441SEvalZero         {
490*10465441SEvalZero             ((struct heap_mem *)&heap_ptr[mem2->next])->prev = ptr2;
491*10465441SEvalZero         }
492*10465441SEvalZero 
493*10465441SEvalZero         plug_holes(mem2);
494*10465441SEvalZero 
495*10465441SEvalZero         rt_sem_release(&heap_sem);
496*10465441SEvalZero 
497*10465441SEvalZero         return rmem;
498*10465441SEvalZero     }
499*10465441SEvalZero     rt_sem_release(&heap_sem);
500*10465441SEvalZero 
501*10465441SEvalZero     /* expand memory */
502*10465441SEvalZero     nmem = rt_malloc(newsize);
503*10465441SEvalZero     if (nmem != RT_NULL) /* check memory */
504*10465441SEvalZero     {
505*10465441SEvalZero         rt_memcpy(nmem, rmem, size < newsize ? size : newsize);
506*10465441SEvalZero         rt_free(rmem);
507*10465441SEvalZero     }
508*10465441SEvalZero 
509*10465441SEvalZero     return nmem;
510*10465441SEvalZero }
511*10465441SEvalZero RTM_EXPORT(rt_realloc);
512*10465441SEvalZero 
513*10465441SEvalZero /**
514*10465441SEvalZero  * This function will contiguously allocate enough space for count objects
515*10465441SEvalZero  * that are size bytes of memory each and returns a pointer to the allocated
516*10465441SEvalZero  * memory.
517*10465441SEvalZero  *
518*10465441SEvalZero  * The allocated memory is filled with bytes of value zero.
519*10465441SEvalZero  *
520*10465441SEvalZero  * @param count number of objects to allocate
521*10465441SEvalZero  * @param size size of the objects to allocate
522*10465441SEvalZero  *
523*10465441SEvalZero  * @return pointer to allocated memory / NULL pointer if there is an error
524*10465441SEvalZero  */
rt_calloc(rt_size_t count,rt_size_t size)525*10465441SEvalZero void *rt_calloc(rt_size_t count, rt_size_t size)
526*10465441SEvalZero {
527*10465441SEvalZero     void *p;
528*10465441SEvalZero 
529*10465441SEvalZero     /* allocate 'count' objects of size 'size' */
530*10465441SEvalZero     p = rt_malloc(count * size);
531*10465441SEvalZero 
532*10465441SEvalZero     /* zero the memory */
533*10465441SEvalZero     if (p)
534*10465441SEvalZero         rt_memset(p, 0, count * size);
535*10465441SEvalZero 
536*10465441SEvalZero     return p;
537*10465441SEvalZero }
538*10465441SEvalZero RTM_EXPORT(rt_calloc);
539*10465441SEvalZero 
540*10465441SEvalZero /**
541*10465441SEvalZero  * This function will release the previously allocated memory block by
542*10465441SEvalZero  * rt_malloc. The released memory block is taken back to system heap.
543*10465441SEvalZero  *
544*10465441SEvalZero  * @param rmem the address of memory which will be released
545*10465441SEvalZero  */
rt_free(void * rmem)546*10465441SEvalZero void rt_free(void *rmem)
547*10465441SEvalZero {
548*10465441SEvalZero     struct heap_mem *mem;
549*10465441SEvalZero 
550*10465441SEvalZero     if (rmem == RT_NULL)
551*10465441SEvalZero         return;
552*10465441SEvalZero 
553*10465441SEvalZero     RT_DEBUG_NOT_IN_INTERRUPT;
554*10465441SEvalZero 
555*10465441SEvalZero     RT_ASSERT((((rt_ubase_t)rmem) & (RT_ALIGN_SIZE - 1)) == 0);
556*10465441SEvalZero     RT_ASSERT((rt_uint8_t *)rmem >= (rt_uint8_t *)heap_ptr &&
557*10465441SEvalZero               (rt_uint8_t *)rmem < (rt_uint8_t *)heap_end);
558*10465441SEvalZero 
559*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_free_hook, (rmem));
560*10465441SEvalZero 
561*10465441SEvalZero     if ((rt_uint8_t *)rmem < (rt_uint8_t *)heap_ptr ||
562*10465441SEvalZero         (rt_uint8_t *)rmem >= (rt_uint8_t *)heap_end)
563*10465441SEvalZero     {
564*10465441SEvalZero         RT_DEBUG_LOG(RT_DEBUG_MEM, ("illegal memory\n"));
565*10465441SEvalZero 
566*10465441SEvalZero         return;
567*10465441SEvalZero     }
568*10465441SEvalZero 
569*10465441SEvalZero     /* Get the corresponding struct heap_mem ... */
570*10465441SEvalZero     mem = (struct heap_mem *)((rt_uint8_t *)rmem - SIZEOF_STRUCT_MEM);
571*10465441SEvalZero 
572*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_MEM,
573*10465441SEvalZero                  ("release memory 0x%x, size: %d\n",
574*10465441SEvalZero                   (rt_ubase_t)rmem,
575*10465441SEvalZero                   (rt_ubase_t)(mem->next - ((rt_uint8_t *)mem - heap_ptr))));
576*10465441SEvalZero 
577*10465441SEvalZero 
578*10465441SEvalZero     /* protect the heap from concurrent access */
579*10465441SEvalZero     rt_sem_take(&heap_sem, RT_WAITING_FOREVER);
580*10465441SEvalZero 
581*10465441SEvalZero     /* ... which has to be in a used state ... */
582*10465441SEvalZero     if (!mem->used || mem->magic != HEAP_MAGIC)
583*10465441SEvalZero     {
584*10465441SEvalZero         rt_kprintf("to free a bad data block:\n");
585*10465441SEvalZero         rt_kprintf("mem: 0x%08x, used flag: %d, magic code: 0x%04x\n", mem, mem->used, mem->magic);
586*10465441SEvalZero     }
587*10465441SEvalZero     RT_ASSERT(mem->used);
588*10465441SEvalZero     RT_ASSERT(mem->magic == HEAP_MAGIC);
589*10465441SEvalZero     /* ... and is now unused. */
590*10465441SEvalZero     mem->used  = 0;
591*10465441SEvalZero     mem->magic = HEAP_MAGIC;
592*10465441SEvalZero #ifdef RT_USING_MEMTRACE
593*10465441SEvalZero     rt_mem_setname(mem, "    ");
594*10465441SEvalZero #endif
595*10465441SEvalZero 
596*10465441SEvalZero     if (mem < lfree)
597*10465441SEvalZero     {
598*10465441SEvalZero         /* the newly freed struct is now the lowest */
599*10465441SEvalZero         lfree = mem;
600*10465441SEvalZero     }
601*10465441SEvalZero 
602*10465441SEvalZero #ifdef RT_MEM_STATS
603*10465441SEvalZero     used_mem -= (mem->next - ((rt_uint8_t *)mem - heap_ptr));
604*10465441SEvalZero #endif
605*10465441SEvalZero 
606*10465441SEvalZero     /* finally, see if prev or next are free also */
607*10465441SEvalZero     plug_holes(mem);
608*10465441SEvalZero     rt_sem_release(&heap_sem);
609*10465441SEvalZero }
610*10465441SEvalZero RTM_EXPORT(rt_free);
611*10465441SEvalZero 
612*10465441SEvalZero #ifdef RT_MEM_STATS
rt_memory_info(rt_uint32_t * total,rt_uint32_t * used,rt_uint32_t * max_used)613*10465441SEvalZero void rt_memory_info(rt_uint32_t *total,
614*10465441SEvalZero                     rt_uint32_t *used,
615*10465441SEvalZero                     rt_uint32_t *max_used)
616*10465441SEvalZero {
617*10465441SEvalZero     if (total != RT_NULL)
618*10465441SEvalZero         *total = mem_size_aligned;
619*10465441SEvalZero     if (used  != RT_NULL)
620*10465441SEvalZero         *used = used_mem;
621*10465441SEvalZero     if (max_used != RT_NULL)
622*10465441SEvalZero         *max_used = max_mem;
623*10465441SEvalZero }
624*10465441SEvalZero 
625*10465441SEvalZero #ifdef RT_USING_FINSH
626*10465441SEvalZero #include <finsh.h>
627*10465441SEvalZero 
list_mem(void)628*10465441SEvalZero void list_mem(void)
629*10465441SEvalZero {
630*10465441SEvalZero     rt_kprintf("total memory: %d\n", mem_size_aligned);
631*10465441SEvalZero     rt_kprintf("used memory : %d\n", used_mem);
632*10465441SEvalZero     rt_kprintf("maximum allocated memory: %d\n", max_mem);
633*10465441SEvalZero }
FINSH_FUNCTION_EXPORT(list_mem,list memory usage information)634*10465441SEvalZero FINSH_FUNCTION_EXPORT(list_mem, list memory usage information)
635*10465441SEvalZero 
636*10465441SEvalZero #ifdef RT_USING_MEMTRACE
637*10465441SEvalZero int memcheck(void)
638*10465441SEvalZero {
639*10465441SEvalZero     int position;
640*10465441SEvalZero     rt_ubase_t level;
641*10465441SEvalZero     struct heap_mem *mem;
642*10465441SEvalZero     level = rt_hw_interrupt_disable();
643*10465441SEvalZero     for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
644*10465441SEvalZero     {
645*10465441SEvalZero         position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr;
646*10465441SEvalZero         if (position < 0) goto __exit;
647*10465441SEvalZero         if (position > mem_size_aligned) goto __exit;
648*10465441SEvalZero         if (mem->magic != HEAP_MAGIC) goto __exit;
649*10465441SEvalZero         if (mem->used != 0 && mem->used != 1) goto __exit;
650*10465441SEvalZero     }
651*10465441SEvalZero     rt_hw_interrupt_enable(level);
652*10465441SEvalZero 
653*10465441SEvalZero     return 0;
654*10465441SEvalZero __exit:
655*10465441SEvalZero     rt_kprintf("Memory block wrong:\n");
656*10465441SEvalZero     rt_kprintf("address: 0x%08x\n", mem);
657*10465441SEvalZero     rt_kprintf("  magic: 0x%04x\n", mem->magic);
658*10465441SEvalZero     rt_kprintf("   used: %d\n", mem->used);
659*10465441SEvalZero     rt_kprintf("  size: %d\n", mem->next - position - SIZEOF_STRUCT_MEM);
660*10465441SEvalZero     rt_hw_interrupt_enable(level);
661*10465441SEvalZero 
662*10465441SEvalZero     return 0;
663*10465441SEvalZero }
664*10465441SEvalZero MSH_CMD_EXPORT(memcheck, check memory data);
665*10465441SEvalZero 
memtrace(int argc,char ** argv)666*10465441SEvalZero int memtrace(int argc, char **argv)
667*10465441SEvalZero {
668*10465441SEvalZero     struct heap_mem *mem;
669*10465441SEvalZero 
670*10465441SEvalZero     list_mem();
671*10465441SEvalZero 
672*10465441SEvalZero     rt_kprintf("\nmemory heap address:\n");
673*10465441SEvalZero     rt_kprintf("heap_ptr: 0x%08x\n", heap_ptr);
674*10465441SEvalZero     rt_kprintf("lfree   : 0x%08x\n", lfree);
675*10465441SEvalZero     rt_kprintf("heap_end: 0x%08x\n", heap_end);
676*10465441SEvalZero 
677*10465441SEvalZero     rt_kprintf("\n--memory item information --\n");
678*10465441SEvalZero     for (mem = (struct heap_mem *)heap_ptr; mem != heap_end; mem = (struct heap_mem *)&heap_ptr[mem->next])
679*10465441SEvalZero     {
680*10465441SEvalZero         int position = (rt_ubase_t)mem - (rt_ubase_t)heap_ptr;
681*10465441SEvalZero         int size;
682*10465441SEvalZero 
683*10465441SEvalZero         rt_kprintf("[0x%08x - ", mem);
684*10465441SEvalZero 
685*10465441SEvalZero         size = mem->next - position - SIZEOF_STRUCT_MEM;
686*10465441SEvalZero         if (size < 1024)
687*10465441SEvalZero             rt_kprintf("%5d", size);
688*10465441SEvalZero         else if (size < 1024 * 1024)
689*10465441SEvalZero             rt_kprintf("%4dK", size / 1024);
690*10465441SEvalZero         else
691*10465441SEvalZero             rt_kprintf("%4dM", size / (1024 * 1024));
692*10465441SEvalZero 
693*10465441SEvalZero         rt_kprintf("] %c%c%c%c", mem->thread[0], mem->thread[1], mem->thread[2], mem->thread[3]);
694*10465441SEvalZero         if (mem->magic != HEAP_MAGIC)
695*10465441SEvalZero             rt_kprintf(": ***\n");
696*10465441SEvalZero         else
697*10465441SEvalZero             rt_kprintf("\n");
698*10465441SEvalZero     }
699*10465441SEvalZero 
700*10465441SEvalZero     return 0;
701*10465441SEvalZero }
702*10465441SEvalZero MSH_CMD_EXPORT(memtrace, dump memory trace information);
703*10465441SEvalZero #endif /* end of RT_USING_MEMTRACE */
704*10465441SEvalZero #endif /* end of RT_USING_FINSH    */
705*10465441SEvalZero 
706*10465441SEvalZero #endif
707*10465441SEvalZero 
708*10465441SEvalZero /**@}*/
709*10465441SEvalZero 
710*10465441SEvalZero #endif /* end of RT_USING_HEAP */
711*10465441SEvalZero #endif /* end of RT_USING_MEMHEAP_AS_HEAP */
712