blob: b2a3138ebdad0ec48c9e16630bfd8e896d10b174 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2004, 2008 IBM Corporation
* All rights reserved.
* This program and the accompanying materials
* are made available under the terms of the BSD License
* which accompanies this distribution, and is available at
* http://www.opensource.org/licenses/bsd-license.php
*
* Contributors:
* IBM Corporation - initial implementation
*****************************************************************************/
#include "stddef.h"
#include "stdlib.h"
#include "unistd.h"
#include "malloc_defs.h"
static int clean(void);
/* act points to the end of the initialized heap and the start of uninitialized heap */
static char *act;
/* Pointers to start and end of heap: */
static char *heap_start, *heap_end;
/*
* Standard malloc function
*/
void *
malloc(size_t size)
{
char *header;
void *data;
size_t blksize; /* size of memory block including the chunk */
blksize = size + sizeof(struct chunk);
/* has malloc been called for the first time? */
if (act == 0) {
size_t initsize;
/* add some space so we have a good initial playground */
initsize = (blksize + 0x1000) & ~0x0fff;
/* get initial memory region with sbrk() */
heap_start = sbrk(initsize);
if (heap_start == (void*)-1)
return NULL;
heap_end = heap_start + initsize;
act = heap_start;
}
header = act;
data = act + sizeof(struct chunk);
/* Check if there is space left in the uninitialized part of the heap */
if (act + blksize > heap_end) {
//search at begin of heap
header = heap_start;
while ((((struct chunk *) header)->inuse != 0
|| ((struct chunk *) header)->length < size)
&& header < act) {
header = header + sizeof(struct chunk)
+ ((struct chunk *) header)->length;
}
// check if heap is full
if (header >= act) {
if (clean()) {
// merging of free blocks succeeded, so try again
return malloc(size);
} else if (sbrk(blksize) == heap_end) {
// succeeded to get more memory, so try again
heap_end += blksize;
return malloc(size);
} else {
// No more memory available
return 0;
}
}
// Check if we need to split this memory block into two
if (((struct chunk *) header)->length > blksize) {
//available memory is too big
int alt;
alt = ((struct chunk *) header)->length;
((struct chunk *) header)->inuse = 1;
((struct chunk *) header)->length = size;
data = header + sizeof(struct chunk);
//mark the rest of the heap
header = data + size;
((struct chunk *) header)->inuse = 0;
((struct chunk *) header)->length =
alt - blksize;
} else {
//new memory matched exactly in available memory
((struct chunk *) header)->inuse = 1;
data = header + sizeof(struct chunk);
}
} else {
((struct chunk *) header)->inuse = 1;
((struct chunk *) header)->length = size;
act += blksize;
}
return data;
}
/*
* Merge free memory blocks in initialized heap if possible
*/
static int
clean(void)
{
char *header;
char *firstfree = 0;
char check = 0;
header = heap_start;
//if (act == 0) // This should never happen
// act = heap_end;
while (header < act) {
if (((struct chunk *) header)->inuse == 0) {
if (firstfree == 0) {
/* First free block in a row, only save address */
firstfree = header;
} else {
/* more than one free block in a row, merge them! */
((struct chunk *) firstfree)->length +=
((struct chunk *) header)->length +
sizeof(struct chunk);
check = 1;
}
} else {
firstfree = 0;
}
header = header + sizeof(struct chunk)
+ ((struct chunk *) header)->length;
}
return check;
}