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