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 long *x; 46 47 n += 8; /* two longs for us */ 48 x = sbrk(n); 49 if((int)x == -1) 50 x = 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 long *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 int n; 115 char buf[128]; 116 char *msg; 117 Private *pv; 118 119 pv = p->private; 120 if(pv->printfd == 0) 121 pv->printfd = checkenv(); 122 123 if(pv->printfd <= 0) 124 pv->printfd = 2; 125 126 msg = buf; 127 va_start(v, fmt); 128 n = doprint(buf, buf+sizeof buf, fmt, v)-msg; 129 write(pv->printfd, buf, n); 130 va_end(v); 131 } 132 133 static char panicbuf[256]; 134 static void 135 ppanic(Pool *p, char *fmt, ...) 136 { 137 va_list v; 138 int n; 139 char *msg; 140 Private *pv; 141 142 pv = p->private; 143 assert(canlock(&pv->lk)==0); 144 145 if(pv->printfd == 0) 146 pv->printfd = checkenv(); 147 if(pv->printfd <= 0) 148 pv->printfd = 2; 149 150 msg = panicbuf; 151 va_start(v, fmt); 152 n = doprint(msg, msg+sizeof panicbuf, fmt, v) - msg; 153 write(2, "panic: ", 7); 154 write(2, msg, n); 155 write(2, "\n", 1); 156 if(pv->printfd != 2){ 157 write(pv->printfd, "panic: ", 7); 158 write(pv->printfd, msg, n); 159 write(pv->printfd, "\n", 1); 160 } 161 va_end(v); 162 unlock(&pv->lk); 163 abort(); 164 } 165 166 /* - everything from here down should be the same in libc, libdebugmalloc, and the kernel - */ 167 /* - except the code for malloc(), which alternately doesn't clear or does. - */ 168 169 /* 170 * Npadlong is the number of 32-bit longs to leave at the beginning of 171 * each allocated buffer for our own bookkeeping. We return to the callers 172 * a pointer that points immediately after our bookkeeping area. Incoming pointers 173 * must be decremented by that much, and outgoing pointers incremented. 174 * The malloc tag is stored at MallocOffset from the beginning of the block, 175 * and the realloc tag at ReallocOffset. The offsets are from the true beginning 176 * of the block, not the beginning the caller sees. 177 * 178 * The extra if(Npadlong != 0) in various places is a hint for the compiler to 179 * compile out function calls that would otherwise be no-ops. 180 */ 181 182 /* non tracing 183 * 184 enum { 185 Npadlong = 0, 186 MallocOffset = 0, 187 ReallocOffset = 0, 188 }; 189 * 190 */ 191 192 /* tracing */ 193 enum { 194 Npadlong = 2, 195 MallocOffset = 0, 196 ReallocOffset = 1 197 }; 198 199 void* 200 malloc(ulong size) 201 { 202 void *v; 203 204 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 205 if(Npadlong && v != nil) { 206 v = (ulong*)v+Npadlong; 207 setmalloctag(v, getcallerpc(&size)); 208 setrealloctag(v, 0); 209 } 210 return v; 211 } 212 213 void* 214 mallocz(ulong size, int clr) 215 { 216 void *v; 217 218 v = poolalloc(mainmem, size+Npadlong*sizeof(ulong)); 219 if(Npadlong && v != nil){ 220 v = (ulong*)v+Npadlong; 221 setmalloctag(v, getcallerpc(&size)); 222 setrealloctag(v, 0); 223 } 224 if(clr && v != nil) 225 memset(v, 0, size); 226 return v; 227 } 228 229 void 230 free(void *v) 231 { 232 if(v != nil) 233 poolfree(mainmem, (ulong*)v-Npadlong); 234 } 235 236 void* 237 realloc(void *v, ulong size) 238 { 239 void *nv; 240 241 if(v == nil) 242 return malloc(size); 243 244 if(size == 0){ 245 free(v); 246 return nil; 247 } 248 249 v = (ulong*)v-Npadlong; 250 size += Npadlong*sizeof(ulong); 251 252 if(nv = poolrealloc(mainmem, v, size)){ 253 nv = (ulong*)nv+Npadlong; 254 setrealloctag(nv, getcallerpc(&v)); 255 if(v == nil) 256 setmalloctag(nv, getcallerpc(&v)); 257 } 258 return nv; 259 } 260 261 ulong 262 msize(void *v) 263 { 264 return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 265 } 266 267 void* 268 calloc(ulong n, ulong szelem) 269 { 270 void *v; 271 if(v = mallocz(n*szelem, 1)) 272 setmalloctag(v, getcallerpc(&n)); 273 return v; 274 } 275 276 void 277 setmalloctag(void *v, ulong pc) 278 { 279 ulong *u; 280 USED(v, pc); 281 if(Npadlong <= MallocOffset || v == nil) 282 return; 283 u = v; 284 u[-Npadlong+MallocOffset] = pc; 285 } 286 287 void 288 setrealloctag(void *v, ulong pc) 289 { 290 ulong *u; 291 USED(v, pc); 292 if(Npadlong <= ReallocOffset || v == nil) 293 return; 294 u = v; 295 u[-Npadlong+ReallocOffset] = pc; 296 } 297 298 ulong 299 getmalloctag(void *v) 300 { 301 USED(v); 302 if(Npadlong <= MallocOffset) 303 return ~0; 304 return ((ulong*)v)[-Npadlong+MallocOffset]; 305 } 306 307 ulong 308 getrealloctag(void *v) 309 { 310 USED(v); 311 if(Npadlong <= ReallocOffset) 312 return ((ulong*)v)[-Npadlong+ReallocOffset]; 313 return ~0; 314 } 315 316 void* 317 malloctopoolblock(void *v) 318 { 319 if(v == nil) 320 return nil; 321 322 return &((ulong*)v)[-Npadlong]; 323 } 324