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