您的位置:首页 > 其它

内存管理: malloc()与free()的一种基于clib标准的实现

2012-05-03 22:12 477 查看
/**
* Zero the heap and initialize start, end and lowest-free
*/
void
mem_init(void)
{
struct mem *mem;

LWIP_ASSERT("Sanity check alignment",
(SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);

/* align the heap */
ram = LWIP_MEM_ALIGN(ram_heap);
/* initialize the start of the heap */
mem = (struct mem *)ram;
mem->next = MEM_SIZE_ALIGNED;
mem->prev = 0;
mem->used = 0;
/* initialize the end of the heap */
ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];
ram_end->used = 1;
ram_end->next = MEM_SIZE_ALIGNED;
ram_end->prev = MEM_SIZE_ALIGNED;

mem_sem = sys_sem_new(1);

/* initialize the lowest-free pointer to the start of the heap */
lfree = (struct mem *)ram;

MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
}

/**
* Adam's mem_malloc() plus solution for bug #17922
* Allocate a block of memory with a minimum of 'size' bytes.
*
* @param size is the minimum size of the requested block in bytes.
* @return pointer to allocated memory or NULL if no free memory was found.
*
* Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).
*/
void *
mem_malloc(mem_size_t size)
{
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;

LWIP_MEM_ALLOC_DECL_PROTECT();

if (size == 0) {
return NULL;
}

/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
size = LWIP_MEM_ALIGN_SIZE(size);

if(size < MIN_SIZE_ALIGNED) {
/* every data block must be at least MIN_SIZE_ALIGNED long */
size = MIN_SIZE_ALIGNED;
}

if (size > MEM_SIZE_ALIGNED) {
return NULL;
}

/* protect the heap from concurrent access */
sys_arch_sem_wait(mem_sem, 0);
LWIP_MEM_ALLOC_PROTECT();

/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
ptr = ((struct mem *)&ram[ptr])->next) {
mem = (struct mem *)&ram[ptr];

if ((!mem->used) &&
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
/* mem is not used and at least perfect fit is possible:
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem
*/

if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
* struct mem would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
/* create mem2 struct */
mem2 = (struct mem *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
/* and insert it between mem and mem->next */
mem->next = ptr2;
mem->used = 1;

if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram));
}

if (mem == lfree) {
/* Find next free block after mem and update lowest free pointer */
while (lfree->used && lfree != ram_end) {
LWIP_MEM_ALLOC_UNPROTECT();
/* prevent high interrupt latency... */
LWIP_MEM_ALLOC_PROTECT();
lfree = (struct mem *)&ram[lfree->next];
}
}
LWIP_MEM_ALLOC_UNPROTECT();
sys_sem_signal(mem_sem);

return (u8_t *)mem + SIZEOF_STRUCT_MEM;
}
}

MEM_STATS_INC(err);
LWIP_MEM_ALLOC_UNPROTECT();
sys_sem_signal(mem_sem);
return NULL;
}

/**
* "Plug holes" by combining adjacent empty struct mems.
* After this function is through, there should not exist
* one empty struct mem pointing to another empty struct mem.
*
* @param mem this points to a struct mem which just has been freed
* @internal this function is only called by mem_free() and mem_realloc()
*
* This assumes access to the heap is protected by the calling function
* already.
*/
static void
plug_holes(struct mem *mem)
{
struct mem *nmem;
struct mem *pmem;

/* plug hole forward */
LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);

nmem = (struct mem *)&ram[mem->next];
if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
/* if mem->next is unused and not end of ram, combine mem and mem->next */
if (lfree == nmem) {
lfree = mem;
}
mem->next = nmem->next;
((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
}

/* plug hole backward */
pmem = (struct mem *)&ram[mem->prev];
if (pmem != mem && pmem->used == 0) {
/* if mem->prev is unused, combine mem and mem->prev */
if (lfree == mem) {
lfree = pmem;
}
pmem->next = mem->next;
((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
}
}

/**
* Put a struct mem back on the heap
*
* @param rmem is the data portion of a struct mem as returned by a previous
*             call to mem_malloc()
*/
void
mem_free(void *rmem)
{
struct mem *mem;

LWIP_MEM_FREE_DECL_PROTECT();

if (rmem == NULL) {
return;
}

if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
SYS_ARCH_DECL_PROTECT(lev);
/* protect mem stats from concurrent access */
SYS_ARCH_PROTECT(lev);
MEM_STATS_INC(illegal);
SYS_ARCH_UNPROTECT(lev);
return;
}
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
/* ... which has to be in a used state ... */
LWIP_ASSERT("mem_free: mem->used", mem->used);
/* ... and is now unused. */
mem->used = 0;

if (mem < lfree) {
/* the newly freed struct is now the lowest */
lfree = mem;
}

MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram));

/* finally, see if prev or next are free also */
plug_holes(mem);
LWIP_MEM_FREE_UNPROTECT();
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐