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 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 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 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 free(void *v) 226 { 227 if(v != nil) 228 poolfree(mainmem, (ulong*)v-Npadlong); 229 } 230 231 void* 232 realloc(void *v, ulong size) 233 { 234 void *nv; 235 236 if(size == 0){ 237 free(v); 238 return nil; 239 } 240 241 if(v) 242 v = (ulong*)v-Npadlong; 243 size += Npadlong*sizeof(ulong); 244 245 if(nv = poolrealloc(mainmem, v, size)){ 246 nv = (ulong*)nv+Npadlong; 247 setrealloctag(nv, getcallerpc(&v)); 248 if(v == nil) 249 setmalloctag(nv, getcallerpc(&v)); 250 } 251 return nv; 252 } 253 254 ulong 255 msize(void *v) 256 { 257 return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong); 258 } 259 260 void* 261 calloc(ulong n, ulong szelem) 262 { 263 void *v; 264 if(v = mallocz(n*szelem, 1)) 265 setmalloctag(v, getcallerpc(&n)); 266 return v; 267 } 268 269 void 270 setmalloctag(void *v, ulong pc) 271 { 272 ulong *u; 273 USED(v, pc); 274 if(Npadlong <= MallocOffset || v == nil) 275 return; 276 u = v; 277 u[-Npadlong+MallocOffset] = pc; 278 } 279 280 void 281 setrealloctag(void *v, ulong pc) 282 { 283 ulong *u; 284 USED(v, pc); 285 if(Npadlong <= ReallocOffset || v == nil) 286 return; 287 u = v; 288 u[-Npadlong+ReallocOffset] = pc; 289 } 290 291 ulong 292 getmalloctag(void *v) 293 { 294 USED(v); 295 if(Npadlong <= MallocOffset) 296 return ~0; 297 return ((ulong*)v)[-Npadlong+MallocOffset]; 298 } 299 300 ulong 301 getrealloctag(void *v) 302 { 303 USED(v); 304 if(Npadlong <= ReallocOffset) 305 return ((ulong*)v)[-Npadlong+ReallocOffset]; 306 return ~0; 307 } 308 309 void* 310 malloctopoolblock(void *v) 311 { 312 if(v == nil) 313 return nil; 314 315 return &((ulong*)v)[-Npadlong]; 316 } 317