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