1 /* 2 * ---------------------------------------------------------------------------- 3 * "THE BEER-WARE LICENSE" (Revision 42): 4 * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5 * can do whatever you want with this stuff. If we meet some day, and you think 6 * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7 * ---------------------------------------------------------------------------- 8 */ 9 10 #if defined(LIBC_SCCS) && !defined(lint) 11 static char rcsid[] = "$OpenBSD: malloc.c,v 1.35 1999/02/03 03:58:05 d Exp $"; 12 #endif /* LIBC_SCCS and not lint */ 13 14 /* 15 * Defining MALLOC_EXTRA_SANITY will enable extra checks which are 16 * related to internal conditions and consistency in malloc.c. This has 17 * a noticeable runtime performance hit, and generally will not do you 18 * any good unless you fiddle with the internals of malloc or want 19 * to catch random pointer corruption as early as possible. 20 */ 21 #ifndef MALLOC_EXTRA_SANITY 22 #undef MALLOC_EXTRA_SANITY 23 #endif 24 25 /* 26 * Defining MALLOC_STATS will enable you to call malloc_dump() and set 27 * the [dD] options in the MALLOC_OPTIONS environment variable. 28 * It has no run-time performance hit, but does pull in stdio... 29 */ 30 #ifndef MALLOC_STATS 31 #undef MALLOC_STATS 32 #endif 33 34 /* 35 * What to use for Junk. This is the byte value we use to fill with 36 * when the 'J' option is enabled. 37 */ 38 #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <fcntl.h> 45 #include <errno.h> 46 #include <sys/types.h> 47 #include <sys/param.h> 48 #include <sys/mman.h> 49 50 /* 51 * The basic parameters you can tweak. 52 * 53 * malloc_pageshift pagesize = 1 << malloc_pageshift 54 * It's probably best if this is the native 55 * page size, but it shouldn't have to be. 56 * 57 * malloc_minsize minimum size of an allocation in bytes. 58 * If this is too small it's too much work 59 * to manage them. This is also the smallest 60 * unit of alignment used for the storage 61 * returned by malloc/realloc. 62 * 63 */ 64 65 #if defined(__i386__) && defined(__FreeBSD__) 66 # define malloc_pageshift 12U 67 # define malloc_minsize 16U 68 #endif /* __i386__ && __FreeBSD__ */ 69 70 #if defined(__sparc__) && !defined(__OpenBSD__) 71 # define malloc_pageshirt 12U 72 # define malloc_minsize 16U 73 # define MAP_ANON (0) 74 # define USE_DEV_ZERO 75 # define MADV_FREE MADV_DONTNEED 76 #endif /* __sparc__ */ 77 78 /* Insert your combination here... */ 79 #if defined(__FOOCPU__) && defined(__BAROS__) 80 # define malloc_pageshift 12U 81 # define malloc_minsize 16U 82 #endif /* __FOOCPU__ && __BAROS__ */ 83 84 #if defined(__OpenBSD__) && !defined(__sparc__) 85 # define malloc_pageshift (PGSHIFT) 86 # define malloc_minsize 16U 87 #endif /* __OpenBSD__ */ 88 89 #ifdef _THREAD_SAFE 90 # include "thread_private.h" 91 # if 0 92 /* kernel threads */ 93 # include <pthread.h> 94 static pthread_mutex_t malloc_lock; 95 # define THREAD_LOCK() pthread_mutex_lock(&malloc_lock) 96 # define THREAD_UNLOCK() pthread_mutex_unlock(&malloc_lock) 97 # define THREAD_LOCK_INIT() pthread_mutex_init(&malloc_lock, 0); 98 # else 99 /* user threads */ 100 # include "spinlock.h" 101 static spinlock_t malloc_lock = _SPINLOCK_INITIALIZER; 102 # define THREAD_LOCK() if (__isthreaded) _SPINLOCK(&malloc_lock) 103 # define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&malloc_lock) 104 # define THREAD_LOCK_INIT() 105 /* 106 * Malloc can't use the wrapped write() if it fails very early, so 107 * we use the unwrapped syscall _thread_sys_write() 108 */ 109 # define write _thread_sys_write 110 ssize_t write __P((int, const void *, size_t)); 111 # undef malloc 112 # undef realloc 113 # undef free 114 # endif 115 #else 116 /* no threads */ 117 # define THREAD_LOCK() 118 # define THREAD_UNLOCK() 119 # define THREAD_LOCK_INIT() 120 #endif 121 122 /* 123 * No user serviceable parts behind this point. 124 * 125 * This structure describes a page worth of chunks. 126 */ 127 128 struct pginfo { 129 struct pginfo *next; /* next on the free list */ 130 void *page; /* Pointer to the page */ 131 u_short size; /* size of this page's chunks */ 132 u_short shift; /* How far to shift for this size chunks */ 133 u_short free; /* How many free chunks */ 134 u_short total; /* How many chunk */ 135 u_long bits[1]; /* Which chunks are free */ 136 }; 137 138 /* 139 * This structure describes a number of free pages. 140 */ 141 142 struct pgfree { 143 struct pgfree *next; /* next run of free pages */ 144 struct pgfree *prev; /* prev run of free pages */ 145 void *page; /* pointer to free pages */ 146 void *end; /* pointer to end of free pages */ 147 u_long size; /* number of bytes free */ 148 }; 149 150 /* 151 * How many bits per u_long in the bitmap. 152 * Change only if not 8 bits/byte 153 */ 154 #define MALLOC_BITS (8*sizeof(u_long)) 155 156 /* 157 * Magic values to put in the page_directory 158 */ 159 #define MALLOC_NOT_MINE ((struct pginfo*) 0) 160 #define MALLOC_FREE ((struct pginfo*) 1) 161 #define MALLOC_FIRST ((struct pginfo*) 2) 162 #define MALLOC_FOLLOW ((struct pginfo*) 3) 163 #define MALLOC_MAGIC ((struct pginfo*) 4) 164 165 #ifndef malloc_pageshift 166 #define malloc_pageshift 12U 167 #endif 168 169 #ifndef malloc_minsize 170 #define malloc_minsize 16U 171 #endif 172 173 #ifndef malloc_pageshift 174 #error "malloc_pageshift undefined" 175 #endif 176 177 #if !defined(malloc_pagesize) 178 #define malloc_pagesize (1UL<<malloc_pageshift) 179 #endif 180 181 #if ((1UL<<malloc_pageshift) != malloc_pagesize) 182 #error "(1UL<<malloc_pageshift) != malloc_pagesize" 183 #endif 184 185 #ifndef malloc_maxsize 186 #define malloc_maxsize ((malloc_pagesize)>>1) 187 #endif 188 189 /* A mask for the offset inside a page. */ 190 #define malloc_pagemask ((malloc_pagesize)-1) 191 192 #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) 193 #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) 194 195 /* fd of /dev/zero */ 196 #ifdef USE_DEV_ZERO 197 static int fdzero; 198 #define MMAP_FD fdzero 199 #define INIT_MMAP() \ 200 { if ((fdzero=open("/dev/zero", O_RDWR, 0000)) == -1) \ 201 wrterror("open of /dev/zero"); } 202 #else 203 #define MMAP_FD (-1) 204 #define INIT_MMAP() 205 #endif 206 207 /* Set when initialization has been done */ 208 static unsigned malloc_started; 209 210 /* Number of free pages we cache */ 211 static unsigned malloc_cache = 16; 212 213 /* The offset from pagenumber to index into the page directory */ 214 static u_long malloc_origo; 215 216 /* The last index in the page directory we care about */ 217 static u_long last_index; 218 219 /* Pointer to page directory. Allocated "as if with" malloc */ 220 static struct pginfo **page_dir; 221 222 /* How many slots in the page directory */ 223 static size_t malloc_ninfo; 224 225 /* Free pages line up here */ 226 static struct pgfree free_list; 227 228 /* Abort(), user doesn't handle problems. */ 229 static int malloc_abort; 230 231 /* Are we trying to die ? */ 232 static int suicide; 233 234 #ifdef MALLOC_STATS 235 /* dump statistics */ 236 static int malloc_stats; 237 #endif 238 239 /* avoid outputting warnings? */ 240 static int malloc_silent; 241 242 /* always realloc ? */ 243 static int malloc_realloc; 244 245 #ifdef __FreeBSD__ 246 /* pass the kernel a hint on free pages ? */ 247 static int malloc_hint; 248 #endif 249 250 /* xmalloc behaviour ? */ 251 static int malloc_xmalloc; 252 253 /* zero fill ? */ 254 static int malloc_zero; 255 256 /* junk fill ? */ 257 static int malloc_junk; 258 259 #ifdef __FreeBSD__ 260 /* utrace ? */ 261 static int malloc_utrace; 262 263 struct ut { void *p; size_t s; void *r; }; 264 265 void utrace __P((struct ut *, int)); 266 267 #define UTRACE(a, b, c) \ 268 if (malloc_utrace) \ 269 {struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);} 270 #else /* !__FreeBSD__ */ 271 #define UTRACE(a,b,c) 272 #endif 273 274 /* my last break. */ 275 static void *malloc_brk; 276 277 /* one location cache for free-list holders */ 278 static struct pgfree *px; 279 280 /* compile-time options */ 281 char *malloc_options; 282 283 /* Name of the current public function */ 284 static char *malloc_func; 285 286 /* Macro for mmap */ 287 #define MMAP(size) \ 288 mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ 289 MMAP_FD, (off_t)0); 290 291 /* 292 * Necessary function declarations 293 */ 294 static int extend_pgdir(u_long index); 295 static void *imalloc(size_t size); 296 static void ifree(void *ptr); 297 static void *irealloc(void *ptr, size_t size); 298 static void *malloc_bytes(size_t size); 299 300 #ifdef MALLOC_STATS 301 void 302 malloc_dump(fd) 303 FILE *fd; 304 { 305 struct pginfo **pd; 306 struct pgfree *pf; 307 int j; 308 309 pd = page_dir; 310 311 /* print out all the pages */ 312 for(j=0;j<=last_index;j++) { 313 fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); 314 if (pd[j] == MALLOC_NOT_MINE) { 315 for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) 316 ; 317 j--; 318 fprintf(fd, ".. %5d not mine\n", j); 319 } else if (pd[j] == MALLOC_FREE) { 320 for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) 321 ; 322 j--; 323 fprintf(fd, ".. %5d free\n", j); 324 } else if (pd[j] == MALLOC_FIRST) { 325 for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) 326 ; 327 j--; 328 fprintf(fd, ".. %5d in use\n", j); 329 } else if (pd[j] < MALLOC_MAGIC) { 330 fprintf(fd, "(%p)\n", pd[j]); 331 } else { 332 fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", 333 pd[j], pd[j]->free, pd[j]->total, 334 pd[j]->size, pd[j]->page, pd[j]->next); 335 } 336 } 337 338 for(pf=free_list.next; pf; pf=pf->next) { 339 fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", 340 pf, pf->page, pf->end, pf->size, pf->prev, pf->next); 341 if (pf == pf->next) { 342 fprintf(fd, "Free_list loops.\n"); 343 break; 344 } 345 } 346 347 /* print out various info */ 348 fprintf(fd, "Minsize\t%d\n", malloc_minsize); 349 fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); 350 fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); 351 fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); 352 fprintf(fd, "FirstPage\t%ld\n", malloc_origo); 353 fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, 354 (last_index + malloc_pageshift) << malloc_pageshift); 355 fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); 356 } 357 #endif /* MALLOC_STATS */ 358 359 extern char *__progname; 360 361 static void 362 wrterror(p) 363 char *p; 364 { 365 char *q = " error: "; 366 write(2, __progname, strlen(__progname)); 367 write(2, malloc_func, strlen(malloc_func)); 368 write(2, q, strlen(q)); 369 write(2, p, strlen(p)); 370 suicide = 1; 371 #ifdef MALLOC_STATS 372 if (malloc_stats) 373 malloc_dump(stderr); 374 #endif /* MALLOC_STATS */ 375 abort(); 376 } 377 378 static void 379 wrtwarning(p) 380 char *p; 381 { 382 char *q = " warning: "; 383 if (malloc_abort) 384 wrterror(p); 385 else if (malloc_silent) 386 return; 387 write(2, __progname, strlen(__progname)); 388 write(2, malloc_func, strlen(malloc_func)); 389 write(2, q, strlen(q)); 390 write(2, p, strlen(p)); 391 } 392 393 #ifdef MALLOC_STATS 394 static void 395 malloc_exit() 396 { 397 FILE *fd = fopen("malloc.out", "a"); 398 char *q = "malloc() warning: Couldn't dump stats.\n"; 399 if (fd) { 400 malloc_dump(fd); 401 fclose(fd); 402 } else 403 write(2, q, strlen(q)); 404 } 405 #endif /* MALLOC_STATS */ 406 407 408 /* 409 * Allocate a number of pages from the OS 410 */ 411 static void * 412 map_pages(pages) 413 int pages; 414 { 415 caddr_t result, tail; 416 417 result = (caddr_t)pageround((u_long)sbrk(0)); 418 tail = result + (pages << malloc_pageshift); 419 420 if (brk(tail)) { 421 #ifdef MALLOC_EXTRA_SANITY 422 wrterror("(ES): map_pages fails\n"); 423 #endif /* MALLOC_EXTRA_SANITY */ 424 return 0; 425 } 426 427 last_index = ptr2index(tail) - 1; 428 malloc_brk = tail; 429 430 if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index)) 431 return 0; 432 433 return result; 434 } 435 436 /* 437 * Extend page directory 438 */ 439 static int 440 extend_pgdir(index) 441 u_long index; 442 { 443 struct pginfo **new, **old; 444 size_t i, oldlen; 445 446 /* Make it this many pages */ 447 i = index * sizeof *page_dir; 448 i /= malloc_pagesize; 449 i += 2; 450 451 /* remember the old mapping size */ 452 oldlen = malloc_ninfo * sizeof *page_dir; 453 454 /* 455 * NOTE: we allocate new pages and copy the directory rather than tempt 456 * fate by trying to "grow" the region.. There is nothing to prevent 457 * us from accidently re-mapping space that's been allocated by our caller 458 * via dlopen() or other mmap(). 459 * 460 * The copy problem is not too bad, as there is 4K of page index per 461 * 4MB of malloc arena. 462 * 463 * We can totally avoid the copy if we open a file descriptor to associate 464 * the anon mappings with. Then, when we remap the pages at the new 465 * address, the old pages will be "magically" remapped.. But this means 466 * keeping open a "secret" file descriptor..... 467 */ 468 469 /* Get new pages */ 470 new = (struct pginfo**) MMAP(i * malloc_pagesize); 471 if (new == (struct pginfo **)-1) 472 return 0; 473 474 /* Copy the old stuff */ 475 memcpy(new, page_dir, 476 malloc_ninfo * sizeof *page_dir); 477 478 /* register the new size */ 479 malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; 480 481 /* swap the pointers */ 482 old = page_dir; 483 page_dir = new; 484 485 /* Now free the old stuff */ 486 munmap(old, oldlen); 487 return 1; 488 } 489 490 /* 491 * Initialize the world 492 */ 493 static void 494 malloc_init () 495 { 496 char *p, b[64]; 497 int i, j; 498 int save_errno = errno; 499 500 THREAD_LOCK_INIT(); 501 502 INIT_MMAP(); 503 504 #ifdef MALLOC_EXTRA_SANITY 505 malloc_junk = 1; 506 #endif /* MALLOC_EXTRA_SANITY */ 507 508 for (i = 0; i < 3; i++) { 509 if (i == 0) { 510 j = readlink("/etc/malloc.conf", b, sizeof b - 1); 511 if (j <= 0) 512 continue; 513 b[j] = '\0'; 514 p = b; 515 } else if (i == 1) { 516 if (issetugid() == 0) 517 p = getenv("MALLOC_OPTIONS"); 518 else 519 continue; 520 } else if (i == 2) { 521 p = malloc_options; 522 } 523 for (; p && *p; p++) { 524 switch (*p) { 525 case '>': malloc_cache <<= 1; break; 526 case '<': malloc_cache >>= 1; break; 527 case 'a': malloc_abort = 0; break; 528 case 'A': malloc_abort = 1; break; 529 #ifdef MALLOC_STATS 530 case 'd': malloc_stats = 0; break; 531 case 'D': malloc_stats = 1; break; 532 #endif /* MALLOC_STATS */ 533 #ifdef __FreeBSD__ 534 case 'h': malloc_hint = 0; break; 535 case 'H': malloc_hint = 1; break; 536 #endif /* __FreeBSD__ */ 537 case 'r': malloc_realloc = 0; break; 538 case 'R': malloc_realloc = 1; break; 539 case 'j': malloc_junk = 0; break; 540 case 'J': malloc_junk = 1; break; 541 case 'n': malloc_silent = 0; break; 542 case 'N': malloc_silent = 1; break; 543 #ifdef __FreeBSD__ 544 case 'u': malloc_utrace = 0; break; 545 case 'U': malloc_utrace = 1; break; 546 #endif /* __FreeBSD__ */ 547 case 'x': malloc_xmalloc = 0; break; 548 case 'X': malloc_xmalloc = 1; break; 549 case 'z': malloc_zero = 0; break; 550 case 'Z': malloc_zero = 1; break; 551 default: 552 j = malloc_abort; 553 malloc_abort = 0; 554 wrtwarning("unknown char in MALLOC_OPTIONS\n"); 555 malloc_abort = j; 556 break; 557 } 558 } 559 } 560 561 UTRACE(0, 0, 0); 562 563 /* 564 * We want junk in the entire allocation, and zero only in the part 565 * the user asked for. 566 */ 567 if (malloc_zero) 568 malloc_junk=1; 569 570 #ifdef MALLOC_STATS 571 if (malloc_stats) 572 atexit(malloc_exit); 573 #endif /* MALLOC_STATS */ 574 575 /* Allocate one page for the page directory */ 576 page_dir = (struct pginfo **) MMAP(malloc_pagesize); 577 578 if (page_dir == (struct pginfo **) -1) 579 wrterror("mmap(2) failed, check limits.\n"); 580 581 /* 582 * We need a maximum of malloc_pageshift buckets, steal these from the 583 * front of the page_directory; 584 */ 585 malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift; 586 malloc_origo -= malloc_pageshift; 587 588 malloc_ninfo = malloc_pagesize / sizeof *page_dir; 589 590 /* Been here, done that */ 591 malloc_started++; 592 593 /* Recalculate the cache size in bytes, and make sure it's nonzero */ 594 595 if (!malloc_cache) 596 malloc_cache++; 597 598 malloc_cache <<= malloc_pageshift; 599 600 /* 601 * This is a nice hack from Kaleb Keithly (kaleb@x.org). 602 * We can sbrk(2) further back when we keep this on a low address. 603 */ 604 px = (struct pgfree *) imalloc (sizeof *px); 605 errno = save_errno; 606 } 607 608 /* 609 * Allocate a number of complete pages 610 */ 611 static void * 612 malloc_pages(size) 613 size_t size; 614 { 615 void *p, *delay_free = 0; 616 int i; 617 struct pgfree *pf; 618 u_long index; 619 620 size = pageround(size); 621 622 p = 0; 623 /* Look for free pages before asking for more */ 624 for(pf = free_list.next; pf; pf = pf->next) { 625 626 #ifdef MALLOC_EXTRA_SANITY 627 if (pf->size & malloc_pagemask) 628 wrterror("(ES): junk length entry on free_list\n"); 629 if (!pf->size) 630 wrterror("(ES): zero length entry on free_list\n"); 631 if (pf->page == pf->end) 632 wrterror("(ES): zero entry on free_list\n"); 633 if (pf->page > pf->end) 634 wrterror("(ES): sick entry on free_list\n"); 635 if ((void*)pf->page >= (void*)sbrk(0)) 636 wrterror("(ES): entry on free_list past brk\n"); 637 if (page_dir[ptr2index(pf->page)] != MALLOC_FREE) 638 wrterror("(ES): non-free first page on free-list\n"); 639 if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE) 640 wrterror("(ES): non-free last page on free-list\n"); 641 #endif /* MALLOC_EXTRA_SANITY */ 642 643 if (pf->size < size) 644 continue; 645 646 if (pf->size == size) { 647 p = pf->page; 648 if (pf->next) 649 pf->next->prev = pf->prev; 650 pf->prev->next = pf->next; 651 delay_free = pf; 652 break; 653 } 654 655 p = pf->page; 656 pf->page = (char *)pf->page + size; 657 pf->size -= size; 658 break; 659 } 660 661 #ifdef MALLOC_EXTRA_SANITY 662 if (p && page_dir[ptr2index(p)] != MALLOC_FREE) 663 wrterror("(ES): allocated non-free page on free-list\n"); 664 #endif /* MALLOC_EXTRA_SANITY */ 665 666 size >>= malloc_pageshift; 667 668 /* Map new pages */ 669 if (!p) 670 p = map_pages(size); 671 672 if (p) { 673 674 index = ptr2index(p); 675 page_dir[index] = MALLOC_FIRST; 676 for (i=1;i<size;i++) 677 page_dir[index+i] = MALLOC_FOLLOW; 678 679 if (malloc_junk) 680 memset(p, SOME_JUNK, size << malloc_pageshift); 681 } 682 683 if (delay_free) { 684 if (!px) 685 px = delay_free; 686 else 687 ifree(delay_free); 688 } 689 690 return p; 691 } 692 693 /* 694 * Allocate a page of fragments 695 */ 696 697 static __inline__ int 698 malloc_make_chunks(bits) 699 int bits; 700 { 701 struct pginfo *bp; 702 void *pp; 703 int i, k, l; 704 705 /* Allocate a new bucket */ 706 pp = malloc_pages((size_t)malloc_pagesize); 707 if (!pp) 708 return 0; 709 710 /* Find length of admin structure */ 711 l = sizeof *bp - sizeof(u_long); 712 l += sizeof(u_long) * 713 (((malloc_pagesize >> bits)+MALLOC_BITS-1) / MALLOC_BITS); 714 715 /* Don't waste more than two chunks on this */ 716 if ((1UL<<(bits)) <= l+l) { 717 bp = (struct pginfo *)pp; 718 } else { 719 bp = (struct pginfo *)imalloc(l); 720 if (!bp) { 721 ifree(pp); 722 return 0; 723 } 724 } 725 726 bp->size = (1UL<<bits); 727 bp->shift = bits; 728 bp->total = bp->free = malloc_pagesize >> bits; 729 bp->page = pp; 730 731 /* set all valid bits in the bitmap */ 732 k = bp->total; 733 i = 0; 734 735 /* Do a bunch at a time */ 736 for(;k-i >= MALLOC_BITS; i += MALLOC_BITS) 737 bp->bits[i / MALLOC_BITS] = ~0UL; 738 739 for(; i < k; i++) 740 bp->bits[i/MALLOC_BITS] |= 1UL<<(i%MALLOC_BITS); 741 742 if (bp == bp->page) { 743 /* Mark the ones we stole for ourselves */ 744 for(i=0;l > 0;i++) { 745 bp->bits[i/MALLOC_BITS] &= ~(1UL<<(i%MALLOC_BITS)); 746 bp->free--; 747 bp->total--; 748 l -= (1 << bits); 749 } 750 } 751 752 /* MALLOC_LOCK */ 753 754 page_dir[ptr2index(pp)] = bp; 755 756 bp->next = page_dir[bits]; 757 page_dir[bits] = bp; 758 759 /* MALLOC_UNLOCK */ 760 761 return 1; 762 } 763 764 /* 765 * Allocate a fragment 766 */ 767 static void * 768 malloc_bytes(size) 769 size_t size; 770 { 771 int i,j; 772 u_long u; 773 struct pginfo *bp; 774 int k; 775 u_long *lp; 776 777 /* Don't bother with anything less than this */ 778 if (size < malloc_minsize) 779 size = malloc_minsize; 780 781 /* Find the right bucket */ 782 j = 1; 783 i = size-1; 784 while (i >>= 1) 785 j++; 786 787 /* If it's empty, make a page more of that size chunks */ 788 if (!page_dir[j] && !malloc_make_chunks(j)) 789 return 0; 790 791 bp = page_dir[j]; 792 793 /* Find first word of bitmap which isn't empty */ 794 for (lp = bp->bits; !*lp; lp++) 795 ; 796 797 /* Find that bit, and tweak it */ 798 u = 1; 799 k = 0; 800 while (!(*lp & u)) { 801 u += u; 802 k++; 803 } 804 *lp ^= u; 805 806 /* If there are no more free, remove from free-list */ 807 if (!--bp->free) { 808 page_dir[j] = bp->next; 809 bp->next = 0; 810 } 811 812 /* Adjust to the real offset of that chunk */ 813 k += (lp-bp->bits)*MALLOC_BITS; 814 k <<= bp->shift; 815 816 if (malloc_junk) 817 memset((char *)bp->page + k, SOME_JUNK, bp->size); 818 819 return (u_char *)bp->page + k; 820 } 821 822 /* 823 * Allocate a piece of memory 824 */ 825 static void * 826 imalloc(size) 827 size_t size; 828 { 829 void *result; 830 831 if (!malloc_started) 832 malloc_init(); 833 834 if (suicide) 835 abort(); 836 837 if ((size + malloc_pagesize) < size) /* Check for overflow */ 838 result = 0; 839 else if (size <= malloc_maxsize) 840 result = malloc_bytes(size); 841 else 842 result = malloc_pages(size); 843 844 if (malloc_abort && !result) 845 wrterror("allocation failed.\n"); 846 847 if (malloc_zero && result) 848 memset(result, 0, size); 849 850 return result; 851 } 852 853 /* 854 * Change the size of an allocation. 855 */ 856 static void * 857 irealloc(ptr, size) 858 void *ptr; 859 size_t size; 860 { 861 void *p; 862 u_long osize, index; 863 struct pginfo **mp; 864 int i; 865 866 if (suicide) 867 abort(); 868 869 if (!malloc_started) { 870 wrtwarning("malloc() has never been called.\n"); 871 return 0; 872 } 873 874 index = ptr2index(ptr); 875 876 if (index < malloc_pageshift) { 877 wrtwarning("junk pointer, too low to make sense.\n"); 878 return 0; 879 } 880 881 if (index > last_index) { 882 wrtwarning("junk pointer, too high to make sense.\n"); 883 return 0; 884 } 885 886 mp = &page_dir[index]; 887 888 if (*mp == MALLOC_FIRST) { /* Page allocation */ 889 890 /* Check the pointer */ 891 if ((u_long)ptr & malloc_pagemask) { 892 wrtwarning("modified (page-) pointer.\n"); 893 return 0; 894 } 895 896 /* Find the size in bytes */ 897 for (osize = malloc_pagesize; *++mp == MALLOC_FOLLOW;) 898 osize += malloc_pagesize; 899 900 if (!malloc_realloc && /* unless we have to, */ 901 size <= osize && /* .. or are too small, */ 902 size > (osize - malloc_pagesize)) { /* .. or can free a page, */ 903 return ptr; /* don't do anything. */ 904 } 905 906 } else if (*mp >= MALLOC_MAGIC) { /* Chunk allocation */ 907 908 /* Check the pointer for sane values */ 909 if (((u_long)ptr & ((*mp)->size-1))) { 910 wrtwarning("modified (chunk-) pointer.\n"); 911 return 0; 912 } 913 914 /* Find the chunk index in the page */ 915 i = ((u_long)ptr & malloc_pagemask) >> (*mp)->shift; 916 917 /* Verify that it isn't a free chunk already */ 918 if ((*mp)->bits[i/MALLOC_BITS] & (1UL<<(i%MALLOC_BITS))) { 919 wrtwarning("chunk is already free.\n"); 920 return 0; 921 } 922 923 osize = (*mp)->size; 924 925 if (!malloc_realloc && /* Unless we have to, */ 926 size < osize && /* ..or are too small, */ 927 (size > osize/2 || /* ..or could use a smaller size, */ 928 osize == malloc_minsize)) { /* ..(if there is one) */ 929 return ptr; /* ..Don't do anything */ 930 } 931 932 } else { 933 wrtwarning("pointer to wrong page.\n"); 934 return 0; 935 } 936 937 p = imalloc(size); 938 939 if (p) { 940 /* copy the lesser of the two sizes, and free the old one */ 941 if (osize < size) 942 memcpy(p, ptr, osize); 943 else 944 memcpy(p, ptr, size); 945 ifree(ptr); 946 } 947 return p; 948 } 949 950 /* 951 * Free a sequence of pages 952 */ 953 954 static __inline__ void 955 free_pages(ptr, index, info) 956 void *ptr; 957 int index; 958 struct pginfo *info; 959 { 960 int i; 961 struct pgfree *pf, *pt=0; 962 u_long l; 963 void *tail; 964 965 if (info == MALLOC_FREE) { 966 wrtwarning("page is already free.\n"); 967 return; 968 } 969 970 if (info != MALLOC_FIRST) { 971 wrtwarning("pointer to wrong page.\n"); 972 return; 973 } 974 975 if ((u_long)ptr & malloc_pagemask) { 976 wrtwarning("modified (page-) pointer.\n"); 977 return; 978 } 979 980 /* Count how many pages and mark them free at the same time */ 981 page_dir[index] = MALLOC_FREE; 982 for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) 983 page_dir[index + i] = MALLOC_FREE; 984 985 l = i << malloc_pageshift; 986 987 if (malloc_junk) 988 memset(ptr, SOME_JUNK, l); 989 990 #ifdef __FreeBSD__ 991 if (malloc_hint) 992 madvise(ptr, l, MADV_FREE); 993 #endif 994 995 tail = (char *)ptr+l; 996 997 /* add to free-list */ 998 if (!px) 999 px = imalloc(sizeof *px); /* This cannot fail... */ 1000 px->page = ptr; 1001 px->end = tail; 1002 px->size = l; 1003 if (!free_list.next) { 1004 1005 /* Nothing on free list, put this at head */ 1006 px->next = free_list.next; 1007 px->prev = &free_list; 1008 free_list.next = px; 1009 pf = px; 1010 px = 0; 1011 1012 } else { 1013 1014 /* Find the right spot, leave pf pointing to the modified entry. */ 1015 tail = (char *)ptr+l; 1016 1017 for(pf = free_list.next; pf->end < ptr && pf->next; pf = pf->next) 1018 ; /* Race ahead here */ 1019 1020 if (pf->page > tail) { 1021 /* Insert before entry */ 1022 px->next = pf; 1023 px->prev = pf->prev; 1024 pf->prev = px; 1025 px->prev->next = px; 1026 pf = px; 1027 px = 0; 1028 } else if (pf->end == ptr ) { 1029 /* Append to the previous entry */ 1030 pf->end = (char *)pf->end + l; 1031 pf->size += l; 1032 if (pf->next && pf->end == pf->next->page ) { 1033 /* And collapse the next too. */ 1034 pt = pf->next; 1035 pf->end = pt->end; 1036 pf->size += pt->size; 1037 pf->next = pt->next; 1038 if (pf->next) 1039 pf->next->prev = pf; 1040 } 1041 } else if (pf->page == tail) { 1042 /* Prepend to entry */ 1043 pf->size += l; 1044 pf->page = ptr; 1045 } else if (!pf->next) { 1046 /* Append at tail of chain */ 1047 px->next = 0; 1048 px->prev = pf; 1049 pf->next = px; 1050 pf = px; 1051 px = 0; 1052 } else { 1053 wrterror("freelist is destroyed.\n"); 1054 } 1055 } 1056 1057 /* Return something to OS ? */ 1058 if (!pf->next && /* If we're the last one, */ 1059 pf->size > malloc_cache && /* ..and the cache is full, */ 1060 pf->end == malloc_brk && /* ..and none behind us, */ 1061 malloc_brk == sbrk(0)) { /* ..and it's OK to do... */ 1062 1063 /* 1064 * Keep the cache intact. Notice that the '>' above guarantees that 1065 * the pf will always have at least one page afterwards. 1066 */ 1067 pf->end = (char *)pf->page + malloc_cache; 1068 pf->size = malloc_cache; 1069 1070 brk(pf->end); 1071 malloc_brk = pf->end; 1072 1073 index = ptr2index(pf->end); 1074 last_index = index - 1; 1075 1076 for(i=index;i <= last_index;) 1077 page_dir[i++] = MALLOC_NOT_MINE; 1078 1079 /* XXX: We could realloc/shrink the pagedir here I guess. */ 1080 } 1081 if (pt) 1082 ifree(pt); 1083 } 1084 1085 /* 1086 * Free a chunk, and possibly the page it's on, if the page becomes empty. 1087 */ 1088 1089 /* ARGSUSED */ 1090 static __inline__ void 1091 free_bytes(ptr, index, info) 1092 void *ptr; 1093 int index; 1094 struct pginfo *info; 1095 { 1096 int i; 1097 struct pginfo **mp; 1098 void *vp; 1099 1100 /* Find the chunk number on the page */ 1101 i = ((u_long)ptr & malloc_pagemask) >> info->shift; 1102 1103 if (((u_long)ptr & (info->size-1))) { 1104 wrtwarning("modified (chunk-) pointer.\n"); 1105 return; 1106 } 1107 1108 if (info->bits[i/MALLOC_BITS] & (1UL<<(i%MALLOC_BITS))) { 1109 wrtwarning("chunk is already free.\n"); 1110 return; 1111 } 1112 1113 if (malloc_junk) 1114 memset(ptr, SOME_JUNK, info->size); 1115 1116 info->bits[i/MALLOC_BITS] |= 1UL<<(i%MALLOC_BITS); 1117 info->free++; 1118 1119 mp = page_dir + info->shift; 1120 1121 if (info->free == 1) { 1122 1123 /* Page became non-full */ 1124 1125 mp = page_dir + info->shift; 1126 /* Insert in address order */ 1127 while (*mp && (*mp)->next && (*mp)->next->page < info->page) 1128 mp = &(*mp)->next; 1129 info->next = *mp; 1130 *mp = info; 1131 return; 1132 } 1133 1134 if (info->free != info->total) 1135 return; 1136 1137 /* Find & remove this page in the queue */ 1138 while (*mp != info) { 1139 mp = &((*mp)->next); 1140 #ifdef MALLOC_EXTRA_SANITY 1141 if (!*mp) 1142 wrterror("(ES): Not on queue\n"); 1143 #endif /* MALLOC_EXTRA_SANITY */ 1144 } 1145 *mp = info->next; 1146 1147 /* Free the page & the info structure if need be */ 1148 page_dir[ptr2index(info->page)] = MALLOC_FIRST; 1149 vp = info->page; /* Order is important ! */ 1150 if(vp != (void*)info) 1151 ifree(info); 1152 ifree(vp); 1153 } 1154 1155 static void 1156 ifree(ptr) 1157 void *ptr; 1158 { 1159 struct pginfo *info; 1160 int index; 1161 1162 /* This is legal */ 1163 if (!ptr) 1164 return; 1165 1166 if (!malloc_started) { 1167 wrtwarning("malloc() has never been called.\n"); 1168 return; 1169 } 1170 1171 /* If we're already sinking, don't make matters any worse. */ 1172 if (suicide) 1173 return; 1174 1175 index = ptr2index(ptr); 1176 1177 if (index < malloc_pageshift) { 1178 wrtwarning("junk pointer, too low to make sense.\n"); 1179 return; 1180 } 1181 1182 if (index > last_index) { 1183 wrtwarning("junk pointer, too high to make sense.\n"); 1184 return; 1185 } 1186 1187 info = page_dir[index]; 1188 1189 if (info < MALLOC_MAGIC) 1190 free_pages(ptr, index, info); 1191 else 1192 free_bytes(ptr, index, info); 1193 return; 1194 } 1195 1196 /* 1197 * These are the public exported interface routines. 1198 */ 1199 1200 static int malloc_active; 1201 1202 void * 1203 malloc(size_t size) 1204 { 1205 register void *r; 1206 1207 malloc_func = " in malloc():"; 1208 THREAD_LOCK(); 1209 if (malloc_active++) { 1210 wrtwarning("recursive call.\n"); 1211 malloc_active--; 1212 return (0); 1213 } 1214 r = imalloc(size); 1215 UTRACE(0, size, r); 1216 malloc_active--; 1217 THREAD_UNLOCK(); 1218 if (malloc_xmalloc && !r) 1219 wrterror("out of memory.\n"); 1220 return (r); 1221 } 1222 1223 void 1224 free(void *ptr) 1225 { 1226 malloc_func = " in free():"; 1227 THREAD_LOCK(); 1228 if (malloc_active++) { 1229 wrtwarning("recursive call.\n"); 1230 malloc_active--; 1231 return; 1232 } 1233 ifree(ptr); 1234 UTRACE(ptr, 0, 0); 1235 malloc_active--; 1236 THREAD_UNLOCK(); 1237 return; 1238 } 1239 1240 void * 1241 realloc(void *ptr, size_t size) 1242 { 1243 register void *r; 1244 1245 malloc_func = " in realloc():"; 1246 THREAD_LOCK(); 1247 if (malloc_active++) { 1248 wrtwarning("recursive call.\n"); 1249 malloc_active--; 1250 return (0); 1251 } 1252 if (!ptr) { 1253 r = imalloc(size); 1254 } else { 1255 r = irealloc(ptr, size); 1256 } 1257 UTRACE(ptr, size, r); 1258 malloc_active--; 1259 THREAD_UNLOCK(); 1260 if (malloc_xmalloc && !r) 1261 wrterror("out of memory.\n"); 1262 return (r); 1263 } 1264