ref: 385ecf9c11ba7114801e877090951e1785698051
dir: /alloc.c/
#include <u.h>
#include "dat.h"
#include "fns.h"
#include "mem.h"
#include "debug.h"
#include "libkern/kern.h"
#define CMEMSIZE DATASIZE
#define BHDR_MAGIC 0xcafebafe
#define BHDR_POISON 0xdeadbeef
#define BPTR(h) ((Bhdr *)((uint)h + sizeof(Bhdr)))
#define BNEXT(h) ((Bhdr *)((uint)h + sizeof(Bhdr) + h->size))
enum {
Bfree = 0,
Balloc,
};
typedef struct Bhdr {
ulong magic;
ulong size;
int tp;
} Bhdr;
#define first ((Bhdr*) DATASADDR)
void
allocinit()
{
first->magic = BHDR_MAGIC;
first->size = DATASIZE - sizeof(Bhdr);
first->tp = Bfree;
memset(BPTR(first), 0, first->size);
}
Bhdr*
cmfindsmallest(ulong size)
{
Bhdr *t = nil;
DBGALLOC print("alloc: finding %uld size block\n", size);
for(Bhdr *hdr = first; ((uint)hdr - (uint)first) < CMEMSIZE;
hdr = BNEXT(hdr)) {
DBGALLOC print("alloc: checking block with size %uld\n", hdr->size);
if(hdr->magic != BHDR_MAGIC)
panic("block has bad magic number");
if(hdr->size < size || hdr->tp == Balloc)
continue;
if(hdr->size >= size && t == nil)
t = hdr;
if(hdr->size >= size && hdr->size < t->size)
t = hdr;
}
DBGALLOC print("alloc: block selected\n");
return t;
}
void*
mallocz(ulong size, int clr)
{
Bhdr* hdr = cmfindsmallest(size);
ulong osize;
void *ptr;
if(hdr == nil)
return nil;
// <-lock
// allocate block
osize = hdr->size;
hdr->tp = Balloc;
hdr->size = size;
ptr = BPTR(hdr);
// create next block
if((uint)BNEXT(hdr) < ((uint)first + CMEMSIZE - sizeof(Bhdr)) &&
BNEXT(hdr)->magic != BHDR_MAGIC) {
hdr = BNEXT(hdr);
hdr->magic = BHDR_MAGIC;
hdr->tp = Bfree;
hdr->size = osize - size - sizeof(Bhdr);
DBGALLOC print("alloc: created next block of size %uld\n", hdr->size);
}
// <-unlock
// return pointer
if(clr)
memset(ptr, 0, size);
return ptr;
}
void*
malloc(ulong size)
{
return mallocz(size, 1);
}
void*
smalloc(ulong size)
{
void *ptr;
while((ptr = malloc(size)) == nil)
_wait(100);
return ptr;
}
void
free(void *ptr)
{
Bhdr *hdr = nil;
Bhdr *c = nil;
// first pass: find and free the block
DBGALLOC print("alloc: free'ing block\n");
for(Bhdr *t = first; (uint)t - (uint)first < CMEMSIZE && hdr == nil; t = BNEXT(t)) {
void *t_ptr = BPTR(t);
if(t_ptr == ptr)
hdr = t;
}
if(hdr == nil)
return;
hdr->tp = Bfree;
memset(ptr, 0, hdr->size);
// second pass: coalesce with the next block
DBGALLOC print("alloc: coalesce with next block\n");
if((uint)BNEXT(hdr) < (uint)first + CMEMSIZE && BNEXT(hdr)->tp == Bfree) {
hdr->size = hdr->size + BNEXT(hdr)->size + sizeof(Bhdr);
}
// third pass: coalesce with the previous block
DBGALLOC print("alloc: coalesce with previous block\n");
for(Bhdr *t = first; (uint)t - (uint)first < CMEMSIZE && c == nil; t = BNEXT(t)) {
if(BNEXT(t) < first + CMEMSIZE && BNEXT(t) == hdr && t->tp == Bfree)
c = t;
}
if(c != nil)
c->size = c->size + hdr->size + sizeof(Bhdr);
DBGALLOC print("alloc: updating size to %uld\n", c->size);
}
void*
realloc(void *ptr, ulong size)
{
Bhdr *hdr = nil;
void *nptr;
for(Bhdr *t = first; (uint)t - (uint)first < CMEMSIZE && hdr == nil; t = BNEXT(t)) {
void *t_ptr = BPTR(t);
if(t_ptr == ptr)
hdr = t;
}
if(hdr == nil)
return nil;
// first pass: see if the block is extendable
// TODO
// second pass: find a new block
nptr = malloc(size);
if(nptr == nil)
return nil;
if(hdr->size < size)
size = hdr->size;
memcpy(nptr, BPTR(hdr), size);
free(ptr);
return nptr;
}