diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libc/stdlib/malloc.c | 656 |
1 files changed, 475 insertions, 181 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index ffb74717e2..139c99aa6d 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c | |||
@@ -8,7 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #if defined(LIBC_SCCS) && !defined(lint) | 10 | #if defined(LIBC_SCCS) && !defined(lint) |
11 | static char rcsid[] = "$OpenBSD: malloc.c,v 1.67 2004/04/12 09:25:11 tdeval Exp $"; | 11 | static char rcsid[] = "$OpenBSD: malloc.c,v 1.68 2004/08/01 08:45:39 tdeval Exp $"; |
12 | #endif /* LIBC_SCCS and not lint */ | 12 | #endif /* LIBC_SCCS and not lint */ |
13 | 13 | ||
14 | /* | 14 | /* |
@@ -38,6 +38,8 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.67 2004/04/12 09:25:11 tdeval Exp | |||
38 | #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ | 38 | #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ |
39 | 39 | ||
40 | #include <sys/types.h> | 40 | #include <sys/types.h> |
41 | #include <sys/time.h> | ||
42 | #include <sys/resource.h> | ||
41 | #include <sys/param.h> | 43 | #include <sys/param.h> |
42 | #include <sys/mman.h> | 44 | #include <sys/mman.h> |
43 | #include <sys/uio.h> | 45 | #include <sys/uio.h> |
@@ -79,11 +81,11 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.67 2004/04/12 09:25:11 tdeval Exp | |||
79 | struct pginfo { | 81 | struct pginfo { |
80 | struct pginfo *next; /* next on the free list */ | 82 | struct pginfo *next; /* next on the free list */ |
81 | void *page; /* Pointer to the page */ | 83 | void *page; /* Pointer to the page */ |
82 | u_short size; /* size of this page's chunks */ | 84 | u_short size; /* size of this page's chunks */ |
83 | u_short shift; /* How far to shift for this size chunks */ | 85 | u_short shift; /* How far to shift for this size chunks */ |
84 | u_short free; /* How many free chunks */ | 86 | u_short free; /* How many free chunks */ |
85 | u_short total; /* How many chunk */ | 87 | u_short total; /* How many chunk */ |
86 | u_long bits[1]; /* Which chunks are free */ | 88 | u_long bits[1]; /* Which chunks are free */ |
87 | }; | 89 | }; |
88 | 90 | ||
89 | /* | 91 | /* |
@@ -94,8 +96,8 @@ struct pgfree { | |||
94 | struct pgfree *next; /* next run of free pages */ | 96 | struct pgfree *next; /* next run of free pages */ |
95 | struct pgfree *prev; /* prev run of free pages */ | 97 | struct pgfree *prev; /* prev run of free pages */ |
96 | void *page; /* pointer to free pages */ | 98 | void *page; /* pointer to free pages */ |
97 | void *end; /* pointer to end of free pages */ | 99 | void *pdir; /* pointer to the base page's dir */ |
98 | u_long size; /* number of bytes free */ | 100 | size_t size; /* number of bytes free */ |
99 | }; | 101 | }; |
100 | 102 | ||
101 | /* | 103 | /* |
@@ -140,8 +142,8 @@ struct pgfree { | |||
140 | /* A mask for the offset inside a page. */ | 142 | /* A mask for the offset inside a page. */ |
141 | #define malloc_pagemask ((malloc_pagesize)-1) | 143 | #define malloc_pagemask ((malloc_pagesize)-1) |
142 | 144 | ||
143 | #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) | 145 | #define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask) |
144 | #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) | 146 | #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift) |
145 | 147 | ||
146 | /* fd of /dev/zero */ | 148 | /* fd of /dev/zero */ |
147 | #ifdef USE_DEV_ZERO | 149 | #ifdef USE_DEV_ZERO |
@@ -161,8 +163,22 @@ static unsigned int malloc_started; | |||
161 | /* Number of free pages we cache */ | 163 | /* Number of free pages we cache */ |
162 | static unsigned int malloc_cache = 16; | 164 | static unsigned int malloc_cache = 16; |
163 | 165 | ||
164 | /* The offset from pagenumber to index into the page directory */ | 166 | /* Structure used for linking discrete directory pages. */ |
165 | static u_long malloc_origo; | 167 | struct pdinfo { |
168 | struct pginfo **base; | ||
169 | struct pdinfo *prev; | ||
170 | struct pdinfo *next; | ||
171 | u_long dirnum; | ||
172 | }; | ||
173 | static struct pdinfo *last_dir; /* Caches to the last and previous */ | ||
174 | static struct pdinfo *prev_dir; /* referenced directory pages. */ | ||
175 | |||
176 | static size_t pdi_off; | ||
177 | static u_long pdi_mod; | ||
178 | #define PD_IDX(num) ((num) / (malloc_pagesize/sizeof(struct pginfo *))) | ||
179 | #define PD_OFF(num) ((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1)) | ||
180 | #define PI_IDX(index) ((index) / pdi_mod) | ||
181 | #define PI_OFF(index) ((index) % pdi_mod) | ||
166 | 182 | ||
167 | /* The last index in the page directory we care about */ | 183 | /* The last index in the page directory we care about */ |
168 | static u_long last_index; | 184 | static u_long last_index; |
@@ -231,72 +247,144 @@ void utrace(struct ut *, int); | |||
231 | /* Status of malloc. */ | 247 | /* Status of malloc. */ |
232 | static int malloc_active; | 248 | static int malloc_active; |
233 | 249 | ||
234 | /* my last break. */ | 250 | /* Allocated memory. */ |
251 | static size_t malloc_used; | ||
252 | |||
253 | /* My last break. */ | ||
235 | static void *malloc_brk; | 254 | static void *malloc_brk; |
236 | 255 | ||
237 | /* one location cache for free-list holders */ | 256 | /* One location cache for free-list holders. */ |
238 | static struct pgfree *px; | 257 | static struct pgfree *px; |
239 | 258 | ||
240 | /* compile-time options */ | 259 | /* Compile-time options. */ |
241 | char *malloc_options; | 260 | char *malloc_options; |
242 | 261 | ||
243 | /* Name of the current public function */ | 262 | /* Name of the current public function. */ |
244 | static char *malloc_func; | 263 | static char *malloc_func; |
245 | 264 | ||
246 | /* Macro for mmap */ | 265 | /* Macro for mmap. */ |
247 | #define MMAP(size) \ | 266 | #define MMAP(size) \ |
248 | mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ | 267 | mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ |
249 | MMAP_FD, (off_t)0) | 268 | MMAP_FD, (off_t)0) |
250 | 269 | ||
251 | /* | 270 | /* |
252 | * Necessary function declarations | 271 | * Necessary function declarations. |
253 | */ | 272 | */ |
254 | static int extend_pgdir(u_long index); | ||
255 | static void *imalloc(size_t size); | 273 | static void *imalloc(size_t size); |
256 | static void ifree(void *ptr); | 274 | static void ifree(void *ptr); |
257 | static void *irealloc(void *ptr, size_t size); | 275 | static void *irealloc(void *ptr, size_t size); |
258 | static void *malloc_bytes(size_t size); | 276 | static void *malloc_bytes(size_t size); |
259 | 277 | ||
278 | |||
279 | /* | ||
280 | * Function for page directory lookup. | ||
281 | */ | ||
282 | static int | ||
283 | pdir_lookup(u_long index, struct pdinfo **pdi) | ||
284 | { | ||
285 | struct pdinfo *spi; | ||
286 | u_long pidx = PI_IDX(index); | ||
287 | |||
288 | if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx) | ||
289 | *pdi = last_dir; | ||
290 | else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx) | ||
291 | *pdi = prev_dir; | ||
292 | else if (last_dir != NULL && prev_dir != NULL) { | ||
293 | if ((PD_IDX(last_dir->dirnum) > pidx) ? | ||
294 | (PD_IDX(last_dir->dirnum) - pidx):(pidx - PD_IDX(last_dir->dirnum)) | ||
295 | < (PD_IDX(prev_dir->dirnum) > pidx) ? | ||
296 | (PD_IDX(prev_dir->dirnum) - pidx):(pidx - PD_IDX(prev_dir->dirnum))) | ||
297 | *pdi = last_dir; | ||
298 | else | ||
299 | *pdi = prev_dir; | ||
300 | |||
301 | if (PD_IDX((*pdi)->dirnum) > pidx) { | ||
302 | for (spi=(*pdi)->prev;spi!=NULL && PD_IDX(spi->dirnum)>pidx; | ||
303 | spi=spi->prev) | ||
304 | *pdi = spi; | ||
305 | if (spi != NULL) | ||
306 | *pdi = spi; | ||
307 | } else | ||
308 | for (spi=(*pdi)->next;spi!=NULL && PD_IDX(spi->dirnum)<=pidx; | ||
309 | spi=spi->next) | ||
310 | *pdi = spi; | ||
311 | } else { | ||
312 | *pdi = (struct pdinfo *)((caddr_t)page_dir + pdi_off); | ||
313 | for (spi=*pdi;spi!=NULL && PD_IDX(spi->dirnum)<=pidx;spi=spi->next) | ||
314 | *pdi = spi; | ||
315 | } | ||
316 | |||
317 | return ((PD_IDX((*pdi)->dirnum) == pidx)?0:(PD_IDX((*pdi)->dirnum) > pidx)?1:-1); | ||
318 | } | ||
319 | |||
320 | |||
260 | #ifdef MALLOC_STATS | 321 | #ifdef MALLOC_STATS |
261 | void | 322 | void |
262 | malloc_dump(FILE *fd) | 323 | malloc_dump(FILE *fd) |
263 | { | 324 | { |
264 | struct pginfo **pd; | 325 | struct pginfo **pd; |
265 | struct pgfree *pf; | 326 | struct pgfree *pf; |
327 | struct pdinfo *pi; | ||
266 | int j; | 328 | int j; |
267 | 329 | ||
268 | pd = page_dir; | 330 | pd = page_dir; |
331 | pi = (struct pdinfo *)((caddr_t)pd + pdi_off); | ||
269 | 332 | ||
270 | /* print out all the pages */ | 333 | /* print out all the pages */ |
271 | for(j=0;j<=last_index;j++) { | 334 | for(j=0;j<=last_index;) { |
272 | fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); | 335 | fprintf(fd, "%08lx %5d ", j << malloc_pageshift, j); |
273 | if (pd[j] == MALLOC_NOT_MINE) { | 336 | if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) { |
274 | for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) | 337 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) { |
275 | ; | 338 | if (!PI_OFF(++j)) { |
339 | if ((pi = pi->next) == NULL || | ||
340 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
341 | pd = pi->base; | ||
342 | j += pdi_mod; | ||
343 | } | ||
344 | } | ||
276 | j--; | 345 | j--; |
277 | fprintf(fd, ".. %5d not mine\n", j); | 346 | fprintf(fd, ".. %5d not mine\n", j); |
278 | } else if (pd[j] == MALLOC_FREE) { | 347 | } else if (pd[PI_OFF(j)] == MALLOC_FREE) { |
279 | for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) | 348 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FREE;) { |
280 | ; | 349 | if (!PI_OFF(++j)) { |
350 | if ((pi = pi->next) == NULL || | ||
351 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
352 | pd = pi->base; | ||
353 | j += pdi_mod; | ||
354 | } | ||
355 | } | ||
281 | j--; | 356 | j--; |
282 | fprintf(fd, ".. %5d free\n", j); | 357 | fprintf(fd, ".. %5d free\n", j); |
283 | } else if (pd[j] == MALLOC_FIRST) { | 358 | } else if (pd[PI_OFF(j)] == MALLOC_FIRST) { |
284 | for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) | 359 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) { |
285 | ; | 360 | if (!PI_OFF(++j)) { |
361 | if ((pi = pi->next) == NULL || | ||
362 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
363 | pd = pi->base; | ||
364 | j += pdi_mod; | ||
365 | } | ||
366 | } | ||
286 | j--; | 367 | j--; |
287 | fprintf(fd, ".. %5d in use\n", j); | 368 | fprintf(fd, ".. %5d in use\n", j); |
288 | } else if (pd[j] < MALLOC_MAGIC) { | 369 | } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) { |
289 | fprintf(fd, "(%p)\n", pd[j]); | 370 | fprintf(fd, "(%p)\n", pd[PI_OFF(j)]); |
290 | } else { | 371 | } else { |
291 | fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", | 372 | fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", |
292 | pd[j], pd[j]->free, pd[j]->total, | 373 | pd[PI_OFF(j)], pd[PI_OFF(j)]->free, pd[PI_OFF(j)]->total, |
293 | pd[j]->size, pd[j]->page, pd[j]->next); | 374 | pd[PI_OFF(j)]->size, pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next); |
375 | } | ||
376 | if (!PI_OFF(++j)) { | ||
377 | if ((pi = pi->next) == NULL) | ||
378 | break; | ||
379 | pd = pi->base; | ||
380 | j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod; | ||
294 | } | 381 | } |
295 | } | 382 | } |
296 | 383 | ||
297 | for(pf=free_list.next; pf; pf=pf->next) { | 384 | for(pf=free_list.next; pf; pf=pf->next) { |
298 | fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", | 385 | fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", |
299 | pf, pf->page, pf->end, pf->size, pf->prev, pf->next); | 386 | pf, pf->page, pf->page + pf->size, pf->size, |
387 | pf->prev, pf->next); | ||
300 | if (pf == pf->next) { | 388 | if (pf == pf->next) { |
301 | fprintf(fd, "Free_list loops\n"); | 389 | fprintf(fd, "Free_list loops\n"); |
302 | break; | 390 | break; |
@@ -308,10 +396,7 @@ malloc_dump(FILE *fd) | |||
308 | fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); | 396 | fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); |
309 | fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); | 397 | fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); |
310 | fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); | 398 | fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); |
311 | fprintf(fd, "FirstPage\t%ld\n", malloc_origo); | 399 | fprintf(fd, "In use\t%lu\n", (u_long)malloc_used); |
312 | fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, | ||
313 | (last_index + malloc_pageshift) << malloc_pageshift); | ||
314 | fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); | ||
315 | } | 400 | } |
316 | #endif /* MALLOC_STATS */ | 401 | #endif /* MALLOC_STATS */ |
317 | 402 | ||
@@ -385,90 +470,84 @@ malloc_exit(void) | |||
385 | static void * | 470 | static void * |
386 | map_pages(size_t pages) | 471 | map_pages(size_t pages) |
387 | { | 472 | { |
388 | caddr_t result, tail; | 473 | struct pdinfo *pi, *spi; |
474 | struct pginfo **pd; | ||
475 | u_long pidx,lidx; | ||
476 | void *result, *tail; | ||
477 | u_long index; | ||
389 | 478 | ||
390 | result = (caddr_t)pageround((u_long)sbrk(0)); | ||
391 | pages <<= malloc_pageshift; | 479 | pages <<= malloc_pageshift; |
392 | if (pages > SIZE_T_MAX - (size_t)result) { | 480 | result = MMAP(pages + malloc_guard); |
393 | #ifdef MALLOC_EXTRA_SANITY | 481 | if (result == MAP_FAILED) { |
394 | wrtwarning("(ES): overflow in map_pages fails\n"); | ||
395 | #endif /* MALLOC_EXTRA_SANITY */ | ||
396 | errno = ENOMEM; | 482 | errno = ENOMEM; |
397 | return (NULL); | ||
398 | } | ||
399 | tail = result + pages + malloc_guard; | ||
400 | |||
401 | if (brk(tail) == (char *)-1) { | ||
402 | #ifdef MALLOC_EXTRA_SANITY | 483 | #ifdef MALLOC_EXTRA_SANITY |
403 | wrtwarning("(ES): map_pages fails\n"); | 484 | wrtwarning("(ES): map_pages fails\n"); |
404 | #endif /* MALLOC_EXTRA_SANITY */ | 485 | #endif /* MALLOC_EXTRA_SANITY */ |
405 | return (NULL); | 486 | return (NULL); |
406 | } | 487 | } |
488 | tail = result + pages + malloc_guard; | ||
407 | if (malloc_guard) | 489 | if (malloc_guard) |
408 | mprotect(result + pages, malloc_pagesize, PROT_NONE); | 490 | mprotect(result + pages, malloc_guard, PROT_NONE); |
409 | |||
410 | last_index = ptr2index(tail) - 1; | ||
411 | malloc_brk = tail; | ||
412 | 491 | ||
413 | if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index)) | 492 | if (tail > malloc_brk) |
414 | return (NULL); | 493 | malloc_brk = tail; |
494 | if ((index = ptr2index(tail) - 1) > last_index) | ||
495 | last_index = index; | ||
415 | 496 | ||
416 | return (result); | 497 | /* Insert directory pages, if needed. */ |
417 | } | 498 | pidx = PI_IDX(ptr2index(result)); |
499 | lidx = PI_IDX(index); | ||
418 | 500 | ||
419 | /* | 501 | pdir_lookup(ptr2index(result), &pi); |
420 | * Extend page directory | ||
421 | */ | ||
422 | static int | ||
423 | extend_pgdir(u_long index) | ||
424 | { | ||
425 | struct pginfo **new, **old; | ||
426 | size_t i, oldlen; | ||
427 | 502 | ||
428 | /* Make it this many pages */ | 503 | for (index=pidx,spi=pi;index<=lidx;index++) { |
429 | i = index * sizeof *page_dir; | 504 | if (pi == NULL || PD_IDX(pi->dirnum) != index) { |
430 | i /= malloc_pagesize; | 505 | if ((pd = MMAP(malloc_pagesize)) == MAP_FAILED) { |
431 | i += 2; | 506 | errno = ENOMEM; |
432 | 507 | munmap(result, tail - result); | |
433 | /* remember the old mapping size */ | 508 | #ifdef MALLOC_EXTRA_SANITY |
434 | oldlen = malloc_ninfo * sizeof *page_dir; | 509 | wrtwarning("(ES): map_pages fails\n"); |
435 | 510 | #endif /* MALLOC_EXTRA_SANITY */ | |
436 | /* | 511 | return (NULL); |
437 | * NOTE: we allocate new pages and copy the directory rather than tempt | 512 | } |
438 | * fate by trying to "grow" the region.. There is nothing to prevent | 513 | memset(pd, 0, malloc_pagesize); |
439 | * us from accidently re-mapping space that's been allocated by our caller | 514 | pi = (struct pdinfo *)((caddr_t)pd + pdi_off); |
440 | * via dlopen() or other mmap(). | 515 | pi->base = pd; |
441 | * | 516 | pi->prev = spi; |
442 | * The copy problem is not too bad, as there is 4K of page index per | 517 | pi->next = spi->next; |
443 | * 4MB of malloc arena. | 518 | pi->dirnum = index * (malloc_pagesize/sizeof(struct pginfo *)); |
444 | * | 519 | |
445 | * We can totally avoid the copy if we open a file descriptor to associate | 520 | if (spi->next != NULL) |
446 | * the anon mappings with. Then, when we remap the pages at the new | 521 | spi->next->prev = pi; |
447 | * address, the old pages will be "magically" remapped.. But this means | 522 | spi->next = pi; |
448 | * keeping open a "secret" file descriptor..... | 523 | } |
449 | */ | 524 | if (index > pidx && index < lidx) { |
450 | 525 | pi->dirnum += pdi_mod; | |
451 | /* Get new pages */ | 526 | } else if (index == pidx) { |
452 | new = (struct pginfo**) MMAP(i * malloc_pagesize); | 527 | if (pidx == lidx) { |
453 | if (new == MAP_FAILED) | 528 | pi->dirnum += (tail - result) >> malloc_pageshift; |
454 | return (0); | 529 | } else { |
455 | 530 | pi->dirnum += pdi_mod - PI_OFF(ptr2index(result)); | |
456 | /* Copy the old stuff */ | 531 | } |
457 | memcpy(new, page_dir, | 532 | } else { |
458 | malloc_ninfo * sizeof *page_dir); | 533 | pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1; |
459 | 534 | } | |
460 | /* register the new size */ | 535 | #ifdef MALLOC_EXTRA_SANITY |
461 | malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; | 536 | if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > index) |
462 | 537 | wrterror("(ES): pages directory overflow\n"); | |
463 | /* swap the pointers */ | 538 | #endif /* MALLOC_EXTRA_SANITY */ |
464 | old = page_dir; | 539 | if (index == pidx && pi != last_dir) { |
465 | page_dir = new; | 540 | prev_dir = last_dir; |
541 | last_dir = pi; | ||
542 | } | ||
543 | spi = pi; | ||
544 | pi = spi->next; | ||
545 | } | ||
466 | 546 | ||
467 | /* Now free the old stuff */ | 547 | return (result); |
468 | munmap(old, oldlen); | ||
469 | return (1); | ||
470 | } | 548 | } |
471 | 549 | ||
550 | |||
472 | /* | 551 | /* |
473 | * Initialize the world | 552 | * Initialize the world |
474 | */ | 553 | */ |
@@ -520,12 +599,12 @@ malloc_init(void) | |||
520 | case 'h': malloc_hint = 0; break; | 599 | case 'h': malloc_hint = 0; break; |
521 | case 'H': malloc_hint = 1; break; | 600 | case 'H': malloc_hint = 1; break; |
522 | #endif /* __FreeBSD__ */ | 601 | #endif /* __FreeBSD__ */ |
523 | case 'r': malloc_realloc = 0; break; | ||
524 | case 'R': malloc_realloc = 1; break; | ||
525 | case 'j': malloc_junk = 0; break; | 602 | case 'j': malloc_junk = 0; break; |
526 | case 'J': malloc_junk = 1; break; | 603 | case 'J': malloc_junk = 1; break; |
527 | case 'n': malloc_silent = 0; break; | 604 | case 'n': malloc_silent = 0; break; |
528 | case 'N': malloc_silent = 1; break; | 605 | case 'N': malloc_silent = 1; break; |
606 | case 'r': malloc_realloc = 0; break; | ||
607 | case 'R': malloc_realloc = 1; break; | ||
529 | #ifdef __FreeBSD__ | 608 | #ifdef __FreeBSD__ |
530 | case 'u': malloc_utrace = 0; break; | 609 | case 'u': malloc_utrace = 0; break; |
531 | case 'U': malloc_utrace = 1; break; | 610 | case 'U': malloc_utrace = 1; break; |
@@ -564,14 +643,15 @@ malloc_init(void) | |||
564 | if (page_dir == MAP_FAILED) | 643 | if (page_dir == MAP_FAILED) |
565 | wrterror("mmap(2) failed, check limits\n"); | 644 | wrterror("mmap(2) failed, check limits\n"); |
566 | 645 | ||
567 | /* | 646 | pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1); |
568 | * We need a maximum of malloc_pageshift buckets, steal these from the | 647 | pdi_mod = pdi_off / sizeof(struct pginfo *); |
569 | * front of the page_directory; | 648 | |
570 | */ | 649 | last_dir = (struct pdinfo *)((caddr_t)page_dir + pdi_off); |
571 | malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift; | 650 | last_dir->base = page_dir; |
572 | malloc_origo -= malloc_pageshift; | 651 | last_dir->prev = last_dir->next = NULL; |
652 | last_dir->dirnum = malloc_pageshift; | ||
573 | 653 | ||
574 | malloc_ninfo = malloc_pagesize / sizeof *page_dir; | 654 | malloc_ninfo = pdi_mod; |
575 | 655 | ||
576 | /* Been here, done that */ | 656 | /* Been here, done that */ |
577 | malloc_started++; | 657 | malloc_started++; |
@@ -583,11 +663,6 @@ malloc_init(void) | |||
583 | 663 | ||
584 | malloc_cache <<= malloc_pageshift; | 664 | malloc_cache <<= malloc_pageshift; |
585 | 665 | ||
586 | /* | ||
587 | * This is a nice hack from Kaleb Keithly (kaleb@x.org). | ||
588 | * We can sbrk(2) further back when we keep this on a low address. | ||
589 | */ | ||
590 | px = (struct pgfree *) imalloc (sizeof *px); | ||
591 | errno = save_errno; | 666 | errno = save_errno; |
592 | } | 667 | } |
593 | 668 | ||
@@ -599,29 +674,49 @@ malloc_pages(size_t size) | |||
599 | { | 674 | { |
600 | void *p, *delay_free = NULL; | 675 | void *p, *delay_free = NULL; |
601 | int i; | 676 | int i; |
677 | struct rlimit rl; | ||
678 | struct pginfo **pd; | ||
679 | struct pdinfo *pi; | ||
680 | u_long pidx; | ||
681 | void *tp; | ||
602 | struct pgfree *pf; | 682 | struct pgfree *pf; |
603 | u_long index; | 683 | u_long index; |
684 | int m; | ||
604 | 685 | ||
605 | size = pageround(size) + malloc_guard; | 686 | size = pageround(size) + malloc_guard; |
606 | 687 | ||
688 | if (getrlimit(RLIMIT_DATA, &rl) == -1) | ||
689 | wrterror("process limits not available\n"); | ||
690 | if (rl.rlim_cur != RLIM_INFINITY && | ||
691 | size > ((size_t)rl.rlim_cur - malloc_used)) { | ||
692 | errno = ENOMEM; | ||
693 | return (NULL); | ||
694 | } | ||
695 | |||
607 | p = NULL; | 696 | p = NULL; |
608 | /* Look for free pages before asking for more */ | 697 | /* Look for free pages before asking for more */ |
609 | for(pf = free_list.next; pf; pf = pf->next) { | 698 | for (pf = free_list.next; pf; pf = pf->next) { |
610 | 699 | ||
611 | #ifdef MALLOC_EXTRA_SANITY | 700 | #ifdef MALLOC_EXTRA_SANITY |
612 | if (pf->size & malloc_pagemask) | 701 | if (pf->size & malloc_pagemask) |
613 | wrterror("(ES): junk length entry on free_list\n"); | 702 | wrterror("(ES): junk length entry on free_list\n"); |
614 | if (!pf->size) | 703 | if (!pf->size) |
615 | wrterror("(ES): zero length entry on free_list\n"); | 704 | wrterror("(ES): zero length entry on free_list\n"); |
616 | if (pf->page == pf->end) | 705 | if (pf->page > (pf->page + pf->size)) |
617 | wrterror("(ES): zero entry on free_list\n"); | ||
618 | if (pf->page > pf->end) | ||
619 | wrterror("(ES): sick entry on free_list\n"); | 706 | wrterror("(ES): sick entry on free_list\n"); |
620 | if ((void*)pf->page >= (void*)sbrk(0)) | 707 | if ((pi = pf->pdir) == NULL) |
621 | wrterror("(ES): entry on free_list past brk\n"); | 708 | wrterror("(ES): invalid page directory on free-list\n"); |
622 | if (page_dir[ptr2index(pf->page)] != MALLOC_FREE) | 709 | if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) |
710 | wrterror("(ES): directory index mismatch on free-list\n"); | ||
711 | pd = pi->base; | ||
712 | if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) | ||
623 | wrterror("(ES): non-free first page on free-list\n"); | 713 | wrterror("(ES): non-free first page on free-list\n"); |
624 | if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE) | 714 | pidx = PI_IDX(ptr2index((pf->page)+(pf->size))-1); |
715 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | ||
716 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
717 | wrterror("(ES): last page not referenced in page directory\n"); | ||
718 | pd = pi->base; | ||
719 | if (pd[PI_OFF(ptr2index((pf->page)+(pf->size))-1)] != MALLOC_FREE) | ||
625 | wrterror("(ES): non-free last page on free-list\n"); | 720 | wrterror("(ES): non-free last page on free-list\n"); |
626 | #endif /* MALLOC_EXTRA_SANITY */ | 721 | #endif /* MALLOC_EXTRA_SANITY */ |
627 | 722 | ||
@@ -630,6 +725,7 @@ malloc_pages(size_t size) | |||
630 | 725 | ||
631 | if (pf->size == size) { | 726 | if (pf->size == size) { |
632 | p = pf->page; | 727 | p = pf->page; |
728 | pi = pf->pdir; | ||
633 | if (pf->next != NULL) | 729 | if (pf->next != NULL) |
634 | pf->next->prev = pf->prev; | 730 | pf->next->prev = pf->prev; |
635 | pf->prev->next = pf->next; | 731 | pf->prev->next = pf->next; |
@@ -640,17 +736,28 @@ malloc_pages(size_t size) | |||
640 | p = pf->page; | 736 | p = pf->page; |
641 | pf->page = (char *)pf->page + size; | 737 | pf->page = (char *)pf->page + size; |
642 | pf->size -= size; | 738 | pf->size -= size; |
739 | pidx = PI_IDX(ptr2index(pf->page)); | ||
740 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | ||
741 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
742 | wrterror("(ES): hole in directories\n"); | ||
743 | tp = pf->pdir; | ||
744 | pf->pdir = pi; | ||
745 | pi = tp; | ||
643 | break; | 746 | break; |
644 | } | 747 | } |
645 | 748 | ||
646 | size -= malloc_guard; | 749 | size -= malloc_guard; |
647 | 750 | ||
648 | #ifdef MALLOC_EXTRA_SANITY | 751 | #ifdef MALLOC_EXTRA_SANITY |
649 | if (p != NULL && page_dir[ptr2index(p)] != MALLOC_FREE) | 752 | if (p != NULL && pi != NULL) { |
753 | pidx = PD_IDX(pi->dirnum); | ||
754 | pd = pi->base; | ||
755 | } | ||
756 | if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) | ||
650 | wrterror("(ES): allocated non-free page on free-list\n"); | 757 | wrterror("(ES): allocated non-free page on free-list\n"); |
651 | #endif /* MALLOC_EXTRA_SANITY */ | 758 | #endif /* MALLOC_EXTRA_SANITY */ |
652 | 759 | ||
653 | if ((malloc_guard || malloc_freeprot) && p != NULL) | 760 | if (p != NULL && (malloc_guard || malloc_freeprot)) |
654 | mprotect(p, size, PROT_READ|PROT_WRITE); | 761 | mprotect(p, size, PROT_READ|PROT_WRITE); |
655 | 762 | ||
656 | size >>= malloc_pageshift; | 763 | size >>= malloc_pageshift; |
@@ -662,9 +769,44 @@ malloc_pages(size_t size) | |||
662 | if (p != NULL) { | 769 | if (p != NULL) { |
663 | 770 | ||
664 | index = ptr2index(p); | 771 | index = ptr2index(p); |
665 | page_dir[index] = MALLOC_FIRST; | 772 | pidx = PI_IDX(index); |
666 | for (i=1;i<size;i++) | 773 | pdir_lookup(index, &pi); |
667 | page_dir[index+i] = MALLOC_FOLLOW; | 774 | #ifdef MALLOC_EXTRA_SANITY |
775 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
776 | wrterror("(ES): mapped pages not found in directory\n"); | ||
777 | #endif /* MALLOC_EXTRA_SANITY */ | ||
778 | if (pi != last_dir) { | ||
779 | prev_dir = last_dir; | ||
780 | last_dir = pi; | ||
781 | } | ||
782 | pd = pi->base; | ||
783 | pd[PI_OFF(index)] = MALLOC_FIRST; | ||
784 | for (i=1;i<size;i++) { | ||
785 | if (!PI_OFF(index+i)) { | ||
786 | pidx++; | ||
787 | pi = pi->next; | ||
788 | #ifdef MALLOC_EXTRA_SANITY | ||
789 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
790 | wrterror("(ES): hole in mapped pages directory\n"); | ||
791 | #endif /* MALLOC_EXTRA_SANITY */ | ||
792 | pd = pi->base; | ||
793 | } | ||
794 | pd[PI_OFF(index+i)] = MALLOC_FOLLOW; | ||
795 | } | ||
796 | if (malloc_guard) { | ||
797 | if (!PI_OFF(index+i)) { | ||
798 | pidx++; | ||
799 | pi = pi->next; | ||
800 | #ifdef MALLOC_EXTRA_SANITY | ||
801 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
802 | wrterror("(ES): hole in mapped pages directory\n"); | ||
803 | #endif /* MALLOC_EXTRA_SANITY */ | ||
804 | pd = pi->base; | ||
805 | } | ||
806 | pd[PI_OFF(index+i)] = MALLOC_FIRST; | ||
807 | } | ||
808 | |||
809 | malloc_used += size << malloc_pageshift; | ||
668 | 810 | ||
669 | if (malloc_junk) | 811 | if (malloc_junk) |
670 | memset(p, SOME_JUNK, size << malloc_pageshift); | 812 | memset(p, SOME_JUNK, size << malloc_pageshift); |
@@ -687,7 +829,10 @@ malloc_pages(size_t size) | |||
687 | static __inline__ int | 829 | static __inline__ int |
688 | malloc_make_chunks(int bits) | 830 | malloc_make_chunks(int bits) |
689 | { | 831 | { |
690 | struct pginfo *bp; | 832 | struct pginfo *bp; |
833 | struct pginfo **pd; | ||
834 | struct pdinfo *pi; | ||
835 | u_long pidx; | ||
691 | void *pp; | 836 | void *pp; |
692 | int i, k, l; | 837 | int i, k, l; |
693 | 838 | ||
@@ -765,7 +910,18 @@ malloc_make_chunks(int bits) | |||
765 | 910 | ||
766 | /* MALLOC_LOCK */ | 911 | /* MALLOC_LOCK */ |
767 | 912 | ||
768 | page_dir[ptr2index(pp)] = bp; | 913 | pidx = PI_IDX(ptr2index(pp)); |
914 | pdir_lookup(ptr2index(pp), &pi); | ||
915 | #ifdef MALLOC_EXTRA_SANITY | ||
916 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
917 | wrterror("(ES): mapped pages not found in directory\n"); | ||
918 | #endif /* MALLOC_EXTRA_SANITY */ | ||
919 | if (pi != last_dir) { | ||
920 | prev_dir = last_dir; | ||
921 | last_dir = pi; | ||
922 | } | ||
923 | pd = pi->base; | ||
924 | pd[PI_OFF(ptr2index(pp))] = bp; | ||
769 | 925 | ||
770 | bp->next = page_dir[bits]; | 926 | bp->next = page_dir[bits]; |
771 | page_dir[bits] = bp; | 927 | page_dir[bits] = bp; |
@@ -819,7 +975,7 @@ malloc_bytes(size_t size) | |||
819 | u += u; | 975 | u += u; |
820 | k++; | 976 | k++; |
821 | } | 977 | } |
822 | 978 | ||
823 | if (malloc_guard) { | 979 | if (malloc_guard) { |
824 | /* Walk to a random position. */ | 980 | /* Walk to a random position. */ |
825 | i = arc4random() % bp->free; | 981 | i = arc4random() % bp->free; |
@@ -832,11 +988,11 @@ malloc_bytes(size_t size) | |||
832 | k = 0; | 988 | k = 0; |
833 | } | 989 | } |
834 | #ifdef MALLOC_EXTRA_SANITY | 990 | #ifdef MALLOC_EXTRA_SANITY |
835 | if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) | 991 | if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) |
836 | wrterror("chunk overflow\n"); | 992 | wrterror("chunk overflow\n"); |
837 | #endif /* MALLOC_EXTRA_SANITY */ | 993 | #endif /* MALLOC_EXTRA_SANITY */ |
838 | if (*lp & u) | 994 | if (*lp & u) |
839 | i--; | 995 | i--; |
840 | } | 996 | } |
841 | } | 997 | } |
842 | *lp ^= u; | 998 | *lp ^= u; |
@@ -896,9 +1052,11 @@ static void * | |||
896 | irealloc(void *ptr, size_t size) | 1052 | irealloc(void *ptr, size_t size) |
897 | { | 1053 | { |
898 | void *p; | 1054 | void *p; |
899 | u_long osize, index; | 1055 | u_long osize, index, i; |
900 | struct pginfo **mp; | 1056 | struct pginfo **mp; |
901 | int i; | 1057 | struct pginfo **pd; |
1058 | struct pdinfo *pi; | ||
1059 | u_long pidx; | ||
902 | 1060 | ||
903 | if (suicide) | 1061 | if (suicide) |
904 | abort(); | 1062 | abort(); |
@@ -920,7 +1078,19 @@ irealloc(void *ptr, size_t size) | |||
920 | return (NULL); | 1078 | return (NULL); |
921 | } | 1079 | } |
922 | 1080 | ||
923 | mp = &page_dir[index]; | 1081 | pidx = PI_IDX(index); |
1082 | pdir_lookup(index, &pi); | ||
1083 | #ifdef MALLOC_EXTRA_SANITY | ||
1084 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
1085 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1086 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1087 | if (pi != last_dir) { | ||
1088 | prev_dir = last_dir; | ||
1089 | last_dir = pi; | ||
1090 | } | ||
1091 | |||
1092 | pd = pi->base; | ||
1093 | mp = &pd[PI_OFF(index)]; | ||
924 | 1094 | ||
925 | if (*mp == MALLOC_FIRST) { /* Page allocation */ | 1095 | if (*mp == MALLOC_FIRST) { /* Page allocation */ |
926 | 1096 | ||
@@ -931,8 +1101,25 @@ irealloc(void *ptr, size_t size) | |||
931 | } | 1101 | } |
932 | 1102 | ||
933 | /* Find the size in bytes */ | 1103 | /* Find the size in bytes */ |
934 | for (osize = malloc_pagesize; *(++mp) == MALLOC_FOLLOW;) | 1104 | i = index; |
1105 | if (!PI_OFF(++i)) { | ||
1106 | pi = pi->next; | ||
1107 | if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1108 | pi = NULL; | ||
1109 | if (pi != NULL) | ||
1110 | pd = pi->base; | ||
1111 | } | ||
1112 | for (osize = malloc_pagesize; | ||
1113 | pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) { | ||
935 | osize += malloc_pagesize; | 1114 | osize += malloc_pagesize; |
1115 | if (!PI_OFF(++i)) { | ||
1116 | pi = pi->next; | ||
1117 | if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1118 | pi = NULL; | ||
1119 | if (pi != NULL) | ||
1120 | pd = pi->base; | ||
1121 | } | ||
1122 | } | ||
936 | 1123 | ||
937 | if (!malloc_realloc && /* Unless we have to, */ | 1124 | if (!malloc_realloc && /* Unless we have to, */ |
938 | size <= osize && /* .. or are too small, */ | 1125 | size <= osize && /* .. or are too small, */ |
@@ -988,6 +1175,7 @@ irealloc(void *ptr, size_t size) | |||
988 | } | 1175 | } |
989 | ifree(ptr); | 1176 | ifree(ptr); |
990 | } | 1177 | } |
1178 | |||
991 | return (p); | 1179 | return (p); |
992 | } | 1180 | } |
993 | 1181 | ||
@@ -999,6 +1187,9 @@ static __inline__ void | |||
999 | free_pages(void *ptr, u_long index, struct pginfo *info) | 1187 | free_pages(void *ptr, u_long index, struct pginfo *info) |
1000 | { | 1188 | { |
1001 | u_long i, l; | 1189 | u_long i, l; |
1190 | struct pginfo **pd; | ||
1191 | struct pdinfo *pi, *spi; | ||
1192 | u_long pidx, lidx; | ||
1002 | struct pgfree *pf, *pt=NULL; | 1193 | struct pgfree *pf, *pt=NULL; |
1003 | void *tail; | 1194 | void *tail; |
1004 | 1195 | ||
@@ -1018,40 +1209,71 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1018 | } | 1209 | } |
1019 | 1210 | ||
1020 | /* Count how many pages and mark them free at the same time */ | 1211 | /* Count how many pages and mark them free at the same time */ |
1021 | page_dir[index] = MALLOC_FREE; | 1212 | pidx = PI_IDX(index); |
1022 | for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) | 1213 | pdir_lookup(index, &pi); |
1023 | page_dir[index + i] = MALLOC_FREE; | 1214 | #ifdef MALLOC_EXTRA_SANITY |
1215 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
1216 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1217 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1218 | |||
1219 | spi = pi; /* Save page index for start of region. */ | ||
1220 | |||
1221 | pd = pi->base; | ||
1222 | pd[PI_OFF(index)] = MALLOC_FREE; | ||
1223 | i = 1; | ||
1224 | if (!PI_OFF(index+i)) { | ||
1225 | pi = pi->next; | ||
1226 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) | ||
1227 | pi = NULL; | ||
1228 | else | ||
1229 | pd = pi->base; | ||
1230 | } | ||
1231 | while (pi != NULL && pd[PI_OFF(index+i)] == MALLOC_FOLLOW) { | ||
1232 | pd[PI_OFF(index+i)] = MALLOC_FREE; | ||
1233 | i++; | ||
1234 | if (!PI_OFF(index+i)) { | ||
1235 | if ((pi=pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) | ||
1236 | pi = NULL; | ||
1237 | else | ||
1238 | pd = pi->base; | ||
1239 | } | ||
1240 | } | ||
1024 | 1241 | ||
1025 | l = i << malloc_pageshift; | 1242 | l = i << malloc_pageshift; |
1026 | 1243 | ||
1027 | if (malloc_junk) | 1244 | if (malloc_junk) |
1028 | memset(ptr, SOME_JUNK, l); | 1245 | memset(ptr, SOME_JUNK, l); |
1029 | 1246 | ||
1247 | malloc_used -= l; | ||
1248 | if (malloc_guard) { | ||
1249 | #ifdef MALLOC_EXTRA_SANITY | ||
1250 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) | ||
1251 | wrterror("(ES): hole in mapped pages directory\n"); | ||
1252 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1253 | pd[PI_OFF(index+i)] = MALLOC_FREE; | ||
1254 | l += malloc_guard; | ||
1255 | } | ||
1256 | tail = (char *)ptr + l; | ||
1257 | |||
1030 | #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) | 1258 | #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) |
1031 | if (malloc_hint) | 1259 | if (malloc_hint) |
1032 | madvise(ptr, l, MADV_FREE); | 1260 | madvise(ptr, l, MADV_FREE); |
1033 | #endif | 1261 | #endif |
1034 | 1262 | ||
1035 | if (malloc_guard) { | ||
1036 | page_dir[index + i] = MALLOC_FREE; | ||
1037 | l += malloc_guard; | ||
1038 | } | ||
1039 | tail = (char *)ptr+l; | ||
1040 | |||
1041 | if (malloc_freeprot) | 1263 | if (malloc_freeprot) |
1042 | mprotect(ptr, tail - ptr, PROT_NONE); | 1264 | mprotect(ptr, l, PROT_NONE); |
1043 | 1265 | ||
1044 | /* add to free-list */ | 1266 | /* Add to free-list. */ |
1045 | if (px == NULL) | 1267 | if (px == NULL) |
1046 | px = imalloc(sizeof *px); /* This cannot fail... */ | 1268 | px = imalloc(sizeof *px); /* This cannot fail... */ |
1047 | px->page = ptr; | 1269 | px->page = ptr; |
1048 | px->end = tail; | 1270 | px->pdir = spi; |
1049 | px->size = l; | 1271 | px->size = l; |
1050 | 1272 | ||
1051 | if (free_list.next == NULL) { | 1273 | if (free_list.next == NULL) { |
1052 | 1274 | ||
1053 | /* Nothing on free list, put this at head */ | 1275 | /* Nothing on free list, put this at head. */ |
1054 | px->next = free_list.next; | 1276 | px->next = NULL; |
1055 | px->prev = &free_list; | 1277 | px->prev = &free_list; |
1056 | free_list.next = px; | 1278 | free_list.next = px; |
1057 | pf = px; | 1279 | pf = px; |
@@ -1061,9 +1283,9 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1061 | 1283 | ||
1062 | /* Find the right spot, leave pf pointing to the modified entry. */ | 1284 | /* Find the right spot, leave pf pointing to the modified entry. */ |
1063 | 1285 | ||
1064 | for(pf = free_list.next; pf->end < ptr && pf->next != NULL; | 1286 | for(pf = free_list.next; (pf->page+pf->size) < ptr && pf->next != NULL; |
1065 | pf = pf->next) | 1287 | pf = pf->next) |
1066 | ; /* Race ahead here */ | 1288 | ; /* Race ahead here. */ |
1067 | 1289 | ||
1068 | if (pf->page > tail) { | 1290 | if (pf->page > tail) { |
1069 | /* Insert before entry */ | 1291 | /* Insert before entry */ |
@@ -1073,25 +1295,24 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1073 | px->prev->next = px; | 1295 | px->prev->next = px; |
1074 | pf = px; | 1296 | pf = px; |
1075 | px = NULL; | 1297 | px = NULL; |
1076 | } else if (pf->end == ptr ) { | 1298 | } else if ((pf->page + pf->size) == ptr ) { |
1077 | /* Append to the previous entry */ | 1299 | /* Append to the previous entry. */ |
1078 | pf->end = (char *)pf->end + l; | ||
1079 | pf->size += l; | 1300 | pf->size += l; |
1080 | if (pf->next != NULL && pf->end == pf->next->page ) { | 1301 | if (pf->next != NULL && (pf->page + pf->size) == pf->next->page ) { |
1081 | /* And collapse the next too. */ | 1302 | /* And collapse the next too. */ |
1082 | pt = pf->next; | 1303 | pt = pf->next; |
1083 | pf->end = pt->end; | ||
1084 | pf->size += pt->size; | 1304 | pf->size += pt->size; |
1085 | pf->next = pt->next; | 1305 | pf->next = pt->next; |
1086 | if (pf->next != NULL) | 1306 | if (pf->next != NULL) |
1087 | pf->next->prev = pf; | 1307 | pf->next->prev = pf; |
1088 | } | 1308 | } |
1089 | } else if (pf->page == tail) { | 1309 | } else if (pf->page == tail) { |
1090 | /* Prepend to entry */ | 1310 | /* Prepend to entry. */ |
1091 | pf->size += l; | 1311 | pf->size += l; |
1092 | pf->page = ptr; | 1312 | pf->page = ptr; |
1313 | pf->pdir = spi; | ||
1093 | } else if (pf->next == NULL) { | 1314 | } else if (pf->next == NULL) { |
1094 | /* Append at tail of chain */ | 1315 | /* Append at tail of chain. */ |
1095 | px->next = NULL; | 1316 | px->next = NULL; |
1096 | px->prev = pf; | 1317 | px->prev = pf; |
1097 | pf->next = px; | 1318 | pf->next = px; |
@@ -1102,31 +1323,72 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1102 | } | 1323 | } |
1103 | } | 1324 | } |
1104 | 1325 | ||
1326 | if (pf->pdir != last_dir) { | ||
1327 | prev_dir = last_dir; | ||
1328 | last_dir = pf->pdir; | ||
1329 | } | ||
1330 | |||
1105 | /* Return something to OS ? */ | 1331 | /* Return something to OS ? */ |
1106 | if (pf->next == NULL && /* If we're the last one, */ | 1332 | if (pf->next == NULL && /* If we're the last one, */ |
1107 | pf->size > malloc_cache && /* ..and the cache is full, */ | 1333 | pf->size > malloc_cache && /* ..and the cache is full, */ |
1108 | pf->end == malloc_brk && /* ..and none behind us, */ | 1334 | (pf->page + pf->size) == malloc_brk) { /* ..and none behind us, */ |
1109 | malloc_brk == sbrk(0)) { /* ..and it's OK to do... */ | ||
1110 | 1335 | ||
1111 | /* | 1336 | /* |
1112 | * Keep the cache intact. Notice that the '>' above guarantees that | 1337 | * Keep the cache intact. Notice that the '>' above guarantees that |
1113 | * the pf will always have at least one page afterwards. | 1338 | * the pf will always have at least one page afterwards. |
1114 | */ | 1339 | */ |
1115 | pf->end = (char *)pf->page + malloc_cache; | 1340 | if (munmap((char *)pf->page + malloc_cache, pf->size - malloc_cache)!=0) |
1341 | goto not_return; | ||
1342 | tail = pf->page + pf->size; | ||
1343 | lidx = ptr2index(tail) - 1; | ||
1116 | pf->size = malloc_cache; | 1344 | pf->size = malloc_cache; |
1117 | 1345 | ||
1118 | brk(pf->end); | 1346 | malloc_brk = pf->page + malloc_cache; |
1119 | malloc_brk = pf->end; | ||
1120 | 1347 | ||
1121 | index = ptr2index(pf->end); | 1348 | index = ptr2index(malloc_brk); |
1122 | 1349 | ||
1123 | for(i=index;i <= last_index;) | 1350 | pidx = PI_IDX(index); |
1124 | page_dir[i++] = MALLOC_NOT_MINE; | 1351 | if (PD_IDX(prev_dir->dirnum) >= pidx) |
1352 | prev_dir = NULL; /* Will be wiped out below ! */ | ||
1353 | |||
1354 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | ||
1355 | |||
1356 | if (pi != NULL && PD_IDX(pi->dirnum) == pidx) { | ||
1357 | pd = pi->base; | ||
1358 | |||
1359 | for(i=index;i <= last_index;) { | ||
1360 | if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) { | ||
1361 | pd[PI_OFF(i)] = MALLOC_NOT_MINE; | ||
1362 | #ifdef MALLOC_EXTRA_SANITY | ||
1363 | if (!PD_OFF(pi->dirnum)) | ||
1364 | wrterror("(ES): pages directory underflow\n"); | ||
1365 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1366 | pi->dirnum--; | ||
1367 | } | ||
1368 | i++; | ||
1369 | if (!PI_OFF(i)) { | ||
1370 | /* If no page in that dir, free directory page. */ | ||
1371 | if (!PD_OFF(pi->dirnum)) { | ||
1372 | /* Remove from list. */ | ||
1373 | pi->prev->next = pi->next; | ||
1374 | if (pi->next != NULL) | ||
1375 | pi->next->prev = pi->prev; | ||
1376 | pi = pi->next; | ||
1377 | munmap(pd, malloc_pagesize); | ||
1378 | } else | ||
1379 | pi = pi->next; | ||
1380 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1381 | break; | ||
1382 | pd = pi->base; | ||
1383 | } | ||
1384 | } | ||
1385 | } | ||
1125 | 1386 | ||
1126 | last_index = index - 1; | 1387 | last_index = index - 1; |
1127 | 1388 | ||
1128 | /* XXX: We could realloc/shrink the pagedir here I guess. */ | 1389 | /* XXX: We could realloc/shrink the pagedir here I guess. */ |
1129 | } | 1390 | } |
1391 | not_return: | ||
1130 | if (pt != NULL) | 1392 | if (pt != NULL) |
1131 | ifree(pt); | 1393 | ifree(pt); |
1132 | } | 1394 | } |
@@ -1141,6 +1403,9 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1141 | { | 1403 | { |
1142 | int i; | 1404 | int i; |
1143 | struct pginfo **mp; | 1405 | struct pginfo **mp; |
1406 | struct pginfo **pd; | ||
1407 | struct pdinfo *pi; | ||
1408 | u_long pidx; | ||
1144 | void *vp; | 1409 | void *vp; |
1145 | 1410 | ||
1146 | /* Find the chunk number on the page */ | 1411 | /* Find the chunk number on the page */ |
@@ -1172,7 +1437,8 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1172 | /* Page became non-full */ | 1437 | /* Page became non-full */ |
1173 | 1438 | ||
1174 | /* Insert in address order */ | 1439 | /* Insert in address order */ |
1175 | while (*mp && (*mp)->next && (*mp)->next->page < info->page) | 1440 | while (*mp != NULL && (*mp)->next != NULL && |
1441 | (*mp)->next->page < info->page) | ||
1176 | mp = &(*mp)->next; | 1442 | mp = &(*mp)->next; |
1177 | info->next = *mp; | 1443 | info->next = *mp; |
1178 | *mp = info; | 1444 | *mp = info; |
@@ -1193,7 +1459,19 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1193 | *mp = info->next; | 1459 | *mp = info->next; |
1194 | 1460 | ||
1195 | /* Free the page & the info structure if need be */ | 1461 | /* Free the page & the info structure if need be */ |
1196 | page_dir[ptr2index(info->page)] = MALLOC_FIRST; | 1462 | pidx = PI_IDX(ptr2index(info->page)); |
1463 | pdir_lookup(ptr2index(info->page), &pi); | ||
1464 | #ifdef MALLOC_EXTRA_SANITY | ||
1465 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
1466 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1467 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1468 | if (pi != last_dir) { | ||
1469 | prev_dir = last_dir; | ||
1470 | last_dir = pi; | ||
1471 | } | ||
1472 | |||
1473 | pd = pi->base; | ||
1474 | pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST; | ||
1197 | 1475 | ||
1198 | /* If the page was mprotected, unprotect it before releasing it */ | 1476 | /* If the page was mprotected, unprotect it before releasing it */ |
1199 | if (info->size == 0) { | 1477 | if (info->size == 0) { |
@@ -1211,6 +1489,9 @@ static void | |||
1211 | ifree(void *ptr) | 1489 | ifree(void *ptr) |
1212 | { | 1490 | { |
1213 | struct pginfo *info; | 1491 | struct pginfo *info; |
1492 | struct pginfo **pd; | ||
1493 | struct pdinfo *pi; | ||
1494 | u_long pidx; | ||
1214 | u_long index; | 1495 | u_long index; |
1215 | 1496 | ||
1216 | /* This is legal */ | 1497 | /* This is legal */ |
@@ -1238,7 +1519,19 @@ ifree(void *ptr) | |||
1238 | return; | 1519 | return; |
1239 | } | 1520 | } |
1240 | 1521 | ||
1241 | info = page_dir[index]; | 1522 | pidx = PI_IDX(index); |
1523 | pdir_lookup(index, &pi); | ||
1524 | #ifdef MALLOC_EXTRA_SANITY | ||
1525 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) | ||
1526 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1527 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1528 | if (pi != last_dir) { | ||
1529 | prev_dir = last_dir; | ||
1530 | last_dir = pi; | ||
1531 | } | ||
1532 | |||
1533 | pd = pi->base; | ||
1534 | info = pd[PI_OFF(index)]; | ||
1242 | 1535 | ||
1243 | if (info < MALLOC_MAGIC) | 1536 | if (info < MALLOC_MAGIC) |
1244 | free_pages(ptr, index, info); | 1537 | free_pages(ptr, index, info); |
@@ -1257,9 +1550,10 @@ malloc_recurse(void) | |||
1257 | { | 1550 | { |
1258 | static int noprint; | 1551 | static int noprint; |
1259 | 1552 | ||
1260 | if (noprint == 0) | 1553 | if (noprint == 0) { |
1554 | noprint = 1; | ||
1261 | wrtwarning("recursive call\n"); | 1555 | wrtwarning("recursive call\n"); |
1262 | noprint = 1; | 1556 | } |
1263 | malloc_active--; | 1557 | malloc_active--; |
1264 | _MALLOC_UNLOCK(); | 1558 | _MALLOC_UNLOCK(); |
1265 | errno = EDEADLK; | 1559 | errno = EDEADLK; |