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