#include <malloc.h>
#include <stdio.h>
#include <os/os.h>
#include <assert.h>
semaphore_t sem_malloc;
static BlockHeader base;
BlockHeader *freep;
BlockHeader* morecore(size_t nu);
typedef struct malloc_debug_t malloc_debug_t;
struct malloc_debug_t
{
malloc_debug_t *next;
int line;
const char *file;
dword start;
};
#define MALLOC_START 0xA110C574
#define MALLOC_END 0xA110C34D
malloc_debug_t *__first, *__last;
void __free_core(void *ptr);
//void* __realloc_core(void* ptr, size_t size);
size_t __msize_core(void* ptr);
//! Allocates a block of memory.
/*!
* malloc() is required to allocate blocks of memory of arbitrary size
* (i.e. whose size is not known at compile time). The contents of the
* new block are undefined.
*
* Blocks allocated using malloc() should be freed using free(). Calls to
* malloc() may require more memory from the operating system, which
* requires a system call.
*
* Blocks returned by malloc() are guaranteed to be \e at \e least \p nbytes
* long. More memory may be allocated for memory manager overhead.
* \param nbytes Size, in bytes, of the block requested.
* \return A pointer to the start of the new block, or NULL if the
* allocation failed (e.g. if the operation system was unable to
* allocate any more memory to the process).
*/
void *malloc_core(size_t nbytes)
{
BlockHeader *p, *prevp;
unsigned nunits;
semAcquire(&sem_malloc);
nunits = (nbytes + sizeof(BlockHeader) - 1) / sizeof(BlockHeader) + 1;
//wprintf(L"malloc: %d bytes = %d units freep = %p", nbytes, nunits, freep);
if ((prevp = freep) == NULL)
{
base.s.ptr = freep = prevp = &base;
base.s.size = 0;
}
for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr)
{
if (p->s.size >= nunits)
{
if (p->s.size == nunits)
prevp->s.ptr = p->s.ptr;
else
{
p->s.size -= nunits;
p += p->s.size;
p->s.size = nunits;
}
freep = prevp;
//wprintf(L"buf = %x\n", p + 1);
semRelease(&sem_malloc);
return (void*) (p + 1);
}
if (p == freep)
if ((p = morecore(nunits)) == NULL)
{
//wprintf(L"[malloc] out of memory\n");
semRelease(&sem_malloc);
return NULL;
}
}
}
void __malloc_check()
{
malloc_debug_t *h;
char *s;
dword *dw;
for (h = __first; h; h = h->next)
{
if (h->start != MALLOC_START)
{
s = (char*) &h->start;
wprintf(L"%S(%d): damaged memory before %p: %c%c%c%c",
h->file, h->line, h + 1, s[0], s[1], s[2], s[3]);
}
dw = (dword*) ((byte*) h + msize(h));
if (dw[-1] != MALLOC_END)
{
s = (char*) &h->start;
wprintf(L"%S(%d): damaged memory after %p: %c%c%c%c",
h->file, h->line, h + 1, s[0], s[1], s[2], s[3]);
}
}
}
void *__malloc_dbg(size_t nbytes, const char *file, int line)
{
malloc_debug_t *header;
dword *dw;
__malloc_check();
nbytes += sizeof(*header) + sizeof(dword);
header = malloc_core(nbytes);
if (header == NULL)
return NULL;
header->start = MALLOC_START;
header->file = file;
header->line = line;
dw = (dword*) ((byte*) (header + 1) + nbytes);
*dw = MALLOC_END;
if (__first == NULL)
__first = header;
if (__last)
__last->next = header;
header->next = NULL;
__last = header;
return header + 1;
}
void __free_dbg(void *p)
{
malloc_debug_t *header, *h, *prev;
__malloc_check();
header = (malloc_debug_t*) p + 1;
prev = NULL;
for (h = __first; h; h = h->next)
{
if (h == header)
{
if (prev)
prev->next = header->next;
if (__last == header)
__last = prev;
break;
}
prev = h;
}
if (__first == header)
__first = header->next;
__free_core(header);
}
size_t __msize_dbg(void *p)
{
return __msize_core(p) - sizeof(malloc_debug_t) - sizeof(dword);
}
/*void *__realloc_dbg(void *p, size_t size)
{
malloc_debug_t *header;
header = __realloc_core(p, size + sizeof(malloc_debug_t) + sizeof(dword));
if (header)
return header + 1;
else
return NULL;
}*/