13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 37dd7cddfSDavid du Colombier #include <pool.h> 4*b85a8364SDavid 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; 16*b85a8364SDavid 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", 2414414594SDavid du Colombier .maxsize= 2UL*1024*1024*1024, 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* 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 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 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); 81*b85a8364SDavid du Colombier if(pv->pid != 0) 82*b85a8364SDavid du Colombier abort(); 83*b85a8364SDavid du Colombier pv->pid = _tos->pid; 847dd7cddfSDavid du Colombier } 853e12c5d1SDavid du Colombier 867dd7cddfSDavid du Colombier static void 877dd7cddfSDavid du Colombier punlock(Pool *p) 887dd7cddfSDavid du Colombier { 897dd7cddfSDavid du Colombier Private *pv; 907dd7cddfSDavid du Colombier pv = p->private; 91*b85a8364SDavid du Colombier if(pv->pid != _tos->pid) 92*b85a8364SDavid du Colombier abort(); 93*b85a8364SDavid du Colombier pv->pid = 0; 947dd7cddfSDavid du Colombier unlock(&pv->lk); 957dd7cddfSDavid du Colombier } 967dd7cddfSDavid du Colombier 977dd7cddfSDavid du Colombier static int 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 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 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); 165*b85a8364SDavid 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* 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* 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* 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 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* 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 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* 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 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 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 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 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* 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