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; }