void *rt_malloc(rt_size_t size) { void* ptr; /* try to allocate in system heap */ ptr = rt_memheap_alloc(&_heap, size); if (ptr == RT_NULL) { struct rt_object *object; struct rt_list_node *node; struct rt_memheap *heap; struct rt_object_information *information; extern struct rt_object_information rt_object_container[]; /* try to allocate on other memory heap */ information = &rt_object_container[RT_Object_Class_MemHeap]; for (node = information->object_list.next; node != &(information->object_list); node = node->next) { object = rt_list_entry(node, struct rt_object, list); heap = (struct rt_memheap *)object; /* not allocate in the default system heap */ if (heap == &_heap) continue; ptr = rt_memheap_alloc(heap, size); if (ptr != RT_NULL) break; } } return ptr; }
void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize) { rt_err_t result; rt_size_t oldsize; struct rt_memheap_item *header_ptr; struct rt_memheap_item *new_ptr; if (newsize == 0) { rt_memheap_free(ptr); return RT_NULL; } /* align allocated size */ newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE); if (newsize < RT_MEMHEAP_MINIALLOC) newsize = RT_MEMHEAP_MINIALLOC; if (ptr == RT_NULL) { return rt_memheap_alloc(heap, newsize); } /* get memory block header and get the size of memory block */ header_ptr = (struct rt_memheap_item *) ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE); oldsize = MEMITEM_SIZE(header_ptr); /* re-allocate memory */ if (newsize > oldsize) { void* new_ptr; struct rt_memheap_item *next_ptr; /* lock memheap */ result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); if (result != RT_EOK) { rt_set_errno(result); return RT_NULL; } next_ptr = header_ptr->next; /* header_ptr should not be the tail */ RT_ASSERT(next_ptr > header_ptr); /* check whether the following free space is enough to expand */ if (!RT_MEMHEAP_IS_USED(next_ptr)) { rt_int32_t nextsize; nextsize = MEMITEM_SIZE(next_ptr); RT_ASSERT(next_ptr > 0); /* Here is the ASCII art of the situation that we can make use of * the next free node without alloc/memcpy, |*| is the control * block: * * oldsize free node * |*|-----------|*|----------------------|*| * newsize >= minialloc * |*|----------------|*|-----------------|*| */ if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC) { /* decrement the entire free size from the available bytes count. */ heap->available_size = heap->available_size - (newsize - oldsize); if (heap->pool_size - heap->available_size > heap->max_used_size) heap->max_used_size = heap->pool_size - heap->available_size; /* remove next_ptr from free list */ RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x", next_ptr, next_ptr->next_free, next_ptr->prev_free)); next_ptr->next_free->prev_free = next_ptr->prev_free; next_ptr->prev_free->next_free = next_ptr->next_free; next_ptr->next->prev = next_ptr->prev; next_ptr->prev->next = next_ptr->next; /* build a new one on the right place */ next_ptr = (struct rt_memheap_item*)((char*)ptr + newsize); RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]", next_ptr, next_ptr->next, next_ptr->prev)); /* mark the new block as a memory block and freed. */ next_ptr->magic = RT_MEMHEAP_MAGIC; /* put the pool pointer into the new block. */ next_ptr->pool_ptr = heap; next_ptr->prev = header_ptr; next_ptr->next = header_ptr->next; header_ptr->next->prev = next_ptr; header_ptr->next = next_ptr; /* insert next_ptr to free list */ next_ptr->next_free = heap->free_list->next_free; next_ptr->prev_free = heap->free_list; heap->free_list->next_free->prev_free = next_ptr; heap->free_list->next_free = next_ptr; RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x", next_ptr->next_free, next_ptr->prev_free)); /* release lock */ rt_sem_release(&(heap->lock)); return ptr; } } /* release lock */ rt_sem_release(&(heap->lock)); /* re-allocate a memory block */ new_ptr = (void*)rt_memheap_alloc(heap, newsize); if (new_ptr != RT_NULL) { rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize); rt_memheap_free(ptr); } return new_ptr; } /* don't split when there is less than one node space left */ if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize) return ptr; /* lock memheap */ result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER); if (result != RT_EOK) { rt_set_errno(result); return RT_NULL; } /* split the block. */ new_ptr = (struct rt_memheap_item *) (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE); RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n", header_ptr, header_ptr->next, header_ptr->prev, new_ptr)); /* mark the new block as a memory block and freed. */ new_ptr->magic = RT_MEMHEAP_MAGIC; /* put the pool pointer into the new block. */ new_ptr->pool_ptr = heap; /* break down the block list */ new_ptr->prev = header_ptr; new_ptr->next = header_ptr->next; header_ptr->next->prev = new_ptr; header_ptr->next = new_ptr; /* determine if the block can be merged with the next neighbor. */ if (!RT_MEMHEAP_IS_USED(new_ptr->next)) { struct rt_memheap_item *free_ptr; /* merge block with next neighbor. */ free_ptr = new_ptr->next; heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr); RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n", header_ptr, header_ptr->next_free, header_ptr->prev_free)); free_ptr->next->prev = new_ptr; new_ptr->next = free_ptr->next; /* remove free ptr from free list */ free_ptr->next_free->prev_free = free_ptr->prev_free; free_ptr->prev_free->next_free = free_ptr->next_free; } /* insert the split block to free list */ new_ptr->next_free = heap->free_list->next_free; new_ptr->prev_free = heap->free_list; heap->free_list->next_free->prev_free = new_ptr; heap->free_list->next_free = new_ptr; RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n", new_ptr->next_free, new_ptr->prev_free)); /* increment the available byte count. */ heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr); /* release lock */ rt_sem_release(&(heap->lock)); /* return the old memory block */ return ptr; }
void *sram_malloc(unsigned long size) { return rt_memheap_alloc(&system_heap, size); }