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