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