13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <pool.h>
4b85a8364SDavid du Colombier #include <tos.h>
53e12c5d1SDavid du Colombier
67dd7cddfSDavid du Colombier static void* sbrkalloc(ulong);
77dd7cddfSDavid du Colombier static int sbrkmerge(void*, void*);
87dd7cddfSDavid du Colombier static void plock(Pool*);
97dd7cddfSDavid du Colombier static void punlock(Pool*);
107dd7cddfSDavid du Colombier static void pprint(Pool*, char*, ...);
117dd7cddfSDavid du Colombier static void ppanic(Pool*, char*, ...);
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier typedef struct Private Private;
147dd7cddfSDavid du Colombier struct Private {
157dd7cddfSDavid du Colombier Lock lk;
16b85a8364SDavid du Colombier int pid;
177dd7cddfSDavid du Colombier int printfd; /* gets debugging output if set */
183e12c5d1SDavid du Colombier };
193e12c5d1SDavid du Colombier
207dd7cddfSDavid du Colombier Private sbrkmempriv;
217dd7cddfSDavid du Colombier
227dd7cddfSDavid du Colombier static Pool sbrkmem = {
237dd7cddfSDavid du Colombier .name= "sbrkmem",
24*3b86f2f8SDavid du Colombier .maxsize= (3840UL-1)*1024*1024, /* up to ~0xf0000000 */
257dd7cddfSDavid du Colombier .minarena= 4*1024,
267dd7cddfSDavid du Colombier .quantum= 32,
277dd7cddfSDavid du Colombier .alloc= sbrkalloc,
287dd7cddfSDavid du Colombier .merge= sbrkmerge,
297dd7cddfSDavid du Colombier .flags= 0,
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier .lock= plock,
327dd7cddfSDavid du Colombier .unlock= punlock,
337dd7cddfSDavid du Colombier .print= pprint,
347dd7cddfSDavid du Colombier .panic= ppanic,
357dd7cddfSDavid du Colombier .private= &sbrkmempriv,
363e12c5d1SDavid du Colombier };
377dd7cddfSDavid du Colombier Pool *mainmem = &sbrkmem;
387dd7cddfSDavid du Colombier Pool *imagmem = &sbrkmem;
393e12c5d1SDavid du Colombier
407dd7cddfSDavid du Colombier /*
417dd7cddfSDavid du Colombier * we do minimal bookkeeping so we can tell pool
427dd7cddfSDavid du Colombier * whether two blocks are adjacent and thus mergeable.
437dd7cddfSDavid du Colombier */
447dd7cddfSDavid du Colombier static void*
sbrkalloc(ulong n)457dd7cddfSDavid du Colombier sbrkalloc(ulong n)
463e12c5d1SDavid du Colombier {
47810832d3SDavid du Colombier ulong *x;
483e12c5d1SDavid du Colombier
49810832d3SDavid du Colombier n += 2*sizeof(ulong); /* two longs for us */
507dd7cddfSDavid du Colombier x = sbrk(n);
5174f16c81SDavid du Colombier if(x == (void*)-1)
529a747e4fSDavid du Colombier return nil;
537dd7cddfSDavid du Colombier x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */
547dd7cddfSDavid du Colombier x[1] = 0xDeadBeef;
557dd7cddfSDavid du Colombier return x+2;
563e12c5d1SDavid du Colombier }
573e12c5d1SDavid du Colombier
587dd7cddfSDavid du Colombier static int
sbrkmerge(void * x,void * y)597dd7cddfSDavid du Colombier sbrkmerge(void *x, void *y)
607dd7cddfSDavid du Colombier {
61810832d3SDavid du Colombier ulong *lx, *ly;
623e12c5d1SDavid du Colombier
637dd7cddfSDavid du Colombier lx = x;
647dd7cddfSDavid du Colombier if(lx[-1] != 0xDeadBeef)
653e12c5d1SDavid du Colombier abort();
663e12c5d1SDavid du Colombier
677dd7cddfSDavid du Colombier if((uchar*)lx+lx[-2] == (uchar*)y) {
687dd7cddfSDavid du Colombier ly = y;
697dd7cddfSDavid du Colombier lx[-2] += ly[-2];
707dd7cddfSDavid du Colombier return 1;
713e12c5d1SDavid du Colombier }
727dd7cddfSDavid du Colombier return 0;
733e12c5d1SDavid du Colombier }
743e12c5d1SDavid du Colombier
757dd7cddfSDavid du Colombier static void
plock(Pool * p)767dd7cddfSDavid du Colombier plock(Pool *p)
777dd7cddfSDavid du Colombier {
787dd7cddfSDavid du Colombier Private *pv;
797dd7cddfSDavid du Colombier pv = p->private;
807dd7cddfSDavid du Colombier lock(&pv->lk);
81b85a8364SDavid du Colombier if(pv->pid != 0)
82b85a8364SDavid du Colombier abort();
83b85a8364SDavid du Colombier pv->pid = _tos->pid;
847dd7cddfSDavid du Colombier }
853e12c5d1SDavid du Colombier
867dd7cddfSDavid du Colombier static void
punlock(Pool * p)877dd7cddfSDavid du Colombier punlock(Pool *p)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier Private *pv;
907dd7cddfSDavid du Colombier pv = p->private;
91b85a8364SDavid du Colombier if(pv->pid != _tos->pid)
92b85a8364SDavid du Colombier abort();
93b85a8364SDavid du Colombier pv->pid = 0;
947dd7cddfSDavid du Colombier unlock(&pv->lk);
957dd7cddfSDavid du Colombier }
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier static int
checkenv(void)987dd7cddfSDavid du Colombier checkenv(void)
997dd7cddfSDavid du Colombier {
1007dd7cddfSDavid du Colombier int n, fd;
1017dd7cddfSDavid du Colombier char buf[20];
1027dd7cddfSDavid du Colombier fd = open("/env/MALLOCFD", OREAD);
1037dd7cddfSDavid du Colombier if(fd < 0)
1047dd7cddfSDavid du Colombier return -1;
1057dd7cddfSDavid du Colombier if((n = read(fd, buf, sizeof buf)) < 0) {
1067dd7cddfSDavid du Colombier close(fd);
1077dd7cddfSDavid du Colombier return -1;
1087dd7cddfSDavid du Colombier }
1097dd7cddfSDavid du Colombier if(n >= sizeof buf)
1107dd7cddfSDavid du Colombier n = sizeof(buf)-1;
1117dd7cddfSDavid du Colombier buf[n] = 0;
1127dd7cddfSDavid du Colombier n = atoi(buf);
1137dd7cddfSDavid du Colombier if(n == 0)
1147dd7cddfSDavid du Colombier n = -1;
1157dd7cddfSDavid du Colombier return n;
1167dd7cddfSDavid du Colombier }
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier static void
pprint(Pool * p,char * fmt,...)1197dd7cddfSDavid du Colombier pprint(Pool *p, char *fmt, ...)
1207dd7cddfSDavid du Colombier {
1217dd7cddfSDavid du Colombier va_list v;
1227dd7cddfSDavid du Colombier Private *pv;
1237dd7cddfSDavid du Colombier
1247dd7cddfSDavid du Colombier pv = p->private;
1257dd7cddfSDavid du Colombier if(pv->printfd == 0)
1267dd7cddfSDavid du Colombier pv->printfd = checkenv();
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier if(pv->printfd <= 0)
1297dd7cddfSDavid du Colombier pv->printfd = 2;
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier va_start(v, fmt);
1329a747e4fSDavid du Colombier vfprint(pv->printfd, fmt, v);
1337dd7cddfSDavid du Colombier va_end(v);
1347dd7cddfSDavid du Colombier }
1357dd7cddfSDavid du Colombier
1367dd7cddfSDavid du Colombier static char panicbuf[256];
1377dd7cddfSDavid du Colombier static void
ppanic(Pool * p,char * fmt,...)1387dd7cddfSDavid du Colombier ppanic(Pool *p, char *fmt, ...)
1397dd7cddfSDavid du Colombier {
1407dd7cddfSDavid du Colombier va_list v;
1417dd7cddfSDavid du Colombier int n;
1427dd7cddfSDavid du Colombier char *msg;
1437dd7cddfSDavid du Colombier Private *pv;
1447dd7cddfSDavid du Colombier
1457dd7cddfSDavid du Colombier pv = p->private;
1467dd7cddfSDavid du Colombier assert(canlock(&pv->lk)==0);
1477dd7cddfSDavid du Colombier
1487dd7cddfSDavid du Colombier if(pv->printfd == 0)
1497dd7cddfSDavid du Colombier pv->printfd = checkenv();
1507dd7cddfSDavid du Colombier if(pv->printfd <= 0)
1517dd7cddfSDavid du Colombier pv->printfd = 2;
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier msg = panicbuf;
1547dd7cddfSDavid du Colombier va_start(v, fmt);
1559a747e4fSDavid du Colombier n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg;
1567dd7cddfSDavid du Colombier write(2, "panic: ", 7);
1577dd7cddfSDavid du Colombier write(2, msg, n);
1587dd7cddfSDavid du Colombier write(2, "\n", 1);
1597dd7cddfSDavid du Colombier if(pv->printfd != 2){
1607dd7cddfSDavid du Colombier write(pv->printfd, "panic: ", 7);
1617dd7cddfSDavid du Colombier write(pv->printfd, msg, n);
1627dd7cddfSDavid du Colombier write(pv->printfd, "\n", 1);
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier va_end(v);
165b85a8364SDavid du Colombier // unlock(&pv->lk);
1667dd7cddfSDavid du Colombier abort();
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier /* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */
1707dd7cddfSDavid du Colombier /* - except the code for malloc(), which alternately doesn't clear or does. - */
1717dd7cddfSDavid du Colombier
1727dd7cddfSDavid du Colombier /*
1737dd7cddfSDavid du Colombier * Npadlong is the number of 32-bit longs to leave at the beginning of
1747dd7cddfSDavid du Colombier * each allocated buffer for our own bookkeeping. We return to the callers
1757dd7cddfSDavid du Colombier * a pointer that points immediately after our bookkeeping area. Incoming pointers
1767dd7cddfSDavid du Colombier * must be decremented by that much, and outgoing pointers incremented.
1777dd7cddfSDavid du Colombier * The malloc tag is stored at MallocOffset from the beginning of the block,
1787dd7cddfSDavid du Colombier * and the realloc tag at ReallocOffset. The offsets are from the true beginning
1797dd7cddfSDavid du Colombier * of the block, not the beginning the caller sees.
1807dd7cddfSDavid du Colombier *
1817dd7cddfSDavid du Colombier * The extra if(Npadlong != 0) in various places is a hint for the compiler to
1827dd7cddfSDavid du Colombier * compile out function calls that would otherwise be no-ops.
1837dd7cddfSDavid du Colombier */
1847dd7cddfSDavid du Colombier
1857dd7cddfSDavid du Colombier /* non tracing
1867dd7cddfSDavid du Colombier *
1877dd7cddfSDavid du Colombier enum {
1887dd7cddfSDavid du Colombier Npadlong = 0,
1897dd7cddfSDavid du Colombier MallocOffset = 0,
1907dd7cddfSDavid du Colombier ReallocOffset = 0,
1917dd7cddfSDavid du Colombier };
1927dd7cddfSDavid du Colombier *
1937dd7cddfSDavid du Colombier */
1947dd7cddfSDavid du Colombier
1957dd7cddfSDavid du Colombier /* tracing */
1967dd7cddfSDavid du Colombier enum {
1977dd7cddfSDavid du Colombier Npadlong = 2,
1987dd7cddfSDavid du Colombier MallocOffset = 0,
1997dd7cddfSDavid du Colombier ReallocOffset = 1
2007dd7cddfSDavid du Colombier };
2017dd7cddfSDavid du Colombier
2027dd7cddfSDavid du Colombier void*
malloc(ulong size)2037dd7cddfSDavid du Colombier malloc(ulong size)
2047dd7cddfSDavid du Colombier {
2057dd7cddfSDavid du Colombier void *v;
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
2087dd7cddfSDavid du Colombier if(Npadlong && v != nil) {
2097dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong;
2107dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size));
2117dd7cddfSDavid du Colombier setrealloctag(v, 0);
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier return v;
2143e12c5d1SDavid du Colombier }
2153e12c5d1SDavid du Colombier
2163e12c5d1SDavid du Colombier void*
mallocz(ulong size,int clr)2177dd7cddfSDavid du Colombier mallocz(ulong size, int clr)
2183e12c5d1SDavid du Colombier {
2197dd7cddfSDavid du Colombier void *v;
2203e12c5d1SDavid du Colombier
2217dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
2227dd7cddfSDavid du Colombier if(Npadlong && v != nil){
2237dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong;
2247dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size));
2257dd7cddfSDavid du Colombier setrealloctag(v, 0);
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier if(clr && v != nil)
2287dd7cddfSDavid du Colombier memset(v, 0, size);
2297dd7cddfSDavid du Colombier return v;
2303e12c5d1SDavid du Colombier }
2313e12c5d1SDavid du Colombier
2325243b8d1SDavid du Colombier void*
mallocalign(ulong size,ulong align,long offset,ulong span)2335243b8d1SDavid du Colombier mallocalign(ulong size, ulong align, long offset, ulong span)
2345243b8d1SDavid du Colombier {
2355243b8d1SDavid du Colombier void *v;
2365243b8d1SDavid du Colombier
2375243b8d1SDavid du Colombier v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
2385243b8d1SDavid du Colombier if(Npadlong && v != nil){
2395243b8d1SDavid du Colombier v = (ulong*)v+Npadlong;
2405243b8d1SDavid du Colombier setmalloctag(v, getcallerpc(&size));
2415243b8d1SDavid du Colombier setrealloctag(v, 0);
2425243b8d1SDavid du Colombier }
2435243b8d1SDavid du Colombier return v;
2445243b8d1SDavid du Colombier }
2455243b8d1SDavid du Colombier
2463e12c5d1SDavid du Colombier void
free(void * v)2477dd7cddfSDavid du Colombier free(void *v)
2483e12c5d1SDavid du Colombier {
2497dd7cddfSDavid du Colombier if(v != nil)
2507dd7cddfSDavid du Colombier poolfree(mainmem, (ulong*)v-Npadlong);
2513e12c5d1SDavid du Colombier }
2523e12c5d1SDavid du Colombier
2533e12c5d1SDavid du Colombier void*
realloc(void * v,ulong size)2547dd7cddfSDavid du Colombier realloc(void *v, ulong size)
2553e12c5d1SDavid du Colombier {
2567dd7cddfSDavid du Colombier void *nv;
2573e12c5d1SDavid du Colombier
2587dd7cddfSDavid du Colombier if(size == 0){
2597dd7cddfSDavid du Colombier free(v);
2607dd7cddfSDavid du Colombier return nil;
2617dd7cddfSDavid du Colombier }
2623e12c5d1SDavid du Colombier
2639a747e4fSDavid du Colombier if(v)
2647dd7cddfSDavid du Colombier v = (ulong*)v-Npadlong;
2657dd7cddfSDavid du Colombier size += Npadlong*sizeof(ulong);
2663e12c5d1SDavid du Colombier
2677dd7cddfSDavid du Colombier if(nv = poolrealloc(mainmem, v, size)){
2687dd7cddfSDavid du Colombier nv = (ulong*)nv+Npadlong;
2697dd7cddfSDavid du Colombier setrealloctag(nv, getcallerpc(&v));
2707dd7cddfSDavid du Colombier if(v == nil)
2717dd7cddfSDavid du Colombier setmalloctag(nv, getcallerpc(&v));
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier return nv;
2747dd7cddfSDavid du Colombier }
2753e12c5d1SDavid du Colombier
2767dd7cddfSDavid du Colombier ulong
msize(void * v)2777dd7cddfSDavid du Colombier msize(void *v)
2787dd7cddfSDavid du Colombier {
2797dd7cddfSDavid du Colombier return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
2807dd7cddfSDavid du Colombier }
2817dd7cddfSDavid du Colombier
2827dd7cddfSDavid du Colombier void*
calloc(ulong n,ulong szelem)2837dd7cddfSDavid du Colombier calloc(ulong n, ulong szelem)
2847dd7cddfSDavid du Colombier {
2857dd7cddfSDavid du Colombier void *v;
2867dd7cddfSDavid du Colombier if(v = mallocz(n*szelem, 1))
2877dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&n));
2887dd7cddfSDavid du Colombier return v;
2897dd7cddfSDavid du Colombier }
2907dd7cddfSDavid du Colombier
2917dd7cddfSDavid du Colombier void
setmalloctag(void * v,ulong pc)2927dd7cddfSDavid du Colombier setmalloctag(void *v, ulong pc)
2937dd7cddfSDavid du Colombier {
2947dd7cddfSDavid du Colombier ulong *u;
2957dd7cddfSDavid du Colombier USED(v, pc);
2967dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset || v == nil)
2977dd7cddfSDavid du Colombier return;
2987dd7cddfSDavid du Colombier u = v;
2997dd7cddfSDavid du Colombier u[-Npadlong+MallocOffset] = pc;
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier
3027dd7cddfSDavid du Colombier void
setrealloctag(void * v,ulong pc)3037dd7cddfSDavid du Colombier setrealloctag(void *v, ulong pc)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier ulong *u;
3067dd7cddfSDavid du Colombier USED(v, pc);
3077dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset || v == nil)
3087dd7cddfSDavid du Colombier return;
3097dd7cddfSDavid du Colombier u = v;
3107dd7cddfSDavid du Colombier u[-Npadlong+ReallocOffset] = pc;
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier
3137dd7cddfSDavid du Colombier ulong
getmalloctag(void * v)3147dd7cddfSDavid du Colombier getmalloctag(void *v)
3157dd7cddfSDavid du Colombier {
3167dd7cddfSDavid du Colombier USED(v);
3177dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset)
3187dd7cddfSDavid du Colombier return ~0;
3197dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+MallocOffset];
3207dd7cddfSDavid du Colombier }
3217dd7cddfSDavid du Colombier
3227dd7cddfSDavid du Colombier ulong
getrealloctag(void * v)3237dd7cddfSDavid du Colombier getrealloctag(void *v)
3247dd7cddfSDavid du Colombier {
3257dd7cddfSDavid du Colombier USED(v);
3267dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset)
3277dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+ReallocOffset];
3287dd7cddfSDavid du Colombier return ~0;
3297dd7cddfSDavid du Colombier }
3307dd7cddfSDavid du Colombier
3317dd7cddfSDavid du Colombier void*
malloctopoolblock(void * v)3327dd7cddfSDavid du Colombier malloctopoolblock(void *v)
3337dd7cddfSDavid du Colombier {
3347dd7cddfSDavid du Colombier if(v == nil)
3353e12c5d1SDavid du Colombier return nil;
3363e12c5d1SDavid du Colombier
3377dd7cddfSDavid du Colombier return &((ulong*)v)[-Npadlong];
3383e12c5d1SDavid du Colombier }
339