1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 /* 33 * Memory management: malloc(), realloc(), free(). 34 * 35 * The following #-parameters may be redefined: 36 * SEGMENTED: if defined, memory requests are assumed to be 37 * non-contiguous across calls of GETCORE's. 38 * GETCORE: a function to get more core memory. If not SEGMENTED, 39 * GETCORE(0) is assumed to return the next available 40 * address. Default is 'sbrk'. 41 * ERRCORE: the error code as returned by GETCORE. 42 * Default is (char *)(-1). 43 * CORESIZE: a desired unit (measured in bytes) to be used 44 * with GETCORE. Default is (1024*ALIGN). 45 * 46 * This algorithm is based on a best fit strategy with lists of 47 * free elts maintained in a self-adjusting binary tree. Each list 48 * contains all elts of the same size. The tree is ordered by size. 49 * For results on self-adjusting trees, see the paper: 50 * Self-Adjusting Binary Trees, 51 * DD Sleator & RE Tarjan, JACM 1985. 52 * 53 * The header of a block contains the size of the data part in bytes. 54 * Since the size of a block is 0%4, the low two bits of the header 55 * are free and used as follows: 56 * 57 * BIT0: 1 for busy (block is in use), 0 for free. 58 * BIT1: if the block is busy, this bit is 1 if the 59 * preceding block in contiguous memory is free. 60 * Otherwise, it is always 0. 61 */ 62 63 #include "lint.h" 64 #include "mallint.h" 65 #include "mtlib.h" 66 67 /* 68 * Some abusers of the system (notably java1.2) acquire __malloc_lock 69 * in order to prevent threads from holding it while they are being 70 * suspended via thr_suspend() or thr_suspend_allmutators(). 71 * This never worked when alternate malloc() libraries were used 72 * because they don't use __malloc_lock for their locking strategy. 73 * We leave __malloc_lock as an external variable to satisfy these 74 * old programs, but we define a new lock, private to libc, to do the 75 * real locking: libc_malloc_lock. This puts libc's malloc() package 76 * on the same footing as all other malloc packages. 77 */ 78 mutex_t __malloc_lock = DEFAULTMUTEX; 79 mutex_t libc_malloc_lock = DEFAULTMUTEX; 80 81 static TREE *Root, /* root of the free tree */ 82 *Bottom, /* the last free chunk in the arena */ 83 *_morecore(size_t); /* function to get more core */ 84 85 static char *Baddr; /* current high address of the arena */ 86 static char *Lfree; /* last freed block with data intact */ 87 88 static void t_delete(TREE *); 89 static void t_splay(TREE *); 90 static void realfree(void *); 91 static void cleanfree(void *); 92 static void *_malloc_unlocked(size_t); 93 94 #define FREESIZE (1<<5) /* size for preserving free blocks until next malloc */ 95 #define FREEMASK FREESIZE-1 96 97 static void *flist[FREESIZE]; /* list of blocks to be freed on next malloc */ 98 static int freeidx; /* index of free blocks in flist % FREESIZE */ 99 100 /* 101 * Interfaces used only by atfork_init() functions. 102 */ 103 void 104 malloc_locks(void) 105 { 106 (void) mutex_lock(&libc_malloc_lock); 107 } 108 109 void 110 malloc_unlocks(void) 111 { 112 (void) mutex_unlock(&libc_malloc_lock); 113 } 114 115 /* 116 * Allocation of small blocks 117 */ 118 static TREE *List[MINSIZE/WORDSIZE-1]; /* lists of small blocks */ 119 120 static void * 121 _smalloc(size_t size) 122 { 123 TREE *tp; 124 size_t i; 125 126 ASSERT(size % WORDSIZE == 0); 127 /* want to return a unique pointer on malloc(0) */ 128 if (size == 0) 129 size = WORDSIZE; 130 131 /* list to use */ 132 i = size / WORDSIZE - 1; 133 134 if (List[i] == NULL) { 135 TREE *np; 136 int n; 137 /* number of blocks to get at one time */ 138 #define NPS (WORDSIZE*8) 139 ASSERT((size + WORDSIZE) * NPS >= MINSIZE); 140 141 /* get NPS of these block types */ 142 if ((List[i] = _malloc_unlocked((size + WORDSIZE) * NPS)) == 0) 143 return (0); 144 145 /* make them into a link list */ 146 for (n = 0, np = List[i]; n < NPS; ++n) { 147 tp = np; 148 SIZE(tp) = size; 149 np = NEXT(tp); 150 AFTER(tp) = np; 151 } 152 AFTER(tp) = NULL; 153 } 154 155 /* allocate from the head of the queue */ 156 tp = List[i]; 157 List[i] = AFTER(tp); 158 SETBIT0(SIZE(tp)); 159 return (DATA(tp)); 160 } 161 162 void * 163 malloc(size_t size) 164 { 165 void *ret; 166 167 if (!primary_link_map) { 168 errno = ENOTSUP; 169 return (NULL); 170 } 171 assert_no_libc_locks_held(); 172 (void) mutex_lock(&libc_malloc_lock); 173 ret = _malloc_unlocked(size); 174 (void) mutex_unlock(&libc_malloc_lock); 175 return (ret); 176 } 177 178 static void * 179 _malloc_unlocked(size_t size) 180 { 181 size_t n; 182 TREE *tp, *sp; 183 size_t o_bit1; 184 185 COUNT(nmalloc); 186 ASSERT(WORDSIZE == ALIGN); 187 188 /* check for size that could overflow calculations */ 189 if (size > MAX_MALLOC) { 190 errno = ENOMEM; 191 return (NULL); 192 } 193 194 /* make sure that size is 0 mod ALIGN */ 195 ROUND(size); 196 197 /* see if the last free block can be used */ 198 if (Lfree) { 199 sp = BLOCK(Lfree); 200 n = SIZE(sp); 201 CLRBITS01(n); 202 if (n == size) { 203 /* 204 * exact match, use it as is 205 */ 206 freeidx = (freeidx + FREESIZE - 1) & 207 FREEMASK; /* 1 back */ 208 flist[freeidx] = Lfree = NULL; 209 return (DATA(sp)); 210 } else if (size >= MINSIZE && n > size) { 211 /* 212 * got a big enough piece 213 */ 214 freeidx = (freeidx + FREESIZE - 1) & 215 FREEMASK; /* 1 back */ 216 flist[freeidx] = Lfree = NULL; 217 o_bit1 = SIZE(sp) & BIT1; 218 SIZE(sp) = n; 219 goto leftover; 220 } 221 } 222 o_bit1 = 0; 223 224 /* perform free's of space since last malloc */ 225 cleanfree(NULL); 226 227 /* small blocks */ 228 if (size < MINSIZE) 229 return (_smalloc(size)); 230 231 /* search for an elt of the right size */ 232 sp = NULL; 233 n = 0; 234 if (Root) { 235 tp = Root; 236 for (;;) { 237 /* branch left */ 238 if (SIZE(tp) >= size) { 239 if (n == 0 || n >= SIZE(tp)) { 240 sp = tp; 241 n = SIZE(tp); 242 } 243 if (LEFT(tp)) 244 tp = LEFT(tp); 245 else 246 break; 247 } else { /* branch right */ 248 if (RIGHT(tp)) 249 tp = RIGHT(tp); 250 else 251 break; 252 } 253 } 254 255 if (sp) { 256 t_delete(sp); 257 } else if (tp != Root) { 258 /* make the searched-to element the root */ 259 t_splay(tp); 260 Root = tp; 261 } 262 } 263 264 /* if found none fitted in the tree */ 265 if (!sp) { 266 if (Bottom && size <= SIZE(Bottom)) { 267 sp = Bottom; 268 CLRBITS01(SIZE(sp)); 269 } else if ((sp = _morecore(size)) == NULL) /* no more memory */ 270 return (NULL); 271 } 272 273 /* tell the forward neighbor that we're busy */ 274 CLRBIT1(SIZE(NEXT(sp))); 275 276 ASSERT(ISBIT0(SIZE(NEXT(sp)))); 277 278 leftover: 279 /* if the leftover is enough for a new free piece */ 280 if ((n = (SIZE(sp) - size)) >= MINSIZE + WORDSIZE) { 281 n -= WORDSIZE; 282 SIZE(sp) = size; 283 tp = NEXT(sp); 284 SIZE(tp) = n|BIT0; 285 realfree(DATA(tp)); 286 } else if (BOTTOM(sp)) 287 Bottom = NULL; 288 289 /* return the allocated space */ 290 SIZE(sp) |= BIT0 | o_bit1; 291 return (DATA(sp)); 292 } 293 294 295 /* 296 * realloc(). 297 * 298 * If the block size is increasing, we try forward merging first. 299 * This is not best-fit but it avoids some data recopying. 300 */ 301 void * 302 realloc(void *old, size_t size) 303 { 304 TREE *tp, *np; 305 size_t ts; 306 char *new; 307 308 if (!primary_link_map) { 309 errno = ENOTSUP; 310 return (NULL); 311 } 312 313 assert_no_libc_locks_held(); 314 COUNT(nrealloc); 315 316 /* check for size that could overflow calculations */ 317 if (size > MAX_MALLOC) { 318 errno = ENOMEM; 319 return (NULL); 320 } 321 322 /* pointer to the block */ 323 (void) mutex_lock(&libc_malloc_lock); 324 if (old == NULL) { 325 new = _malloc_unlocked(size); 326 (void) mutex_unlock(&libc_malloc_lock); 327 return (new); 328 } 329 330 /* perform free's of space since last malloc */ 331 cleanfree(old); 332 333 /* make sure that size is 0 mod ALIGN */ 334 ROUND(size); 335 336 tp = BLOCK(old); 337 ts = SIZE(tp); 338 339 /* if the block was freed, data has been destroyed. */ 340 if (!ISBIT0(ts)) { 341 (void) mutex_unlock(&libc_malloc_lock); 342 return (NULL); 343 } 344 345 /* nothing to do */ 346 CLRBITS01(SIZE(tp)); 347 if (size == SIZE(tp)) { 348 SIZE(tp) = ts; 349 (void) mutex_unlock(&libc_malloc_lock); 350 return (old); 351 } 352 353 /* special cases involving small blocks */ 354 if (size < MINSIZE || SIZE(tp) < MINSIZE) { 355 /* free is size is zero */ 356 if (size == 0) { 357 SETOLD01(SIZE(tp), ts); 358 _free_unlocked(old); 359 (void) mutex_unlock(&libc_malloc_lock); 360 return (NULL); 361 } else { 362 goto call_malloc; 363 } 364 } 365 366 /* block is increasing in size, try merging the next block */ 367 if (size > SIZE(tp)) { 368 np = NEXT(tp); 369 if (!ISBIT0(SIZE(np))) { 370 ASSERT(SIZE(np) >= MINSIZE); 371 ASSERT(!ISBIT1(SIZE(np))); 372 SIZE(tp) += SIZE(np) + WORDSIZE; 373 if (np != Bottom) 374 t_delete(np); 375 else 376 Bottom = NULL; 377 CLRBIT1(SIZE(NEXT(np))); 378 } 379 380 #ifndef SEGMENTED 381 /* not enough & at TRUE end of memory, try extending core */ 382 if (size > SIZE(tp) && BOTTOM(tp) && GETCORE(0) == Baddr) { 383 Bottom = tp; 384 if ((tp = _morecore(size)) == NULL) { 385 tp = Bottom; 386 Bottom = NULL; 387 } 388 } 389 #endif 390 } 391 392 /* got enough space to use */ 393 if (size <= SIZE(tp)) { 394 size_t n; 395 396 chop_big: 397 if ((n = (SIZE(tp) - size)) >= MINSIZE + WORDSIZE) { 398 n -= WORDSIZE; 399 SIZE(tp) = size; 400 np = NEXT(tp); 401 SIZE(np) = n|BIT0; 402 realfree(DATA(np)); 403 } else if (BOTTOM(tp)) 404 Bottom = NULL; 405 406 /* the previous block may be free */ 407 SETOLD01(SIZE(tp), ts); 408 (void) mutex_unlock(&libc_malloc_lock); 409 return (old); 410 } 411 412 /* call malloc to get a new block */ 413 call_malloc: 414 SETOLD01(SIZE(tp), ts); 415 if ((new = _malloc_unlocked(size)) != NULL) { 416 CLRBITS01(ts); 417 if (ts > size) 418 ts = size; 419 MEMCOPY(new, old, ts); 420 _free_unlocked(old); 421 (void) mutex_unlock(&libc_malloc_lock); 422 return (new); 423 } 424 425 /* 426 * Attempt special case recovery allocations since malloc() failed: 427 * 428 * 1. size <= SIZE(tp) < MINSIZE 429 * Simply return the existing block 430 * 2. SIZE(tp) < size < MINSIZE 431 * malloc() may have failed to allocate the chunk of 432 * small blocks. Try asking for MINSIZE bytes. 433 * 3. size < MINSIZE <= SIZE(tp) 434 * malloc() may have failed as with 2. Change to 435 * MINSIZE allocation which is taken from the beginning 436 * of the current block. 437 * 4. MINSIZE <= SIZE(tp) < size 438 * If the previous block is free and the combination of 439 * these two blocks has at least size bytes, then merge 440 * the two blocks copying the existing contents backwards. 441 */ 442 CLRBITS01(SIZE(tp)); 443 if (SIZE(tp) < MINSIZE) { 444 if (size < SIZE(tp)) { /* case 1. */ 445 SETOLD01(SIZE(tp), ts); 446 (void) mutex_unlock(&libc_malloc_lock); 447 return (old); 448 } else if (size < MINSIZE) { /* case 2. */ 449 size = MINSIZE; 450 goto call_malloc; 451 } 452 } else if (size < MINSIZE) { /* case 3. */ 453 size = MINSIZE; 454 goto chop_big; 455 } else if (ISBIT1(ts) && 456 (SIZE(np = LAST(tp)) + SIZE(tp) + WORDSIZE) >= size) { 457 ASSERT(!ISBIT0(SIZE(np))); 458 t_delete(np); 459 SIZE(np) += SIZE(tp) + WORDSIZE; 460 /* 461 * Since the copy may overlap, use memmove() if available. 462 * Otherwise, copy by hand. 463 */ 464 (void) memmove(DATA(np), old, SIZE(tp)); 465 old = DATA(np); 466 tp = np; 467 CLRBIT1(ts); 468 goto chop_big; 469 } 470 SETOLD01(SIZE(tp), ts); 471 (void) mutex_unlock(&libc_malloc_lock); 472 return (NULL); 473 } 474 475 476 /* 477 * realfree(). 478 * 479 * Coalescing of adjacent free blocks is done first. 480 * Then, the new free block is leaf-inserted into the free tree 481 * without splaying. This strategy does not guarantee the amortized 482 * O(nlogn) behaviour for the insert/delete/find set of operations 483 * on the tree. In practice, however, free is much more infrequent 484 * than malloc/realloc and the tree searches performed by these 485 * functions adequately keep the tree in balance. 486 */ 487 static void 488 realfree(void *old) 489 { 490 TREE *tp, *sp, *np; 491 size_t ts, size; 492 493 COUNT(nfree); 494 495 /* pointer to the block */ 496 tp = BLOCK(old); 497 ts = SIZE(tp); 498 if (!ISBIT0(ts)) 499 return; 500 CLRBITS01(SIZE(tp)); 501 502 /* small block, put it in the right linked list */ 503 if (SIZE(tp) < MINSIZE) { 504 ASSERT(SIZE(tp) / WORDSIZE >= 1); 505 ts = SIZE(tp) / WORDSIZE - 1; 506 AFTER(tp) = List[ts]; 507 List[ts] = tp; 508 return; 509 } 510 511 /* see if coalescing with next block is warranted */ 512 np = NEXT(tp); 513 if (!ISBIT0(SIZE(np))) { 514 if (np != Bottom) 515 t_delete(np); 516 SIZE(tp) += SIZE(np) + WORDSIZE; 517 } 518 519 /* the same with the preceding block */ 520 if (ISBIT1(ts)) { 521 np = LAST(tp); 522 ASSERT(!ISBIT0(SIZE(np))); 523 ASSERT(np != Bottom); 524 t_delete(np); 525 SIZE(np) += SIZE(tp) + WORDSIZE; 526 tp = np; 527 } 528 529 /* initialize tree info */ 530 PARENT(tp) = LEFT(tp) = RIGHT(tp) = LINKFOR(tp) = NULL; 531 532 /* the last word of the block contains self's address */ 533 *(SELFP(tp)) = tp; 534 535 /* set bottom block, or insert in the free tree */ 536 if (BOTTOM(tp)) 537 Bottom = tp; 538 else { 539 /* search for the place to insert */ 540 if (Root) { 541 size = SIZE(tp); 542 np = Root; 543 for (;;) { 544 if (SIZE(np) > size) { 545 if (LEFT(np)) 546 np = LEFT(np); 547 else { 548 LEFT(np) = tp; 549 PARENT(tp) = np; 550 break; 551 } 552 } else if (SIZE(np) < size) { 553 if (RIGHT(np)) 554 np = RIGHT(np); 555 else { 556 RIGHT(np) = tp; 557 PARENT(tp) = np; 558 break; 559 } 560 } else { 561 if ((sp = PARENT(np)) != NULL) { 562 if (np == LEFT(sp)) 563 LEFT(sp) = tp; 564 else 565 RIGHT(sp) = tp; 566 PARENT(tp) = sp; 567 } else 568 Root = tp; 569 570 /* insert to head of list */ 571 if ((sp = LEFT(np)) != NULL) 572 PARENT(sp) = tp; 573 LEFT(tp) = sp; 574 575 if ((sp = RIGHT(np)) != NULL) 576 PARENT(sp) = tp; 577 RIGHT(tp) = sp; 578 579 /* doubly link list */ 580 LINKFOR(tp) = np; 581 LINKBAK(np) = tp; 582 SETNOTREE(np); 583 584 break; 585 } 586 } 587 } else 588 Root = tp; 589 } 590 591 /* tell next block that this one is free */ 592 SETBIT1(SIZE(NEXT(tp))); 593 594 ASSERT(ISBIT0(SIZE(NEXT(tp)))); 595 } 596 597 /* 598 * Get more core. Gaps in memory are noted as busy blocks. 599 */ 600 static TREE * 601 _morecore(size_t size) 602 { 603 TREE *tp; 604 ssize_t n, offset; 605 char *addr; 606 ssize_t nsize; 607 608 /* compute new amount of memory to get */ 609 tp = Bottom; 610 n = (ssize_t)size + 2 * WORDSIZE; 611 addr = GETCORE(0); 612 613 if (addr == ERRCORE) 614 return (NULL); 615 616 /* need to pad size out so that addr is aligned */ 617 if ((((uintptr_t)addr) % ALIGN) != 0) 618 offset = ALIGN - (uintptr_t)addr % ALIGN; 619 else 620 offset = 0; 621 622 #ifndef SEGMENTED 623 /* if not segmented memory, what we need may be smaller */ 624 if (addr == Baddr) { 625 n -= WORDSIZE; 626 if (tp != NULL) 627 n -= SIZE(tp); 628 } 629 #endif 630 631 /* get a multiple of CORESIZE */ 632 n = ((n - 1) / CORESIZE + 1) * CORESIZE; 633 nsize = n + offset; 634 635 /* check if nsize request could overflow in GETCORE */ 636 if ((size_t)nsize > MAX_MALLOC - (uintptr_t)addr) { 637 errno = ENOMEM; 638 return (NULL); 639 } 640 641 if ((size_t)nsize <= MAX_GETCORE) { 642 if (GETCORE(nsize) == ERRCORE) 643 return (NULL); 644 } else { 645 intptr_t delta; 646 /* 647 * the value required is too big for GETCORE() to deal with 648 * in one go, so use GETCORE() at most 2 times instead. 649 * Argument to GETCORE() must be multiple of ALIGN. 650 * If not, GETCORE(-MAX_GETCORE) will not return brk point 651 * to previous value, but will be ALIGN more. 652 * This would leave a small hole. 653 */ 654 delta = MAX_GETCORE; 655 while (delta > 0) { 656 if (GETCORE(delta) == ERRCORE) { 657 if (addr != GETCORE(0)) 658 (void) GETCORE(-MAX_GETCORE); 659 return (NULL); 660 } 661 nsize -= MAX_GETCORE; 662 delta = nsize; 663 } 664 } 665 666 /* contiguous memory */ 667 if (addr == Baddr) { 668 ASSERT(offset == 0); 669 if (tp) { 670 addr = (char *)tp; 671 n += SIZE(tp) + 2 * WORDSIZE; 672 } else { 673 addr = Baddr - WORDSIZE; 674 n += WORDSIZE; 675 } 676 } else 677 addr += offset; 678 679 /* new bottom address */ 680 Baddr = addr + n; 681 682 /* new bottom block */ 683 tp = (TREE *)(uintptr_t)addr; 684 SIZE(tp) = n - 2 * WORDSIZE; 685 ASSERT((SIZE(tp) % ALIGN) == 0); 686 687 /* reserved the last word to head any noncontiguous memory */ 688 SETBIT0(SIZE(NEXT(tp))); 689 690 /* non-contiguous memory, free old bottom block */ 691 if (Bottom && Bottom != tp) { 692 SETBIT0(SIZE(Bottom)); 693 realfree(DATA(Bottom)); 694 } 695 696 return (tp); 697 } 698 699 700 /* 701 * Tree rotation functions (BU: bottom-up, TD: top-down) 702 */ 703 704 #define LEFT1(x, y) \ 705 if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\ 706 if ((PARENT(y) = PARENT(x)) != NULL)\ 707 if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ 708 else RIGHT(PARENT(y)) = y;\ 709 LEFT(y) = x; PARENT(x) = y 710 711 #define RIGHT1(x, y) \ 712 if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\ 713 if ((PARENT(y) = PARENT(x)) != NULL)\ 714 if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ 715 else RIGHT(PARENT(y)) = y;\ 716 RIGHT(y) = x; PARENT(x) = y 717 718 #define BULEFT2(x, y, z) \ 719 if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\ 720 if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\ 721 if ((PARENT(z) = PARENT(x)) != NULL)\ 722 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 723 else RIGHT(PARENT(z)) = z;\ 724 LEFT(z) = y; PARENT(y) = z; LEFT(y) = x; PARENT(x) = y 725 726 #define BURIGHT2(x, y, z) \ 727 if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\ 728 if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\ 729 if ((PARENT(z) = PARENT(x)) != NULL)\ 730 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 731 else RIGHT(PARENT(z)) = z;\ 732 RIGHT(z) = y; PARENT(y) = z; RIGHT(y) = x; PARENT(x) = y 733 734 #define TDLEFT2(x, y, z) \ 735 if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\ 736 if ((PARENT(z) = PARENT(x)) != NULL)\ 737 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 738 else RIGHT(PARENT(z)) = z;\ 739 PARENT(x) = z; LEFT(z) = x; 740 741 #define TDRIGHT2(x, y, z) \ 742 if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\ 743 if ((PARENT(z) = PARENT(x)) != NULL)\ 744 if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 745 else RIGHT(PARENT(z)) = z;\ 746 PARENT(x) = z; RIGHT(z) = x; 747 748 /* 749 * Delete a tree element 750 */ 751 static void 752 t_delete(TREE *op) 753 { 754 TREE *tp, *sp, *gp; 755 756 /* if this is a non-tree node */ 757 if (ISNOTREE(op)) { 758 tp = LINKBAK(op); 759 if ((sp = LINKFOR(op)) != NULL) 760 LINKBAK(sp) = tp; 761 LINKFOR(tp) = sp; 762 return; 763 } 764 765 /* make op the root of the tree */ 766 if (PARENT(op)) 767 t_splay(op); 768 769 /* if this is the start of a list */ 770 if ((tp = LINKFOR(op)) != NULL) { 771 PARENT(tp) = NULL; 772 if ((sp = LEFT(op)) != NULL) 773 PARENT(sp) = tp; 774 LEFT(tp) = sp; 775 776 if ((sp = RIGHT(op)) != NULL) 777 PARENT(sp) = tp; 778 RIGHT(tp) = sp; 779 780 Root = tp; 781 return; 782 } 783 784 /* if op has a non-null left subtree */ 785 if ((tp = LEFT(op)) != NULL) { 786 PARENT(tp) = NULL; 787 788 if (RIGHT(op)) { 789 /* make the right-end of the left subtree its root */ 790 while ((sp = RIGHT(tp)) != NULL) { 791 if ((gp = RIGHT(sp)) != NULL) { 792 TDLEFT2(tp, sp, gp); 793 tp = gp; 794 } else { 795 LEFT1(tp, sp); 796 tp = sp; 797 } 798 } 799 800 /* hook the right subtree of op to the above elt */ 801 RIGHT(tp) = RIGHT(op); 802 PARENT(RIGHT(tp)) = tp; 803 } 804 } else if ((tp = RIGHT(op)) != NULL) /* no left subtree */ 805 PARENT(tp) = NULL; 806 807 Root = tp; 808 } 809 810 /* 811 * Bottom up splaying (simple version). 812 * The basic idea is to roughly cut in half the 813 * path from Root to tp and make tp the new root. 814 */ 815 static void 816 t_splay(TREE *tp) 817 { 818 TREE *pp, *gp; 819 820 /* iterate until tp is the root */ 821 while ((pp = PARENT(tp)) != NULL) { 822 /* grandparent of tp */ 823 gp = PARENT(pp); 824 825 /* x is a left child */ 826 if (LEFT(pp) == tp) { 827 if (gp && LEFT(gp) == pp) { 828 BURIGHT2(gp, pp, tp); 829 } else { 830 RIGHT1(pp, tp); 831 } 832 } else { 833 ASSERT(RIGHT(pp) == tp); 834 if (gp && RIGHT(gp) == pp) { 835 BULEFT2(gp, pp, tp); 836 } else { 837 LEFT1(pp, tp); 838 } 839 } 840 } 841 } 842 843 844 /* 845 * free(). 846 * Performs a delayed free of the block pointed to 847 * by old. The pointer to old is saved on a list, flist, 848 * until the next malloc or realloc. At that time, all the 849 * blocks pointed to in flist are actually freed via 850 * realfree(). This allows the contents of free blocks to 851 * remain undisturbed until the next malloc or realloc. 852 */ 853 void 854 free(void *old) 855 { 856 if (!primary_link_map) { 857 errno = ENOTSUP; 858 return; 859 } 860 assert_no_libc_locks_held(); 861 (void) mutex_lock(&libc_malloc_lock); 862 _free_unlocked(old); 863 (void) mutex_unlock(&libc_malloc_lock); 864 } 865 866 867 void 868 _free_unlocked(void *old) 869 { 870 int i; 871 872 if (old == NULL) 873 return; 874 875 /* 876 * Make sure the same data block is not freed twice. 877 * 3 cases are checked. It returns immediately if either 878 * one of the conditions is true. 879 * 1. Last freed. 880 * 2. Not in use or freed already. 881 * 3. In the free list. 882 */ 883 if (old == Lfree) 884 return; 885 if (!ISBIT0(SIZE(BLOCK(old)))) 886 return; 887 for (i = 0; i < freeidx; i++) 888 if (old == flist[i]) 889 return; 890 891 if (flist[freeidx] != NULL) 892 realfree(flist[freeidx]); 893 flist[freeidx] = Lfree = old; 894 freeidx = (freeidx + 1) & FREEMASK; /* one forward */ 895 } 896 897 /* 898 * cleanfree() frees all the blocks pointed to be flist. 899 * 900 * realloc() should work if it is called with a pointer 901 * to a block that was freed since the last call to malloc() or 902 * realloc(). If cleanfree() is called from realloc(), ptr 903 * is set to the old block and that block should not be 904 * freed since it is actually being reallocated. 905 */ 906 static void 907 cleanfree(void *ptr) 908 { 909 char **flp; 910 911 flp = (char **)&(flist[freeidx]); 912 for (;;) { 913 if (flp == (char **)&(flist[0])) 914 flp = (char **)&(flist[FREESIZE]); 915 if (*--flp == NULL) 916 break; 917 if (*flp != ptr) 918 realfree(*flp); 919 *flp = NULL; 920 } 921 freeidx = 0; 922 Lfree = NULL; 923 } 924