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