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