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