13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <pool.h> 43e12c5d1SDavid du Colombier 57dd7cddfSDavid du Colombier static void* sbrkalloc(ulong); 67dd7cddfSDavid du Colombier static int sbrkmerge(void*, void*); 77dd7cddfSDavid du Colombier static void plock(Pool*); 87dd7cddfSDavid du Colombier static void punlock(Pool*); 97dd7cddfSDavid du Colombier static void pprint(Pool*, char*, ...); 107dd7cddfSDavid du Colombier static void ppanic(Pool*, char*, ...); 117dd7cddfSDavid du Colombier 127dd7cddfSDavid du Colombier typedef struct Private Private; 137dd7cddfSDavid du Colombier struct Private { 147dd7cddfSDavid du Colombier Lock lk; 157dd7cddfSDavid du Colombier int printfd; /* gets debugging output if set */ 163e12c5d1SDavid du Colombier }; 173e12c5d1SDavid du Colombier 187dd7cddfSDavid du Colombier Private sbrkmempriv; 197dd7cddfSDavid du Colombier 207dd7cddfSDavid du Colombier static Pool sbrkmem = { 217dd7cddfSDavid du Colombier .name= "sbrkmem", 22*14414594SDavid du Colombier .maxsize= 2UL*1024*1024*1024, 237dd7cddfSDavid du Colombier .minarena= 4*1024, 247dd7cddfSDavid du Colombier .quantum= 32, 257dd7cddfSDavid du Colombier .alloc= sbrkalloc, 267dd7cddfSDavid du Colombier .merge= sbrkmerge, 277dd7cddfSDavid du Colombier .flags= 0, 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier .lock= plock, 307dd7cddfSDavid du Colombier .unlock= punlock, 317dd7cddfSDavid du Colombier .print= pprint, 327dd7cddfSDavid du Colombier .panic= ppanic, 337dd7cddfSDavid du Colombier .private= &sbrkmempriv, 343e12c5d1SDavid du Colombier }; 357dd7cddfSDavid du Colombier Pool *mainmem = &sbrkmem; 367dd7cddfSDavid du Colombier Pool *imagmem = &sbrkmem; 373e12c5d1SDavid du Colombier 387dd7cddfSDavid du Colombier /* 397dd7cddfSDavid du Colombier * we do minimal bookkeeping so we can tell pool 407dd7cddfSDavid du Colombier * whether two blocks are adjacent and thus mergeable. 417dd7cddfSDavid du Colombier */ 427dd7cddfSDavid du Colombier static void* 437dd7cddfSDavid du Colombier sbrkalloc(ulong n) 443e12c5d1SDavid du Colombier { 457dd7cddfSDavid du Colombier long *x; 463e12c5d1SDavid du Colombier 477dd7cddfSDavid du Colombier n += 8; /* two longs for us */ 487dd7cddfSDavid du Colombier x = sbrk(n); 497dd7cddfSDavid du Colombier if((int)x == -1) 507dd7cddfSDavid du Colombier x = nil; 517dd7cddfSDavid du Colombier x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */ 527dd7cddfSDavid du Colombier x[1] = 0xDeadBeef; 537dd7cddfSDavid du Colombier return x+2; 543e12c5d1SDavid du Colombier } 553e12c5d1SDavid du Colombier 567dd7cddfSDavid du Colombier static int 577dd7cddfSDavid du Colombier sbrkmerge(void *x, void *y) 587dd7cddfSDavid du Colombier { 597dd7cddfSDavid du Colombier long *lx, *ly; 603e12c5d1SDavid du Colombier 617dd7cddfSDavid du Colombier lx = x; 627dd7cddfSDavid du Colombier if(lx[-1] != 0xDeadBeef) 633e12c5d1SDavid du Colombier abort(); 643e12c5d1SDavid du Colombier 657dd7cddfSDavid du Colombier if((uchar*)lx+lx[-2] == (uchar*)y) { 667dd7cddfSDavid du Colombier ly = y; 677dd7cddfSDavid du Colombier lx[-2] += ly[-2]; 687dd7cddfSDavid du Colombier return 1; 693e12c5d1SDavid du Colombier } 707dd7cddfSDavid du Colombier return 0; 713e12c5d1SDavid du Colombier } 723e12c5d1SDavid du Colombier 737dd7cddfSDavid du Colombier static void 747dd7cddfSDavid du Colombier plock(Pool *p) 757dd7cddfSDavid du Colombier { 767dd7cddfSDavid du Colombier Private *pv; 777dd7cddfSDavid du Colombier pv = p->private; 787dd7cddfSDavid du Colombier lock(&pv->lk); 797dd7cddfSDavid du Colombier } 803e12c5d1SDavid du Colombier 817dd7cddfSDavid du Colombier static void 827dd7cddfSDavid du Colombier punlock(Pool *p) 837dd7cddfSDavid du Colombier { 847dd7cddfSDavid du Colombier Private *pv; 857dd7cddfSDavid du Colombier pv = p->private; 867dd7cddfSDavid du Colombier unlock(&pv->lk); 877dd7cddfSDavid du Colombier } 887dd7cddfSDavid du Colombier 897dd7cddfSDavid du Colombier static int 907dd7cddfSDavid du Colombier checkenv(void) 917dd7cddfSDavid du Colombier { 927dd7cddfSDavid du Colombier int n, fd; 937dd7cddfSDavid du Colombier char buf[20]; 947dd7cddfSDavid du Colombier fd = open("/env/MALLOCFD", OREAD); 957dd7cddfSDavid du Colombier if(fd < 0) 967dd7cddfSDavid du Colombier return -1; 977dd7cddfSDavid du Colombier if((n = read(fd, buf, sizeof buf)) < 0) { 987dd7cddfSDavid du Colombier close(fd); 997dd7cddfSDavid du Colombier return -1; 1007dd7cddfSDavid du Colombier } 1017dd7cddfSDavid du Colombier if(n >= sizeof buf) 1027dd7cddfSDavid du Colombier n = sizeof(buf)-1; 1037dd7cddfSDavid du Colombier buf[n] = 0; 1047dd7cddfSDavid du Colombier n = atoi(buf); 1057dd7cddfSDavid du Colombier if(n == 0) 1067dd7cddfSDavid du Colombier n = -1; 1077dd7cddfSDavid du Colombier return n; 1087dd7cddfSDavid du Colombier } 1097dd7cddfSDavid du Colombier 1107dd7cddfSDavid du Colombier static void 1117dd7cddfSDavid du Colombier pprint(Pool *p, char *fmt, ...) 1127dd7cddfSDavid du Colombier { 1137dd7cddfSDavid du Colombier va_list v; 1147dd7cddfSDavid du Colombier int n; 1157dd7cddfSDavid du Colombier char buf[128]; 1167dd7cddfSDavid du Colombier char *msg; 1177dd7cddfSDavid du Colombier Private *pv; 1187dd7cddfSDavid du Colombier 1197dd7cddfSDavid du Colombier pv = p->private; 1207dd7cddfSDavid du Colombier if(pv->printfd == 0) 1217dd7cddfSDavid du Colombier pv->printfd = checkenv(); 1227dd7cddfSDavid du Colombier 1237dd7cddfSDavid du Colombier if(pv->printfd <= 0) 1247dd7cddfSDavid du Colombier pv->printfd = 2; 1257dd7cddfSDavid du Colombier 1267dd7cddfSDavid du Colombier msg = buf; 1277dd7cddfSDavid du Colombier va_start(v, fmt); 1287dd7cddfSDavid du Colombier n = doprint(buf, buf+sizeof buf, fmt, v)-msg; 1297dd7cddfSDavid du Colombier write(pv->printfd, buf, n); 1307dd7cddfSDavid du Colombier va_end(v); 1317dd7cddfSDavid du Colombier } 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier static char panicbuf[256]; 1347dd7cddfSDavid du Colombier static void 1357dd7cddfSDavid du Colombier ppanic(Pool *p, char *fmt, ...) 1367dd7cddfSDavid du Colombier { 1377dd7cddfSDavid du Colombier va_list v; 1387dd7cddfSDavid du Colombier int n; 1397dd7cddfSDavid du Colombier char *msg; 1407dd7cddfSDavid du Colombier Private *pv; 1417dd7cddfSDavid du Colombier 1427dd7cddfSDavid du Colombier pv = p->private; 1437dd7cddfSDavid du Colombier assert(canlock(&pv->lk)==0); 1447dd7cddfSDavid du Colombier 1457dd7cddfSDavid du Colombier if(pv->printfd == 0) 1467dd7cddfSDavid du Colombier pv->printfd = checkenv(); 1477dd7cddfSDavid du Colombier if(pv->printfd <= 0) 1487dd7cddfSDavid du Colombier pv->printfd = 2; 1497dd7cddfSDavid du Colombier 1507dd7cddfSDavid du Colombier msg = panicbuf; 1517dd7cddfSDavid du Colombier va_start(v, fmt); 1527dd7cddfSDavid du Colombier n = doprint(msg, msg+sizeof panicbuf, fmt, v) - msg; 1537dd7cddfSDavid du Colombier write(2, "panic: ", 7); 1547dd7cddfSDavid du Colombier write(2, msg, n); 1557dd7cddfSDavid du Colombier write(2, "\n", 1); 1567dd7cddfSDavid du Colombier if(pv->printfd != 2){ 1577dd7cddfSDavid du Colombier write(pv->printfd, "panic: ", 7); 1587dd7cddfSDavid du Colombier write(pv->printfd, msg, n); 1597dd7cddfSDavid du Colombier write(pv->printfd, "\n", 1); 1607dd7cddfSDavid du Colombier } 1617dd7cddfSDavid du Colombier va_end(v); 1627dd7cddfSDavid du Colombier unlock(&pv->lk); 1637dd7cddfSDavid du Colombier abort(); 1647dd7cddfSDavid du Colombier } 1657dd7cddfSDavid du Colombier 1667dd7cddfSDavid du Colombier /* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */ 1677dd7cddfSDavid du Colombier /* - except the code for malloc(), which alternately doesn't clear or does. - */ 1687dd7cddfSDavid du Colombier 1697dd7cddfSDavid du Colombier /* 1707dd7cddfSDavid du Colombier * Npadlong is the number of 32-bit longs to leave at the beginning of 1717dd7cddfSDavid du Colombier * each allocated buffer for our own bookkeeping. We return to the callers 1727dd7cddfSDavid du Colombier * a pointer that points immediately after our bookkeeping area. Incoming pointers 1737dd7cddfSDavid du Colombier * must be decremented by that much, and outgoing pointers incremented. 1747dd7cddfSDavid du Colombier * The malloc tag is stored at MallocOffset from the beginning of the block, 1757dd7cddfSDavid du Colombier * and the realloc tag at ReallocOffset. The offsets are from the true beginning 1767dd7cddfSDavid du Colombier * of the block, not the beginning the caller sees. 1777dd7cddfSDavid du Colombier * 1787dd7cddfSDavid du Colombier * The extra if(Npadlong != 0) in various places is a hint for the compiler to 1797dd7cddfSDavid du Colombier * compile out function calls that would otherwise be no-ops. 1807dd7cddfSDavid du Colombier */ 1817dd7cddfSDavid du Colombier 1827dd7cddfSDavid du Colombier /* non tracing 1837dd7cddfSDavid du Colombier * 1847dd7cddfSDavid du Colombier enum { 1857dd7cddfSDavid du Colombier Npadlong = 0, 1867dd7cddfSDavid du Colombier MallocOffset = 0, 1877dd7cddfSDavid du Colombier ReallocOffset = 0, 1887dd7cddfSDavid du Colombier }; 1897dd7cddfSDavid du Colombier * 1907dd7cddfSDavid du Colombier */ 1917dd7cddfSDavid du Colombier 1927dd7cddfSDavid du Colombier /* tracing */ 1937dd7cddfSDavid du Colombier enum { 1947dd7cddfSDavid du Colombier Npadlong = 2, 1957dd7cddfSDavid du Colombier MallocOffset = 0, 1967dd7cddfSDavid du Colombier ReallocOffset = 1 1977dd7cddfSDavid du Colombier }; 1987dd7cddfSDavid du Colombier 1997dd7cddfSDavid du Colombier void* 2007dd7cddfSDavid du Colombier malloc(ulong size) 2017dd7cddfSDavid du Colombier { 2027dd7cddfSDavid du Colombier void *v; 2037dd7cddfSDavid du Colombier 2047dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 2057dd7cddfSDavid du Colombier if(Npadlong && v != nil) { 2067dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong; 2077dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size)); 2087dd7cddfSDavid du Colombier setrealloctag(v, 0); 2097dd7cddfSDavid du Colombier } 2107dd7cddfSDavid du Colombier return v; 2113e12c5d1SDavid du Colombier } 2123e12c5d1SDavid du Colombier 2133e12c5d1SDavid du Colombier void* 2147dd7cddfSDavid du Colombier mallocz(ulong size, int clr) 2153e12c5d1SDavid du Colombier { 2167dd7cddfSDavid du Colombier void *v; 2173e12c5d1SDavid du Colombier 2187dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 2197dd7cddfSDavid du Colombier if(Npadlong && v != nil){ 2207dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong; 2217dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size)); 2227dd7cddfSDavid du Colombier setrealloctag(v, 0); 2237dd7cddfSDavid du Colombier } 2247dd7cddfSDavid du Colombier if(clr && v != nil) 2257dd7cddfSDavid du Colombier memset(v, 0, size); 2267dd7cddfSDavid du Colombier return v; 2273e12c5d1SDavid du Colombier } 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier void 2307dd7cddfSDavid du Colombier free(void *v) 2313e12c5d1SDavid du Colombier { 2327dd7cddfSDavid du Colombier if(v != nil) 2337dd7cddfSDavid du Colombier poolfree(mainmem, (ulong*)v-Npadlong); 2343e12c5d1SDavid du Colombier } 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier void* 2377dd7cddfSDavid du Colombier realloc(void *v, ulong size) 2383e12c5d1SDavid du Colombier { 2397dd7cddfSDavid du Colombier void *nv; 2403e12c5d1SDavid du Colombier 2417dd7cddfSDavid du Colombier if(v == nil) 2427dd7cddfSDavid du Colombier return malloc(size); 2433e12c5d1SDavid du Colombier 2447dd7cddfSDavid du Colombier if(size == 0){ 2457dd7cddfSDavid du Colombier free(v); 2467dd7cddfSDavid du Colombier return nil; 2477dd7cddfSDavid du Colombier } 2483e12c5d1SDavid du Colombier 2497dd7cddfSDavid du Colombier v = (ulong*)v-Npadlong; 2507dd7cddfSDavid du Colombier size += Npadlong*sizeof(ulong); 2513e12c5d1SDavid du Colombier 2527dd7cddfSDavid du Colombier if(nv = poolrealloc(mainmem, v, size)){ 2537dd7cddfSDavid du Colombier nv = (ulong*)nv+Npadlong; 2547dd7cddfSDavid du Colombier setrealloctag(nv, getcallerpc(&v)); 2557dd7cddfSDavid du Colombier if(v == nil) 2567dd7cddfSDavid du Colombier setmalloctag(nv, getcallerpc(&v)); 2577dd7cddfSDavid du Colombier } 2587dd7cddfSDavid du Colombier return nv; 2597dd7cddfSDavid du Colombier } 2603e12c5d1SDavid du Colombier 2617dd7cddfSDavid du Colombier ulong 2627dd7cddfSDavid du Colombier msize(void *v) 2637dd7cddfSDavid du Colombier { 2647dd7cddfSDavid du Colombier return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 2657dd7cddfSDavid du Colombier } 2667dd7cddfSDavid du Colombier 2677dd7cddfSDavid du Colombier void* 2687dd7cddfSDavid du Colombier calloc(ulong n, ulong szelem) 2697dd7cddfSDavid du Colombier { 2707dd7cddfSDavid du Colombier void *v; 2717dd7cddfSDavid du Colombier if(v = mallocz(n*szelem, 1)) 2727dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&n)); 2737dd7cddfSDavid du Colombier return v; 2747dd7cddfSDavid du Colombier } 2757dd7cddfSDavid du Colombier 2767dd7cddfSDavid du Colombier void 2777dd7cddfSDavid du Colombier setmalloctag(void *v, ulong pc) 2787dd7cddfSDavid du Colombier { 2797dd7cddfSDavid du Colombier ulong *u; 2807dd7cddfSDavid du Colombier USED(v, pc); 2817dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset || v == nil) 2827dd7cddfSDavid du Colombier return; 2837dd7cddfSDavid du Colombier u = v; 2847dd7cddfSDavid du Colombier u[-Npadlong+MallocOffset] = pc; 2857dd7cddfSDavid du Colombier } 2867dd7cddfSDavid du Colombier 2877dd7cddfSDavid du Colombier void 2887dd7cddfSDavid du Colombier setrealloctag(void *v, ulong pc) 2897dd7cddfSDavid du Colombier { 2907dd7cddfSDavid du Colombier ulong *u; 2917dd7cddfSDavid du Colombier USED(v, pc); 2927dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset || v == nil) 2937dd7cddfSDavid du Colombier return; 2947dd7cddfSDavid du Colombier u = v; 2957dd7cddfSDavid du Colombier u[-Npadlong+ReallocOffset] = pc; 2967dd7cddfSDavid du Colombier } 2977dd7cddfSDavid du Colombier 2987dd7cddfSDavid du Colombier ulong 2997dd7cddfSDavid du Colombier getmalloctag(void *v) 3007dd7cddfSDavid du Colombier { 3017dd7cddfSDavid du Colombier USED(v); 3027dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset) 3037dd7cddfSDavid du Colombier return ~0; 3047dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+MallocOffset]; 3057dd7cddfSDavid du Colombier } 3067dd7cddfSDavid du Colombier 3077dd7cddfSDavid du Colombier ulong 3087dd7cddfSDavid du Colombier getrealloctag(void *v) 3097dd7cddfSDavid du Colombier { 3107dd7cddfSDavid du Colombier USED(v); 3117dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset) 3127dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+ReallocOffset]; 3137dd7cddfSDavid du Colombier return ~0; 3147dd7cddfSDavid du Colombier } 3157dd7cddfSDavid du Colombier 3167dd7cddfSDavid du Colombier void* 3177dd7cddfSDavid du Colombier malloctopoolblock(void *v) 3187dd7cddfSDavid du Colombier { 3197dd7cddfSDavid du Colombier if(v == nil) 3203e12c5d1SDavid du Colombier return nil; 3213e12c5d1SDavid du Colombier 3227dd7cddfSDavid du Colombier return &((ulong*)v)[-Npadlong]; 3233e12c5d1SDavid du Colombier } 324