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