13e12c5d1SDavid du Colombier #include <u.h> 23e12c5d1SDavid du Colombier #include <libc.h> 3*7dd7cddfSDavid du Colombier #include <pool.h> 43e12c5d1SDavid du Colombier 5*7dd7cddfSDavid du Colombier static void* sbrkalloc(ulong); 6*7dd7cddfSDavid du Colombier static int sbrkmerge(void*, void*); 7*7dd7cddfSDavid du Colombier static void plock(Pool*); 8*7dd7cddfSDavid du Colombier static void punlock(Pool*); 9*7dd7cddfSDavid du Colombier static void pprint(Pool*, char*, ...); 10*7dd7cddfSDavid du Colombier static void ppanic(Pool*, char*, ...); 11*7dd7cddfSDavid du Colombier 12*7dd7cddfSDavid du Colombier typedef struct Private Private; 13*7dd7cddfSDavid du Colombier struct Private { 14*7dd7cddfSDavid du Colombier Lock lk; 15*7dd7cddfSDavid du Colombier int printfd; /* gets debugging output if set */ 163e12c5d1SDavid du Colombier }; 173e12c5d1SDavid du Colombier 18*7dd7cddfSDavid du Colombier Private sbrkmempriv; 19*7dd7cddfSDavid du Colombier 20*7dd7cddfSDavid du Colombier static Pool sbrkmem = { 21*7dd7cddfSDavid du Colombier .name= "sbrkmem", 22*7dd7cddfSDavid du Colombier .maxsize= 2*1024*1024*1024, 23*7dd7cddfSDavid du Colombier .minarena= 4*1024, 24*7dd7cddfSDavid du Colombier .quantum= 32, 25*7dd7cddfSDavid du Colombier .alloc= sbrkalloc, 26*7dd7cddfSDavid du Colombier .merge= sbrkmerge, 27*7dd7cddfSDavid du Colombier .flags= 0, 28*7dd7cddfSDavid du Colombier 29*7dd7cddfSDavid du Colombier .lock= plock, 30*7dd7cddfSDavid du Colombier .unlock= punlock, 31*7dd7cddfSDavid du Colombier .print= pprint, 32*7dd7cddfSDavid du Colombier .panic= ppanic, 33*7dd7cddfSDavid du Colombier .private= &sbrkmempriv, 343e12c5d1SDavid du Colombier }; 35*7dd7cddfSDavid du Colombier Pool *mainmem = &sbrkmem; 36*7dd7cddfSDavid du Colombier Pool *imagmem = &sbrkmem; 373e12c5d1SDavid du Colombier 38*7dd7cddfSDavid du Colombier /* 39*7dd7cddfSDavid du Colombier * we do minimal bookkeeping so we can tell pool 40*7dd7cddfSDavid du Colombier * whether two blocks are adjacent and thus mergeable. 41*7dd7cddfSDavid du Colombier */ 42*7dd7cddfSDavid du Colombier static void* 43*7dd7cddfSDavid du Colombier sbrkalloc(ulong n) 443e12c5d1SDavid du Colombier { 45*7dd7cddfSDavid du Colombier long *x; 463e12c5d1SDavid du Colombier 47*7dd7cddfSDavid du Colombier n += 8; /* two longs for us */ 48*7dd7cddfSDavid du Colombier x = sbrk(n); 49*7dd7cddfSDavid du Colombier if((int)x == -1) 50*7dd7cddfSDavid du Colombier x = nil; 51*7dd7cddfSDavid du Colombier x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */ 52*7dd7cddfSDavid du Colombier x[1] = 0xDeadBeef; 53*7dd7cddfSDavid du Colombier return x+2; 543e12c5d1SDavid du Colombier } 553e12c5d1SDavid du Colombier 56*7dd7cddfSDavid du Colombier static int 57*7dd7cddfSDavid du Colombier sbrkmerge(void *x, void *y) 58*7dd7cddfSDavid du Colombier { 59*7dd7cddfSDavid du Colombier long *lx, *ly; 603e12c5d1SDavid du Colombier 61*7dd7cddfSDavid du Colombier lx = x; 62*7dd7cddfSDavid du Colombier if(lx[-1] != 0xDeadBeef) 633e12c5d1SDavid du Colombier abort(); 643e12c5d1SDavid du Colombier 65*7dd7cddfSDavid du Colombier if((uchar*)lx+lx[-2] == (uchar*)y) { 66*7dd7cddfSDavid du Colombier ly = y; 67*7dd7cddfSDavid du Colombier lx[-2] += ly[-2]; 68*7dd7cddfSDavid du Colombier return 1; 693e12c5d1SDavid du Colombier } 70*7dd7cddfSDavid du Colombier return 0; 713e12c5d1SDavid du Colombier } 723e12c5d1SDavid du Colombier 73*7dd7cddfSDavid du Colombier static void 74*7dd7cddfSDavid du Colombier plock(Pool *p) 75*7dd7cddfSDavid du Colombier { 76*7dd7cddfSDavid du Colombier Private *pv; 77*7dd7cddfSDavid du Colombier pv = p->private; 78*7dd7cddfSDavid du Colombier lock(&pv->lk); 79*7dd7cddfSDavid du Colombier } 803e12c5d1SDavid du Colombier 81*7dd7cddfSDavid du Colombier static void 82*7dd7cddfSDavid du Colombier punlock(Pool *p) 83*7dd7cddfSDavid du Colombier { 84*7dd7cddfSDavid du Colombier Private *pv; 85*7dd7cddfSDavid du Colombier pv = p->private; 86*7dd7cddfSDavid du Colombier unlock(&pv->lk); 87*7dd7cddfSDavid du Colombier } 88*7dd7cddfSDavid du Colombier 89*7dd7cddfSDavid du Colombier static int 90*7dd7cddfSDavid du Colombier checkenv(void) 91*7dd7cddfSDavid du Colombier { 92*7dd7cddfSDavid du Colombier int n, fd; 93*7dd7cddfSDavid du Colombier char buf[20]; 94*7dd7cddfSDavid du Colombier fd = open("/env/MALLOCFD", OREAD); 95*7dd7cddfSDavid du Colombier if(fd < 0) 96*7dd7cddfSDavid du Colombier return -1; 97*7dd7cddfSDavid du Colombier if((n = read(fd, buf, sizeof buf)) < 0) { 98*7dd7cddfSDavid du Colombier close(fd); 99*7dd7cddfSDavid du Colombier return -1; 100*7dd7cddfSDavid du Colombier } 101*7dd7cddfSDavid du Colombier if(n >= sizeof buf) 102*7dd7cddfSDavid du Colombier n = sizeof(buf)-1; 103*7dd7cddfSDavid du Colombier buf[n] = 0; 104*7dd7cddfSDavid du Colombier n = atoi(buf); 105*7dd7cddfSDavid du Colombier if(n == 0) 106*7dd7cddfSDavid du Colombier n = -1; 107*7dd7cddfSDavid du Colombier return n; 108*7dd7cddfSDavid du Colombier } 109*7dd7cddfSDavid du Colombier 110*7dd7cddfSDavid du Colombier static void 111*7dd7cddfSDavid du Colombier pprint(Pool *p, char *fmt, ...) 112*7dd7cddfSDavid du Colombier { 113*7dd7cddfSDavid du Colombier va_list v; 114*7dd7cddfSDavid du Colombier int n; 115*7dd7cddfSDavid du Colombier char buf[128]; 116*7dd7cddfSDavid du Colombier char *msg; 117*7dd7cddfSDavid du Colombier Private *pv; 118*7dd7cddfSDavid du Colombier 119*7dd7cddfSDavid du Colombier pv = p->private; 120*7dd7cddfSDavid du Colombier if(pv->printfd == 0) 121*7dd7cddfSDavid du Colombier pv->printfd = checkenv(); 122*7dd7cddfSDavid du Colombier 123*7dd7cddfSDavid du Colombier if(pv->printfd <= 0) 124*7dd7cddfSDavid du Colombier pv->printfd = 2; 125*7dd7cddfSDavid du Colombier 126*7dd7cddfSDavid du Colombier msg = buf; 127*7dd7cddfSDavid du Colombier va_start(v, fmt); 128*7dd7cddfSDavid du Colombier n = doprint(buf, buf+sizeof buf, fmt, v)-msg; 129*7dd7cddfSDavid du Colombier write(pv->printfd, buf, n); 130*7dd7cddfSDavid du Colombier va_end(v); 131*7dd7cddfSDavid du Colombier } 132*7dd7cddfSDavid du Colombier 133*7dd7cddfSDavid du Colombier static char panicbuf[256]; 134*7dd7cddfSDavid du Colombier static void 135*7dd7cddfSDavid du Colombier ppanic(Pool *p, char *fmt, ...) 136*7dd7cddfSDavid du Colombier { 137*7dd7cddfSDavid du Colombier va_list v; 138*7dd7cddfSDavid du Colombier int n; 139*7dd7cddfSDavid du Colombier char *msg; 140*7dd7cddfSDavid du Colombier Private *pv; 141*7dd7cddfSDavid du Colombier 142*7dd7cddfSDavid du Colombier pv = p->private; 143*7dd7cddfSDavid du Colombier assert(canlock(&pv->lk)==0); 144*7dd7cddfSDavid du Colombier 145*7dd7cddfSDavid du Colombier if(pv->printfd == 0) 146*7dd7cddfSDavid du Colombier pv->printfd = checkenv(); 147*7dd7cddfSDavid du Colombier if(pv->printfd <= 0) 148*7dd7cddfSDavid du Colombier pv->printfd = 2; 149*7dd7cddfSDavid du Colombier 150*7dd7cddfSDavid du Colombier msg = panicbuf; 151*7dd7cddfSDavid du Colombier va_start(v, fmt); 152*7dd7cddfSDavid du Colombier n = doprint(msg, msg+sizeof panicbuf, fmt, v) - msg; 153*7dd7cddfSDavid du Colombier write(2, "panic: ", 7); 154*7dd7cddfSDavid du Colombier write(2, msg, n); 155*7dd7cddfSDavid du Colombier write(2, "\n", 1); 156*7dd7cddfSDavid du Colombier if(pv->printfd != 2){ 157*7dd7cddfSDavid du Colombier write(pv->printfd, "panic: ", 7); 158*7dd7cddfSDavid du Colombier write(pv->printfd, msg, n); 159*7dd7cddfSDavid du Colombier write(pv->printfd, "\n", 1); 160*7dd7cddfSDavid du Colombier } 161*7dd7cddfSDavid du Colombier va_end(v); 162*7dd7cddfSDavid du Colombier unlock(&pv->lk); 163*7dd7cddfSDavid du Colombier abort(); 164*7dd7cddfSDavid du Colombier } 165*7dd7cddfSDavid du Colombier 166*7dd7cddfSDavid du Colombier /* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */ 167*7dd7cddfSDavid du Colombier /* - except the code for malloc(), which alternately doesn't clear or does. - */ 168*7dd7cddfSDavid du Colombier 169*7dd7cddfSDavid du Colombier /* 170*7dd7cddfSDavid du Colombier * Npadlong is the number of 32-bit longs to leave at the beginning of 171*7dd7cddfSDavid du Colombier * each allocated buffer for our own bookkeeping. We return to the callers 172*7dd7cddfSDavid du Colombier * a pointer that points immediately after our bookkeeping area. Incoming pointers 173*7dd7cddfSDavid du Colombier * must be decremented by that much, and outgoing pointers incremented. 174*7dd7cddfSDavid du Colombier * The malloc tag is stored at MallocOffset from the beginning of the block, 175*7dd7cddfSDavid du Colombier * and the realloc tag at ReallocOffset. The offsets are from the true beginning 176*7dd7cddfSDavid du Colombier * of the block, not the beginning the caller sees. 177*7dd7cddfSDavid du Colombier * 178*7dd7cddfSDavid du Colombier * The extra if(Npadlong != 0) in various places is a hint for the compiler to 179*7dd7cddfSDavid du Colombier * compile out function calls that would otherwise be no-ops. 180*7dd7cddfSDavid du Colombier */ 181*7dd7cddfSDavid du Colombier 182*7dd7cddfSDavid du Colombier /* non tracing 183*7dd7cddfSDavid du Colombier * 184*7dd7cddfSDavid du Colombier enum { 185*7dd7cddfSDavid du Colombier Npadlong = 0, 186*7dd7cddfSDavid du Colombier MallocOffset = 0, 187*7dd7cddfSDavid du Colombier ReallocOffset = 0, 188*7dd7cddfSDavid du Colombier }; 189*7dd7cddfSDavid du Colombier * 190*7dd7cddfSDavid du Colombier */ 191*7dd7cddfSDavid du Colombier 192*7dd7cddfSDavid du Colombier /* tracing */ 193*7dd7cddfSDavid du Colombier enum { 194*7dd7cddfSDavid du Colombier Npadlong = 2, 195*7dd7cddfSDavid du Colombier MallocOffset = 0, 196*7dd7cddfSDavid du Colombier ReallocOffset = 1 197*7dd7cddfSDavid du Colombier }; 198*7dd7cddfSDavid du Colombier 199*7dd7cddfSDavid du Colombier void* 200*7dd7cddfSDavid du Colombier malloc(ulong size) 201*7dd7cddfSDavid du Colombier { 202*7dd7cddfSDavid du Colombier void *v; 203*7dd7cddfSDavid du Colombier 204*7dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 205*7dd7cddfSDavid du Colombier if(Npadlong && v != nil) { 206*7dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong; 207*7dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size)); 208*7dd7cddfSDavid du Colombier setrealloctag(v, 0); 209*7dd7cddfSDavid du Colombier } 210*7dd7cddfSDavid du Colombier return v; 2113e12c5d1SDavid du Colombier } 2123e12c5d1SDavid du Colombier 2133e12c5d1SDavid du Colombier void* 214*7dd7cddfSDavid du Colombier mallocz(ulong size, int clr) 2153e12c5d1SDavid du Colombier { 216*7dd7cddfSDavid du Colombier void *v; 2173e12c5d1SDavid du Colombier 218*7dd7cddfSDavid du Colombier v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 219*7dd7cddfSDavid du Colombier if(Npadlong && v != nil){ 220*7dd7cddfSDavid du Colombier v = (ulong*)v+Npadlong; 221*7dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&size)); 222*7dd7cddfSDavid du Colombier setrealloctag(v, 0); 223*7dd7cddfSDavid du Colombier } 224*7dd7cddfSDavid du Colombier if(clr && v != nil) 225*7dd7cddfSDavid du Colombier memset(v, 0, size); 226*7dd7cddfSDavid du Colombier return v; 2273e12c5d1SDavid du Colombier } 2283e12c5d1SDavid du Colombier 2293e12c5d1SDavid du Colombier void 230*7dd7cddfSDavid du Colombier free(void *v) 2313e12c5d1SDavid du Colombier { 232*7dd7cddfSDavid du Colombier if(v != nil) 233*7dd7cddfSDavid du Colombier poolfree(mainmem, (ulong*)v-Npadlong); 2343e12c5d1SDavid du Colombier } 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier void* 237*7dd7cddfSDavid du Colombier realloc(void *v, ulong size) 2383e12c5d1SDavid du Colombier { 239*7dd7cddfSDavid du Colombier void *nv; 2403e12c5d1SDavid du Colombier 241*7dd7cddfSDavid du Colombier if(v == nil) 242*7dd7cddfSDavid du Colombier return malloc(size); 2433e12c5d1SDavid du Colombier 244*7dd7cddfSDavid du Colombier if(size == 0){ 245*7dd7cddfSDavid du Colombier free(v); 246*7dd7cddfSDavid du Colombier return nil; 247*7dd7cddfSDavid du Colombier } 2483e12c5d1SDavid du Colombier 249*7dd7cddfSDavid du Colombier v = (ulong*)v-Npadlong; 250*7dd7cddfSDavid du Colombier size += Npadlong*sizeof(ulong); 2513e12c5d1SDavid du Colombier 252*7dd7cddfSDavid du Colombier if(nv = poolrealloc(mainmem, v, size)){ 253*7dd7cddfSDavid du Colombier nv = (ulong*)nv+Npadlong; 254*7dd7cddfSDavid du Colombier setrealloctag(nv, getcallerpc(&v)); 255*7dd7cddfSDavid du Colombier if(v == nil) 256*7dd7cddfSDavid du Colombier setmalloctag(nv, getcallerpc(&v)); 257*7dd7cddfSDavid du Colombier } 258*7dd7cddfSDavid du Colombier return nv; 259*7dd7cddfSDavid du Colombier } 2603e12c5d1SDavid du Colombier 261*7dd7cddfSDavid du Colombier ulong 262*7dd7cddfSDavid du Colombier msize(void *v) 263*7dd7cddfSDavid du Colombier { 264*7dd7cddfSDavid du Colombier return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 265*7dd7cddfSDavid du Colombier } 266*7dd7cddfSDavid du Colombier 267*7dd7cddfSDavid du Colombier void* 268*7dd7cddfSDavid du Colombier calloc(ulong n, ulong szelem) 269*7dd7cddfSDavid du Colombier { 270*7dd7cddfSDavid du Colombier void *v; 271*7dd7cddfSDavid du Colombier if(v = mallocz(n*szelem, 1)) 272*7dd7cddfSDavid du Colombier setmalloctag(v, getcallerpc(&n)); 273*7dd7cddfSDavid du Colombier return v; 274*7dd7cddfSDavid du Colombier } 275*7dd7cddfSDavid du Colombier 276*7dd7cddfSDavid du Colombier void 277*7dd7cddfSDavid du Colombier setmalloctag(void *v, ulong pc) 278*7dd7cddfSDavid du Colombier { 279*7dd7cddfSDavid du Colombier ulong *u; 280*7dd7cddfSDavid du Colombier USED(v, pc); 281*7dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset || v == nil) 282*7dd7cddfSDavid du Colombier return; 283*7dd7cddfSDavid du Colombier u = v; 284*7dd7cddfSDavid du Colombier u[-Npadlong+MallocOffset] = pc; 285*7dd7cddfSDavid du Colombier } 286*7dd7cddfSDavid du Colombier 287*7dd7cddfSDavid du Colombier void 288*7dd7cddfSDavid du Colombier setrealloctag(void *v, ulong pc) 289*7dd7cddfSDavid du Colombier { 290*7dd7cddfSDavid du Colombier ulong *u; 291*7dd7cddfSDavid du Colombier USED(v, pc); 292*7dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset || v == nil) 293*7dd7cddfSDavid du Colombier return; 294*7dd7cddfSDavid du Colombier u = v; 295*7dd7cddfSDavid du Colombier u[-Npadlong+ReallocOffset] = pc; 296*7dd7cddfSDavid du Colombier } 297*7dd7cddfSDavid du Colombier 298*7dd7cddfSDavid du Colombier ulong 299*7dd7cddfSDavid du Colombier getmalloctag(void *v) 300*7dd7cddfSDavid du Colombier { 301*7dd7cddfSDavid du Colombier USED(v); 302*7dd7cddfSDavid du Colombier if(Npadlong <= MallocOffset) 303*7dd7cddfSDavid du Colombier return ~0; 304*7dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+MallocOffset]; 305*7dd7cddfSDavid du Colombier } 306*7dd7cddfSDavid du Colombier 307*7dd7cddfSDavid du Colombier ulong 308*7dd7cddfSDavid du Colombier getrealloctag(void *v) 309*7dd7cddfSDavid du Colombier { 310*7dd7cddfSDavid du Colombier USED(v); 311*7dd7cddfSDavid du Colombier if(Npadlong <= ReallocOffset) 312*7dd7cddfSDavid du Colombier return ((ulong*)v)[-Npadlong+ReallocOffset]; 313*7dd7cddfSDavid du Colombier return ~0; 314*7dd7cddfSDavid du Colombier } 315*7dd7cddfSDavid du Colombier 316*7dd7cddfSDavid du Colombier void* 317*7dd7cddfSDavid du Colombier malloctopoolblock(void *v) 318*7dd7cddfSDavid du Colombier { 319*7dd7cddfSDavid du Colombier if(v == nil) 3203e12c5d1SDavid du Colombier return nil; 3213e12c5d1SDavid du Colombier 322*7dd7cddfSDavid du Colombier return &((ulong*)v)[-Npadlong]; 3233e12c5d1SDavid du Colombier } 324