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