#include #include "list.h" #include "error.h" #include "bin.h" #include "mem.h" #define MEM_PRE 4096 static align_t local_store[MEM_PRE / MEM_ALIGN]; #define space ((char *)local_store) static unsigned int avail = MEM_PRE; static int bomb_gc = 0; static list_t gc = 0; void inline *mem_alloc(int bytes) { int (*fn)(void *); register char *x; int tries = 0; list_t lp; /* could overflow if MEM_ALIGN is too large */ bytes = MEM_ALIGN + bytes - (bytes & (MEM_ALIGN - 1)); if (bytes <= avail) { avail -= bytes; return space + avail; } /* Clib */ retry_l:x = malloc(bytes); if (!x) { if (bomb_gc && tries > 9) { /* try at most 10 times... if bomb_gc is set, bad things * are going to happen anyway... */ errno = ENOMEM; return x; } /* try gc handlers */ for (lp = gc; lp; lp = lp->next) { x = lp->str; fn = (int (*)(void *))(((char *)lp->str)+sizeof(char *)); if (fn(x)) { tries++; goto retry_l; } } errno = ENOMEM; } return x; } void mem_free(void *x) { /* this assumes a flat address space */ if (((char *)x) >= space && ((char *)x) <= space + MEM_PRE) return; free(x); } void mem_register_gc(void *x, int (*fn)(void *x)) { bin_t c; if (!fn) return; bomb_gc = 1; bin_init(c); bin_copy(c, (char *)&x, sizeof(char *)); bin_cat(c, (char *)&fn, sizeof(char *)); list_push(&gc, caddr(c)); bomb_gc = 0; }