The Mullocator - Part III - Testing Boundaries
This poses the question how to get memory from the OS. We can't use malloc obviously, because we're trying to replace it. In the old unix days one used sbrk and brk. It still can be used today - maybe I should use it :) - but instead we are going to use the slightly more "modern" mmap feature. There is also vm_allocate which can be used to allocate memory under Mach. I prefer to use mmap because it's a little bit more universal and at least a few years ago, also faster. The actual implementation details are for another installment. I weasel my way out of the predicament by using a os_alloc function, that will call the required OS function. os_alloc will be written later.
Because malloc(0) is guaranteed by convention to return a unique pointer and not NULL (if memory is available), let's also check for that and align the size at the same time.
Also we now support errno. It should be set to ENOMEM if memory is exhausted.
static inline void *malloc( size_t size)
{
extern long *memory;
extern long *sentinel;
extern long *buf;
void *p;
long *q;
size_t len;
size += (size == 0);
size = (size + sizeof( long) - 1) / sizeof( long);
q = &buf[ size];
if( q > sentinel)
{
len = size < BLOCK_SIZE_LONGS ? BLOCK_SIZE_LONGS : size;
memory = os_alloc( len);
if( ! memory)
{
errno = ENOMEM; // yes should be setting errno..
return( NULL);
}
sentinel = &memory[ len];
buf = memory;
q = &buf[ size];
}
p = buf;
buf = q;
return( p);
}
Although this code does solve problem #4, it also introduces a few problems.
- The BLOCK_SIZE_LONGS constant is an arbitrary choice. If we set it to 0x1000000 / sizeof( longs) we haven't gained anything compared to the code before. If we set it to 1, we'll be calling os_alloc for every malloc call. The truth is somewhere in the unknown middle.
- The old memory block is immediately forgotten once we cannot satisfy a memory request. This is very wasteful. In a call sequence of
for(;;) { malloc( 1); malloc( BLOCK_SIZE_LONGS * sizeof( long)); }we'd be burning memory at almost twice the rate necessary. This is probably too wasteful.