10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*2186Sraf * Common Development and Distribution License (the "License"). 6*2186Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 21*2186Sraf 220Sstevel@tonic-gate /* 23*2186Sraf * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 300Sstevel@tonic-gate /* All Rights Reserved */ 310Sstevel@tonic-gate 320Sstevel@tonic-gate /* 330Sstevel@tonic-gate * Memory management: malloc(), realloc(), free(). 340Sstevel@tonic-gate * 350Sstevel@tonic-gate * The following #-parameters may be redefined: 360Sstevel@tonic-gate * SEGMENTED: if defined, memory requests are assumed to be 370Sstevel@tonic-gate * non-contiguous across calls of GETCORE's. 380Sstevel@tonic-gate * GETCORE: a function to get more core memory. If not SEGMENTED, 390Sstevel@tonic-gate * GETCORE(0) is assumed to return the next available 400Sstevel@tonic-gate * address. Default is 'sbrk'. 410Sstevel@tonic-gate * ERRCORE: the error code as returned by GETCORE. 420Sstevel@tonic-gate * Default is (char *)(-1). 430Sstevel@tonic-gate * CORESIZE: a desired unit (measured in bytes) to be used 440Sstevel@tonic-gate * with GETCORE. Default is (1024*ALIGN). 450Sstevel@tonic-gate * 460Sstevel@tonic-gate * This algorithm is based on a best fit strategy with lists of 470Sstevel@tonic-gate * free elts maintained in a self-adjusting binary tree. Each list 480Sstevel@tonic-gate * contains all elts of the same size. The tree is ordered by size. 490Sstevel@tonic-gate * For results on self-adjusting trees, see the paper: 500Sstevel@tonic-gate * Self-Adjusting Binary Trees, 510Sstevel@tonic-gate * DD Sleator & RE Tarjan, JACM 1985. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * The header of a block contains the size of the data part in bytes. 540Sstevel@tonic-gate * Since the size of a block is 0%4, the low two bits of the header 550Sstevel@tonic-gate * are free and used as follows: 560Sstevel@tonic-gate * 570Sstevel@tonic-gate * BIT0: 1 for busy (block is in use), 0 for free. 580Sstevel@tonic-gate * BIT1: if the block is busy, this bit is 1 if the 590Sstevel@tonic-gate * preceding block in contiguous memory is free. 600Sstevel@tonic-gate * Otherwise, it is always 0. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate #include "synonyms.h" 640Sstevel@tonic-gate #include "mallint.h" 650Sstevel@tonic-gate #include "mtlib.h" 660Sstevel@tonic-gate 670Sstevel@tonic-gate /* 680Sstevel@tonic-gate * Some abusers of the system (notably java1.2) acquire __malloc_lock 690Sstevel@tonic-gate * in order to prevent threads from holding it while they are being 700Sstevel@tonic-gate * suspended via thr_suspend() or thr_suspend_allmutators(). 71*2186Sraf * This never worked when alternate malloc() libraries were used 72*2186Sraf * because they don't use __malloc_lock for their locking strategy. 73*2186Sraf * We leave __malloc_lock as an external variable to satisfy these 74*2186Sraf * old programs, but we define a new lock, private to libc, to do the 75*2186Sraf * real locking: libc_malloc_lock. This puts libc's malloc() package 76*2186Sraf * on the same footing as all other malloc packages. 770Sstevel@tonic-gate */ 780Sstevel@tonic-gate mutex_t __malloc_lock = DEFAULTMUTEX; 790Sstevel@tonic-gate mutex_t libc_malloc_lock = DEFAULTMUTEX; 800Sstevel@tonic-gate 810Sstevel@tonic-gate static TREE *Root, /* root of the free tree */ 820Sstevel@tonic-gate *Bottom, /* the last free chunk in the arena */ 830Sstevel@tonic-gate *_morecore(size_t); /* function to get more core */ 840Sstevel@tonic-gate 850Sstevel@tonic-gate static char *Baddr; /* current high address of the arena */ 860Sstevel@tonic-gate static char *Lfree; /* last freed block with data intact */ 870Sstevel@tonic-gate 880Sstevel@tonic-gate static void t_delete(TREE *); 890Sstevel@tonic-gate static void t_splay(TREE *); 900Sstevel@tonic-gate static void realfree(void *); 910Sstevel@tonic-gate static void cleanfree(void *); 920Sstevel@tonic-gate static void *_malloc_unlocked(size_t); 930Sstevel@tonic-gate 940Sstevel@tonic-gate #define FREESIZE (1<<5) /* size for preserving free blocks until next malloc */ 950Sstevel@tonic-gate #define FREEMASK FREESIZE-1 960Sstevel@tonic-gate 970Sstevel@tonic-gate static void *flist[FREESIZE]; /* list of blocks to be freed on next malloc */ 980Sstevel@tonic-gate static int freeidx; /* index of free blocks in flist % FREESIZE */ 990Sstevel@tonic-gate 1000Sstevel@tonic-gate /* 101*2186Sraf * Interfaces used only by atfork_init() functions. 102*2186Sraf */ 103*2186Sraf void 104*2186Sraf malloc_locks(void) 105*2186Sraf { 106*2186Sraf (void) _private_mutex_lock(&libc_malloc_lock); 107*2186Sraf } 108*2186Sraf 109*2186Sraf void 110*2186Sraf malloc_unlocks(void) 111*2186Sraf { 112*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 113*2186Sraf } 114*2186Sraf 115*2186Sraf /* 1160Sstevel@tonic-gate * Allocation of small blocks 1170Sstevel@tonic-gate */ 1180Sstevel@tonic-gate static TREE *List[MINSIZE/WORDSIZE-1]; /* lists of small blocks */ 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static void * 1210Sstevel@tonic-gate _smalloc(size_t size) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate TREE *tp; 1240Sstevel@tonic-gate size_t i; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate ASSERT(size % WORDSIZE == 0); 1270Sstevel@tonic-gate /* want to return a unique pointer on malloc(0) */ 1280Sstevel@tonic-gate if (size == 0) 1290Sstevel@tonic-gate size = WORDSIZE; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* list to use */ 1320Sstevel@tonic-gate i = size / WORDSIZE - 1; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate if (List[i] == NULL) { 1350Sstevel@tonic-gate TREE *np; 1360Sstevel@tonic-gate int n; 1370Sstevel@tonic-gate /* number of blocks to get at one time */ 1380Sstevel@tonic-gate #define NPS (WORDSIZE*8) 1390Sstevel@tonic-gate ASSERT((size + WORDSIZE) * NPS >= MINSIZE); 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate /* get NPS of these block types */ 1420Sstevel@tonic-gate if ((List[i] = _malloc_unlocked((size + WORDSIZE) * NPS)) == 0) 1430Sstevel@tonic-gate return (0); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate /* make them into a link list */ 1460Sstevel@tonic-gate for (n = 0, np = List[i]; n < NPS; ++n) { 1470Sstevel@tonic-gate tp = np; 1480Sstevel@tonic-gate SIZE(tp) = size; 1490Sstevel@tonic-gate np = NEXT(tp); 1500Sstevel@tonic-gate AFTER(tp) = np; 1510Sstevel@tonic-gate } 1520Sstevel@tonic-gate AFTER(tp) = NULL; 1530Sstevel@tonic-gate } 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* allocate from the head of the queue */ 1560Sstevel@tonic-gate tp = List[i]; 1570Sstevel@tonic-gate List[i] = AFTER(tp); 1580Sstevel@tonic-gate SETBIT0(SIZE(tp)); 1590Sstevel@tonic-gate return (DATA(tp)); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate void * 1630Sstevel@tonic-gate malloc(size_t size) 1640Sstevel@tonic-gate { 1650Sstevel@tonic-gate void *ret; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (!primary_link_map) { 1680Sstevel@tonic-gate errno = ENOTSUP; 1690Sstevel@tonic-gate return (NULL); 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate assert_no_libc_locks_held(); 172*2186Sraf (void) _private_mutex_lock(&libc_malloc_lock); 1730Sstevel@tonic-gate ret = _malloc_unlocked(size); 174*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 1750Sstevel@tonic-gate return (ret); 1760Sstevel@tonic-gate } 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate static void * 1790Sstevel@tonic-gate _malloc_unlocked(size_t size) 1800Sstevel@tonic-gate { 1810Sstevel@tonic-gate size_t n; 1820Sstevel@tonic-gate TREE *tp, *sp; 1830Sstevel@tonic-gate size_t o_bit1; 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate COUNT(nmalloc); 1860Sstevel@tonic-gate ASSERT(WORDSIZE == ALIGN); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate /* check for size that could overflow calculations */ 1890Sstevel@tonic-gate if (size > MAX_MALLOC) { 1900Sstevel@tonic-gate errno = ENOMEM; 1910Sstevel@tonic-gate return (NULL); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* make sure that size is 0 mod ALIGN */ 1950Sstevel@tonic-gate ROUND(size); 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate /* see if the last free block can be used */ 1980Sstevel@tonic-gate if (Lfree) { 1990Sstevel@tonic-gate sp = BLOCK(Lfree); 2000Sstevel@tonic-gate n = SIZE(sp); 2010Sstevel@tonic-gate CLRBITS01(n); 2020Sstevel@tonic-gate if (n == size) { 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * exact match, use it as is 2050Sstevel@tonic-gate */ 2060Sstevel@tonic-gate freeidx = (freeidx + FREESIZE - 1) & 2070Sstevel@tonic-gate FREEMASK; /* 1 back */ 2080Sstevel@tonic-gate flist[freeidx] = Lfree = NULL; 2090Sstevel@tonic-gate return (DATA(sp)); 2100Sstevel@tonic-gate } else if (size >= MINSIZE && n > size) { 2110Sstevel@tonic-gate /* 2120Sstevel@tonic-gate * got a big enough piece 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate freeidx = (freeidx + FREESIZE - 1) & 2150Sstevel@tonic-gate FREEMASK; /* 1 back */ 2160Sstevel@tonic-gate flist[freeidx] = Lfree = NULL; 2170Sstevel@tonic-gate o_bit1 = SIZE(sp) & BIT1; 2180Sstevel@tonic-gate SIZE(sp) = n; 2190Sstevel@tonic-gate goto leftover; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate o_bit1 = 0; 2230Sstevel@tonic-gate 2240Sstevel@tonic-gate /* perform free's of space since last malloc */ 2250Sstevel@tonic-gate cleanfree(NULL); 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* small blocks */ 2280Sstevel@tonic-gate if (size < MINSIZE) 2290Sstevel@tonic-gate return (_smalloc(size)); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate /* search for an elt of the right size */ 2320Sstevel@tonic-gate sp = NULL; 2330Sstevel@tonic-gate n = 0; 2340Sstevel@tonic-gate if (Root) { 2350Sstevel@tonic-gate tp = Root; 2360Sstevel@tonic-gate for (;;) { 2370Sstevel@tonic-gate /* branch left */ 2380Sstevel@tonic-gate if (SIZE(tp) >= size) { 2390Sstevel@tonic-gate if (n == 0 || n >= SIZE(tp)) { 2400Sstevel@tonic-gate sp = tp; 2410Sstevel@tonic-gate n = SIZE(tp); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate if (LEFT(tp)) 2440Sstevel@tonic-gate tp = LEFT(tp); 2450Sstevel@tonic-gate else 2460Sstevel@tonic-gate break; 2470Sstevel@tonic-gate } else { /* branch right */ 2480Sstevel@tonic-gate if (RIGHT(tp)) 2490Sstevel@tonic-gate tp = RIGHT(tp); 2500Sstevel@tonic-gate else 2510Sstevel@tonic-gate break; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate if (sp) { 2560Sstevel@tonic-gate t_delete(sp); 2570Sstevel@tonic-gate } else if (tp != Root) { 2580Sstevel@tonic-gate /* make the searched-to element the root */ 2590Sstevel@tonic-gate t_splay(tp); 2600Sstevel@tonic-gate Root = tp; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate } 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate /* if found none fitted in the tree */ 2650Sstevel@tonic-gate if (!sp) { 2660Sstevel@tonic-gate if (Bottom && size <= SIZE(Bottom)) { 2670Sstevel@tonic-gate sp = Bottom; 2680Sstevel@tonic-gate CLRBITS01(SIZE(sp)); 2690Sstevel@tonic-gate } else if ((sp = _morecore(size)) == NULL) /* no more memory */ 2700Sstevel@tonic-gate return (NULL); 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* tell the forward neighbor that we're busy */ 2740Sstevel@tonic-gate CLRBIT1(SIZE(NEXT(sp))); 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate ASSERT(ISBIT0(SIZE(NEXT(sp)))); 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate leftover: 2790Sstevel@tonic-gate /* if the leftover is enough for a new free piece */ 2800Sstevel@tonic-gate if ((n = (SIZE(sp) - size)) >= MINSIZE + WORDSIZE) { 2810Sstevel@tonic-gate n -= WORDSIZE; 2820Sstevel@tonic-gate SIZE(sp) = size; 2830Sstevel@tonic-gate tp = NEXT(sp); 2840Sstevel@tonic-gate SIZE(tp) = n|BIT0; 2850Sstevel@tonic-gate realfree(DATA(tp)); 2860Sstevel@tonic-gate } else if (BOTTOM(sp)) 2870Sstevel@tonic-gate Bottom = NULL; 2880Sstevel@tonic-gate 2890Sstevel@tonic-gate /* return the allocated space */ 2900Sstevel@tonic-gate SIZE(sp) |= BIT0 | o_bit1; 2910Sstevel@tonic-gate return (DATA(sp)); 2920Sstevel@tonic-gate } 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate /* 2960Sstevel@tonic-gate * realloc(). 2970Sstevel@tonic-gate * 2980Sstevel@tonic-gate * If the block size is increasing, we try forward merging first. 2990Sstevel@tonic-gate * This is not best-fit but it avoids some data recopying. 3000Sstevel@tonic-gate */ 3010Sstevel@tonic-gate void * 3020Sstevel@tonic-gate realloc(void *old, size_t size) 3030Sstevel@tonic-gate { 3040Sstevel@tonic-gate TREE *tp, *np; 3050Sstevel@tonic-gate size_t ts; 3060Sstevel@tonic-gate char *new; 3070Sstevel@tonic-gate 3080Sstevel@tonic-gate if (!primary_link_map) { 3090Sstevel@tonic-gate errno = ENOTSUP; 3100Sstevel@tonic-gate return (NULL); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate 3130Sstevel@tonic-gate assert_no_libc_locks_held(); 3140Sstevel@tonic-gate COUNT(nrealloc); 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* check for size that could overflow calculations */ 3170Sstevel@tonic-gate if (size > MAX_MALLOC) { 3180Sstevel@tonic-gate errno = ENOMEM; 3190Sstevel@tonic-gate return (NULL); 3200Sstevel@tonic-gate } 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* pointer to the block */ 323*2186Sraf (void) _private_mutex_lock(&libc_malloc_lock); 3240Sstevel@tonic-gate if (old == NULL) { 3250Sstevel@tonic-gate new = _malloc_unlocked(size); 326*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 3270Sstevel@tonic-gate return (new); 3280Sstevel@tonic-gate } 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* perform free's of space since last malloc */ 3310Sstevel@tonic-gate cleanfree(old); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate /* make sure that size is 0 mod ALIGN */ 3340Sstevel@tonic-gate ROUND(size); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate tp = BLOCK(old); 3370Sstevel@tonic-gate ts = SIZE(tp); 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate /* if the block was freed, data has been destroyed. */ 3400Sstevel@tonic-gate if (!ISBIT0(ts)) { 341*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 3420Sstevel@tonic-gate return (NULL); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 3450Sstevel@tonic-gate /* nothing to do */ 3460Sstevel@tonic-gate CLRBITS01(SIZE(tp)); 3470Sstevel@tonic-gate if (size == SIZE(tp)) { 3480Sstevel@tonic-gate SIZE(tp) = ts; 349*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 3500Sstevel@tonic-gate return (old); 3510Sstevel@tonic-gate } 3520Sstevel@tonic-gate 3530Sstevel@tonic-gate /* special cases involving small blocks */ 3540Sstevel@tonic-gate if (size < MINSIZE || SIZE(tp) < MINSIZE) { 3550Sstevel@tonic-gate /* free is size is zero */ 3560Sstevel@tonic-gate if (size == 0) { 3570Sstevel@tonic-gate SETOLD01(SIZE(tp), ts); 3580Sstevel@tonic-gate _free_unlocked(old); 359*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 3600Sstevel@tonic-gate return (NULL); 3610Sstevel@tonic-gate } else { 3620Sstevel@tonic-gate goto call_malloc; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate /* block is increasing in size, try merging the next block */ 3670Sstevel@tonic-gate if (size > SIZE(tp)) { 3680Sstevel@tonic-gate np = NEXT(tp); 3690Sstevel@tonic-gate if (!ISBIT0(SIZE(np))) { 3700Sstevel@tonic-gate ASSERT(SIZE(np) >= MINSIZE); 3710Sstevel@tonic-gate ASSERT(!ISBIT1(SIZE(np))); 3720Sstevel@tonic-gate SIZE(tp) += SIZE(np) + WORDSIZE; 3730Sstevel@tonic-gate if (np != Bottom) 3740Sstevel@tonic-gate t_delete(np); 3750Sstevel@tonic-gate else 3760Sstevel@tonic-gate Bottom = NULL; 3770Sstevel@tonic-gate CLRBIT1(SIZE(NEXT(np))); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate #ifndef SEGMENTED 3810Sstevel@tonic-gate /* not enough & at TRUE end of memory, try extending core */ 3820Sstevel@tonic-gate if (size > SIZE(tp) && BOTTOM(tp) && GETCORE(0) == Baddr) { 3830Sstevel@tonic-gate Bottom = tp; 3840Sstevel@tonic-gate if ((tp = _morecore(size)) == NULL) { 3850Sstevel@tonic-gate tp = Bottom; 3860Sstevel@tonic-gate Bottom = NULL; 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate } 3890Sstevel@tonic-gate #endif 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate /* got enough space to use */ 3930Sstevel@tonic-gate if (size <= SIZE(tp)) { 3940Sstevel@tonic-gate size_t n; 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate chop_big: 3970Sstevel@tonic-gate if ((n = (SIZE(tp) - size)) >= MINSIZE + WORDSIZE) { 3980Sstevel@tonic-gate n -= WORDSIZE; 3990Sstevel@tonic-gate SIZE(tp) = size; 4000Sstevel@tonic-gate np = NEXT(tp); 4010Sstevel@tonic-gate SIZE(np) = n|BIT0; 4020Sstevel@tonic-gate realfree(DATA(np)); 4030Sstevel@tonic-gate } else if (BOTTOM(tp)) 4040Sstevel@tonic-gate Bottom = NULL; 4050Sstevel@tonic-gate 4060Sstevel@tonic-gate /* the previous block may be free */ 4070Sstevel@tonic-gate SETOLD01(SIZE(tp), ts); 408*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 4090Sstevel@tonic-gate return (old); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* call malloc to get a new block */ 4130Sstevel@tonic-gate call_malloc: 4140Sstevel@tonic-gate SETOLD01(SIZE(tp), ts); 4150Sstevel@tonic-gate if ((new = _malloc_unlocked(size)) != NULL) { 4160Sstevel@tonic-gate CLRBITS01(ts); 4170Sstevel@tonic-gate if (ts > size) 4180Sstevel@tonic-gate ts = size; 4190Sstevel@tonic-gate MEMCOPY(new, old, ts); 4200Sstevel@tonic-gate _free_unlocked(old); 421*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 4220Sstevel@tonic-gate return (new); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate /* 4260Sstevel@tonic-gate * Attempt special case recovery allocations since malloc() failed: 4270Sstevel@tonic-gate * 4280Sstevel@tonic-gate * 1. size <= SIZE(tp) < MINSIZE 4290Sstevel@tonic-gate * Simply return the existing block 4300Sstevel@tonic-gate * 2. SIZE(tp) < size < MINSIZE 4310Sstevel@tonic-gate * malloc() may have failed to allocate the chunk of 4320Sstevel@tonic-gate * small blocks. Try asking for MINSIZE bytes. 4330Sstevel@tonic-gate * 3. size < MINSIZE <= SIZE(tp) 4340Sstevel@tonic-gate * malloc() may have failed as with 2. Change to 4350Sstevel@tonic-gate * MINSIZE allocation which is taken from the beginning 4360Sstevel@tonic-gate * of the current block. 4370Sstevel@tonic-gate * 4. MINSIZE <= SIZE(tp) < size 4380Sstevel@tonic-gate * If the previous block is free and the combination of 4390Sstevel@tonic-gate * these two blocks has at least size bytes, then merge 4400Sstevel@tonic-gate * the two blocks copying the existing contents backwards. 4410Sstevel@tonic-gate */ 4420Sstevel@tonic-gate CLRBITS01(SIZE(tp)); 4430Sstevel@tonic-gate if (SIZE(tp) < MINSIZE) { 4440Sstevel@tonic-gate if (size < SIZE(tp)) { /* case 1. */ 4450Sstevel@tonic-gate SETOLD01(SIZE(tp), ts); 446*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 4470Sstevel@tonic-gate return (old); 4480Sstevel@tonic-gate } else if (size < MINSIZE) { /* case 2. */ 4490Sstevel@tonic-gate size = MINSIZE; 4500Sstevel@tonic-gate goto call_malloc; 4510Sstevel@tonic-gate } 4520Sstevel@tonic-gate } else if (size < MINSIZE) { /* case 3. */ 4530Sstevel@tonic-gate size = MINSIZE; 4540Sstevel@tonic-gate goto chop_big; 4550Sstevel@tonic-gate } else if (ISBIT1(ts) && 4560Sstevel@tonic-gate (SIZE(np = LAST(tp)) + SIZE(tp) + WORDSIZE) >= size) { 4570Sstevel@tonic-gate ASSERT(!ISBIT0(SIZE(np))); 4580Sstevel@tonic-gate t_delete(np); 4590Sstevel@tonic-gate SIZE(np) += SIZE(tp) + WORDSIZE; 4600Sstevel@tonic-gate /* 4610Sstevel@tonic-gate * Since the copy may overlap, use memmove() if available. 4620Sstevel@tonic-gate * Otherwise, copy by hand. 4630Sstevel@tonic-gate */ 4640Sstevel@tonic-gate (void) memmove(DATA(np), old, SIZE(tp)); 4650Sstevel@tonic-gate old = DATA(np); 4660Sstevel@tonic-gate tp = np; 4670Sstevel@tonic-gate CLRBIT1(ts); 4680Sstevel@tonic-gate goto chop_big; 4690Sstevel@tonic-gate } 4700Sstevel@tonic-gate SETOLD01(SIZE(tp), ts); 471*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 4720Sstevel@tonic-gate return (NULL); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate 4760Sstevel@tonic-gate /* 4770Sstevel@tonic-gate * realfree(). 4780Sstevel@tonic-gate * 4790Sstevel@tonic-gate * Coalescing of adjacent free blocks is done first. 4800Sstevel@tonic-gate * Then, the new free block is leaf-inserted into the free tree 4810Sstevel@tonic-gate * without splaying. This strategy does not guarantee the amortized 4820Sstevel@tonic-gate * O(nlogn) behaviour for the insert/delete/find set of operations 4830Sstevel@tonic-gate * on the tree. In practice, however, free is much more infrequent 4840Sstevel@tonic-gate * than malloc/realloc and the tree searches performed by these 4850Sstevel@tonic-gate * functions adequately keep the tree in balance. 4860Sstevel@tonic-gate */ 4870Sstevel@tonic-gate static void 4880Sstevel@tonic-gate realfree(void *old) 4890Sstevel@tonic-gate { 4900Sstevel@tonic-gate TREE *tp, *sp, *np; 4910Sstevel@tonic-gate size_t ts, size; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate COUNT(nfree); 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate /* pointer to the block */ 4960Sstevel@tonic-gate tp = BLOCK(old); 4970Sstevel@tonic-gate ts = SIZE(tp); 4980Sstevel@tonic-gate if (!ISBIT0(ts)) 4990Sstevel@tonic-gate return; 5000Sstevel@tonic-gate CLRBITS01(SIZE(tp)); 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate /* small block, put it in the right linked list */ 5030Sstevel@tonic-gate if (SIZE(tp) < MINSIZE) { 5040Sstevel@tonic-gate ASSERT(SIZE(tp) / WORDSIZE >= 1); 5050Sstevel@tonic-gate ts = SIZE(tp) / WORDSIZE - 1; 5060Sstevel@tonic-gate AFTER(tp) = List[ts]; 5070Sstevel@tonic-gate List[ts] = tp; 5080Sstevel@tonic-gate return; 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* see if coalescing with next block is warranted */ 5120Sstevel@tonic-gate np = NEXT(tp); 5130Sstevel@tonic-gate if (!ISBIT0(SIZE(np))) { 5140Sstevel@tonic-gate if (np != Bottom) 5150Sstevel@tonic-gate t_delete(np); 5160Sstevel@tonic-gate SIZE(tp) += SIZE(np) + WORDSIZE; 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate /* the same with the preceding block */ 5200Sstevel@tonic-gate if (ISBIT1(ts)) { 5210Sstevel@tonic-gate np = LAST(tp); 5220Sstevel@tonic-gate ASSERT(!ISBIT0(SIZE(np))); 5230Sstevel@tonic-gate ASSERT(np != Bottom); 5240Sstevel@tonic-gate t_delete(np); 5250Sstevel@tonic-gate SIZE(np) += SIZE(tp) + WORDSIZE; 5260Sstevel@tonic-gate tp = np; 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate /* initialize tree info */ 5300Sstevel@tonic-gate PARENT(tp) = LEFT(tp) = RIGHT(tp) = LINKFOR(tp) = NULL; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* the last word of the block contains self's address */ 5330Sstevel@tonic-gate *(SELFP(tp)) = tp; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate /* set bottom block, or insert in the free tree */ 5360Sstevel@tonic-gate if (BOTTOM(tp)) 5370Sstevel@tonic-gate Bottom = tp; 5380Sstevel@tonic-gate else { 5390Sstevel@tonic-gate /* search for the place to insert */ 5400Sstevel@tonic-gate if (Root) { 5410Sstevel@tonic-gate size = SIZE(tp); 5420Sstevel@tonic-gate np = Root; 5430Sstevel@tonic-gate for (;;) { 5440Sstevel@tonic-gate if (SIZE(np) > size) { 5450Sstevel@tonic-gate if (LEFT(np)) 5460Sstevel@tonic-gate np = LEFT(np); 5470Sstevel@tonic-gate else { 5480Sstevel@tonic-gate LEFT(np) = tp; 5490Sstevel@tonic-gate PARENT(tp) = np; 5500Sstevel@tonic-gate break; 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate } else if (SIZE(np) < size) { 5530Sstevel@tonic-gate if (RIGHT(np)) 5540Sstevel@tonic-gate np = RIGHT(np); 5550Sstevel@tonic-gate else { 5560Sstevel@tonic-gate RIGHT(np) = tp; 5570Sstevel@tonic-gate PARENT(tp) = np; 5580Sstevel@tonic-gate break; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate } else { 5610Sstevel@tonic-gate if ((sp = PARENT(np)) != NULL) { 5620Sstevel@tonic-gate if (np == LEFT(sp)) 5630Sstevel@tonic-gate LEFT(sp) = tp; 5640Sstevel@tonic-gate else 5650Sstevel@tonic-gate RIGHT(sp) = tp; 5660Sstevel@tonic-gate PARENT(tp) = sp; 5670Sstevel@tonic-gate } else 5680Sstevel@tonic-gate Root = tp; 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate /* insert to head of list */ 5710Sstevel@tonic-gate if ((sp = LEFT(np)) != NULL) 5720Sstevel@tonic-gate PARENT(sp) = tp; 5730Sstevel@tonic-gate LEFT(tp) = sp; 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate if ((sp = RIGHT(np)) != NULL) 5760Sstevel@tonic-gate PARENT(sp) = tp; 5770Sstevel@tonic-gate RIGHT(tp) = sp; 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate /* doubly link list */ 5800Sstevel@tonic-gate LINKFOR(tp) = np; 5810Sstevel@tonic-gate LINKBAK(np) = tp; 5820Sstevel@tonic-gate SETNOTREE(np); 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate break; 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate } else 5880Sstevel@tonic-gate Root = tp; 5890Sstevel@tonic-gate } 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /* tell next block that this one is free */ 5920Sstevel@tonic-gate SETBIT1(SIZE(NEXT(tp))); 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate ASSERT(ISBIT0(SIZE(NEXT(tp)))); 5950Sstevel@tonic-gate } 5960Sstevel@tonic-gate 5970Sstevel@tonic-gate /* 5980Sstevel@tonic-gate * Get more core. Gaps in memory are noted as busy blocks. 5990Sstevel@tonic-gate */ 6000Sstevel@tonic-gate static TREE * 6010Sstevel@tonic-gate _morecore(size_t size) 6020Sstevel@tonic-gate { 6030Sstevel@tonic-gate TREE *tp; 6040Sstevel@tonic-gate ssize_t n, offset; 6050Sstevel@tonic-gate char *addr; 6060Sstevel@tonic-gate ssize_t nsize; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate /* compute new amount of memory to get */ 6090Sstevel@tonic-gate tp = Bottom; 6100Sstevel@tonic-gate n = (ssize_t)size + 2 * WORDSIZE; 6110Sstevel@tonic-gate addr = GETCORE(0); 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate if (addr == ERRCORE) 6140Sstevel@tonic-gate return (NULL); 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate /* need to pad size out so that addr is aligned */ 6170Sstevel@tonic-gate if ((((uintptr_t)addr) % ALIGN) != 0) 6180Sstevel@tonic-gate offset = ALIGN - (uintptr_t)addr % ALIGN; 6190Sstevel@tonic-gate else 6200Sstevel@tonic-gate offset = 0; 6210Sstevel@tonic-gate 6220Sstevel@tonic-gate #ifndef SEGMENTED 6230Sstevel@tonic-gate /* if not segmented memory, what we need may be smaller */ 6240Sstevel@tonic-gate if (addr == Baddr) { 6250Sstevel@tonic-gate n -= WORDSIZE; 6260Sstevel@tonic-gate if (tp != NULL) 6270Sstevel@tonic-gate n -= SIZE(tp); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate #endif 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate /* get a multiple of CORESIZE */ 6320Sstevel@tonic-gate n = ((n - 1) / CORESIZE + 1) * CORESIZE; 6330Sstevel@tonic-gate nsize = n + offset; 6340Sstevel@tonic-gate 6350Sstevel@tonic-gate /* check if nsize request could overflow in GETCORE */ 6360Sstevel@tonic-gate if ((size_t)nsize > MAX_MALLOC - (uintptr_t)addr) { 6370Sstevel@tonic-gate errno = ENOMEM; 6380Sstevel@tonic-gate return (NULL); 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate if ((size_t)nsize <= MAX_GETCORE) { 6420Sstevel@tonic-gate if (GETCORE(nsize) == ERRCORE) 6430Sstevel@tonic-gate return (NULL); 6440Sstevel@tonic-gate } else { 6450Sstevel@tonic-gate intptr_t delta; 6460Sstevel@tonic-gate /* 6470Sstevel@tonic-gate * the value required is too big for GETCORE() to deal with 6480Sstevel@tonic-gate * in one go, so use GETCORE() at most 2 times instead. 6490Sstevel@tonic-gate * Argument to GETCORE() must be multiple of ALIGN. 6500Sstevel@tonic-gate * If not, GETCORE(-MAX_GETCORE) will not return brk point 6510Sstevel@tonic-gate * to previous value, but will be ALIGN more. 6520Sstevel@tonic-gate * This would leave a small hole. 6530Sstevel@tonic-gate */ 6540Sstevel@tonic-gate delta = MAX_GETCORE; 6550Sstevel@tonic-gate while (delta > 0) { 6560Sstevel@tonic-gate if (GETCORE(delta) == ERRCORE) { 6570Sstevel@tonic-gate if (addr != GETCORE(0)) 6580Sstevel@tonic-gate (void) GETCORE(-MAX_GETCORE); 6590Sstevel@tonic-gate return (NULL); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate nsize -= MAX_GETCORE; 6620Sstevel@tonic-gate delta = nsize; 6630Sstevel@tonic-gate } 6640Sstevel@tonic-gate } 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate /* contiguous memory */ 6670Sstevel@tonic-gate if (addr == Baddr) { 6680Sstevel@tonic-gate ASSERT(offset == 0); 6690Sstevel@tonic-gate if (tp) { 6700Sstevel@tonic-gate addr = (char *)tp; 6710Sstevel@tonic-gate n += SIZE(tp) + 2 * WORDSIZE; 6720Sstevel@tonic-gate } else { 6730Sstevel@tonic-gate addr = Baddr - WORDSIZE; 6740Sstevel@tonic-gate n += WORDSIZE; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate } else 6770Sstevel@tonic-gate addr += offset; 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate /* new bottom address */ 6800Sstevel@tonic-gate Baddr = addr + n; 6810Sstevel@tonic-gate 6820Sstevel@tonic-gate /* new bottom block */ 6830Sstevel@tonic-gate tp = (TREE *)(uintptr_t)addr; 6840Sstevel@tonic-gate SIZE(tp) = n - 2 * WORDSIZE; 6850Sstevel@tonic-gate ASSERT((SIZE(tp) % ALIGN) == 0); 6860Sstevel@tonic-gate 6870Sstevel@tonic-gate /* reserved the last word to head any noncontiguous memory */ 6880Sstevel@tonic-gate SETBIT0(SIZE(NEXT(tp))); 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate /* non-contiguous memory, free old bottom block */ 6910Sstevel@tonic-gate if (Bottom && Bottom != tp) { 6920Sstevel@tonic-gate SETBIT0(SIZE(Bottom)); 6930Sstevel@tonic-gate realfree(DATA(Bottom)); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate return (tp); 6970Sstevel@tonic-gate } 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * Tree rotation functions (BU: bottom-up, TD: top-down) 7020Sstevel@tonic-gate */ 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate #define LEFT1(x, y) \ 7050Sstevel@tonic-gate if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\ 7060Sstevel@tonic-gate if ((PARENT(y) = PARENT(x)) != NULL)\ 7070Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ 7080Sstevel@tonic-gate else RIGHT(PARENT(y)) = y;\ 7090Sstevel@tonic-gate LEFT(y) = x; PARENT(x) = y 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate #define RIGHT1(x, y) \ 7120Sstevel@tonic-gate if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\ 7130Sstevel@tonic-gate if ((PARENT(y) = PARENT(x)) != NULL)\ 7140Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(y)) = y;\ 7150Sstevel@tonic-gate else RIGHT(PARENT(y)) = y;\ 7160Sstevel@tonic-gate RIGHT(y) = x; PARENT(x) = y 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate #define BULEFT2(x, y, z) \ 7190Sstevel@tonic-gate if ((RIGHT(x) = LEFT(y)) != NULL) PARENT(RIGHT(x)) = x;\ 7200Sstevel@tonic-gate if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\ 7210Sstevel@tonic-gate if ((PARENT(z) = PARENT(x)) != NULL)\ 7220Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 7230Sstevel@tonic-gate else RIGHT(PARENT(z)) = z;\ 7240Sstevel@tonic-gate LEFT(z) = y; PARENT(y) = z; LEFT(y) = x; PARENT(x) = y 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate #define BURIGHT2(x, y, z) \ 7270Sstevel@tonic-gate if ((LEFT(x) = RIGHT(y)) != NULL) PARENT(LEFT(x)) = x;\ 7280Sstevel@tonic-gate if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\ 7290Sstevel@tonic-gate if ((PARENT(z) = PARENT(x)) != NULL)\ 7300Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 7310Sstevel@tonic-gate else RIGHT(PARENT(z)) = z;\ 7320Sstevel@tonic-gate RIGHT(z) = y; PARENT(y) = z; RIGHT(y) = x; PARENT(x) = y 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate #define TDLEFT2(x, y, z) \ 7350Sstevel@tonic-gate if ((RIGHT(y) = LEFT(z)) != NULL) PARENT(RIGHT(y)) = y;\ 7360Sstevel@tonic-gate if ((PARENT(z) = PARENT(x)) != NULL)\ 7370Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 7380Sstevel@tonic-gate else RIGHT(PARENT(z)) = z;\ 7390Sstevel@tonic-gate PARENT(x) = z; LEFT(z) = x; 7400Sstevel@tonic-gate 7410Sstevel@tonic-gate #define TDRIGHT2(x, y, z) \ 7420Sstevel@tonic-gate if ((LEFT(y) = RIGHT(z)) != NULL) PARENT(LEFT(y)) = y;\ 7430Sstevel@tonic-gate if ((PARENT(z) = PARENT(x)) != NULL)\ 7440Sstevel@tonic-gate if (LEFT(PARENT(x)) == x) LEFT(PARENT(z)) = z;\ 7450Sstevel@tonic-gate else RIGHT(PARENT(z)) = z;\ 7460Sstevel@tonic-gate PARENT(x) = z; RIGHT(z) = x; 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate /* 7490Sstevel@tonic-gate * Delete a tree element 7500Sstevel@tonic-gate */ 7510Sstevel@tonic-gate static void 7520Sstevel@tonic-gate t_delete(TREE *op) 7530Sstevel@tonic-gate { 7540Sstevel@tonic-gate TREE *tp, *sp, *gp; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate /* if this is a non-tree node */ 7570Sstevel@tonic-gate if (ISNOTREE(op)) { 7580Sstevel@tonic-gate tp = LINKBAK(op); 7590Sstevel@tonic-gate if ((sp = LINKFOR(op)) != NULL) 7600Sstevel@tonic-gate LINKBAK(sp) = tp; 7610Sstevel@tonic-gate LINKFOR(tp) = sp; 7620Sstevel@tonic-gate return; 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate /* make op the root of the tree */ 7660Sstevel@tonic-gate if (PARENT(op)) 7670Sstevel@tonic-gate t_splay(op); 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* if this is the start of a list */ 7700Sstevel@tonic-gate if ((tp = LINKFOR(op)) != NULL) { 7710Sstevel@tonic-gate PARENT(tp) = NULL; 7720Sstevel@tonic-gate if ((sp = LEFT(op)) != NULL) 7730Sstevel@tonic-gate PARENT(sp) = tp; 7740Sstevel@tonic-gate LEFT(tp) = sp; 7750Sstevel@tonic-gate 7760Sstevel@tonic-gate if ((sp = RIGHT(op)) != NULL) 7770Sstevel@tonic-gate PARENT(sp) = tp; 7780Sstevel@tonic-gate RIGHT(tp) = sp; 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate Root = tp; 7810Sstevel@tonic-gate return; 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate /* if op has a non-null left subtree */ 7850Sstevel@tonic-gate if ((tp = LEFT(op)) != NULL) { 7860Sstevel@tonic-gate PARENT(tp) = NULL; 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate if (RIGHT(op)) { 7890Sstevel@tonic-gate /* make the right-end of the left subtree its root */ 7900Sstevel@tonic-gate while ((sp = RIGHT(tp)) != NULL) { 7910Sstevel@tonic-gate if ((gp = RIGHT(sp)) != NULL) { 7920Sstevel@tonic-gate TDLEFT2(tp, sp, gp); 7930Sstevel@tonic-gate tp = gp; 7940Sstevel@tonic-gate } else { 7950Sstevel@tonic-gate LEFT1(tp, sp); 7960Sstevel@tonic-gate tp = sp; 7970Sstevel@tonic-gate } 7980Sstevel@tonic-gate } 7990Sstevel@tonic-gate 8000Sstevel@tonic-gate /* hook the right subtree of op to the above elt */ 8010Sstevel@tonic-gate RIGHT(tp) = RIGHT(op); 8020Sstevel@tonic-gate PARENT(RIGHT(tp)) = tp; 8030Sstevel@tonic-gate } 8040Sstevel@tonic-gate } else if ((tp = RIGHT(op)) != NULL) /* no left subtree */ 8050Sstevel@tonic-gate PARENT(tp) = NULL; 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate Root = tp; 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * Bottom up splaying (simple version). 8120Sstevel@tonic-gate * The basic idea is to roughly cut in half the 8130Sstevel@tonic-gate * path from Root to tp and make tp the new root. 8140Sstevel@tonic-gate */ 8150Sstevel@tonic-gate static void 8160Sstevel@tonic-gate t_splay(TREE *tp) 8170Sstevel@tonic-gate { 8180Sstevel@tonic-gate TREE *pp, *gp; 8190Sstevel@tonic-gate 8200Sstevel@tonic-gate /* iterate until tp is the root */ 8210Sstevel@tonic-gate while ((pp = PARENT(tp)) != NULL) { 8220Sstevel@tonic-gate /* grandparent of tp */ 8230Sstevel@tonic-gate gp = PARENT(pp); 8240Sstevel@tonic-gate 8250Sstevel@tonic-gate /* x is a left child */ 8260Sstevel@tonic-gate if (LEFT(pp) == tp) { 8270Sstevel@tonic-gate if (gp && LEFT(gp) == pp) { 8280Sstevel@tonic-gate BURIGHT2(gp, pp, tp); 8290Sstevel@tonic-gate } else { 8300Sstevel@tonic-gate RIGHT1(pp, tp); 8310Sstevel@tonic-gate } 8320Sstevel@tonic-gate } else { 8330Sstevel@tonic-gate ASSERT(RIGHT(pp) == tp); 8340Sstevel@tonic-gate if (gp && RIGHT(gp) == pp) { 8350Sstevel@tonic-gate BULEFT2(gp, pp, tp); 8360Sstevel@tonic-gate } else { 8370Sstevel@tonic-gate LEFT1(pp, tp); 8380Sstevel@tonic-gate } 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate } 8410Sstevel@tonic-gate } 8420Sstevel@tonic-gate 8430Sstevel@tonic-gate 8440Sstevel@tonic-gate /* 8450Sstevel@tonic-gate * free(). 8460Sstevel@tonic-gate * Performs a delayed free of the block pointed to 8470Sstevel@tonic-gate * by old. The pointer to old is saved on a list, flist, 8480Sstevel@tonic-gate * until the next malloc or realloc. At that time, all the 8490Sstevel@tonic-gate * blocks pointed to in flist are actually freed via 8500Sstevel@tonic-gate * realfree(). This allows the contents of free blocks to 8510Sstevel@tonic-gate * remain undisturbed until the next malloc or realloc. 8520Sstevel@tonic-gate */ 8530Sstevel@tonic-gate void 8540Sstevel@tonic-gate free(void *old) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate assert_no_libc_locks_held(); 857*2186Sraf (void) _private_mutex_lock(&libc_malloc_lock); 8580Sstevel@tonic-gate _free_unlocked(old); 859*2186Sraf (void) _private_mutex_unlock(&libc_malloc_lock); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate void 8640Sstevel@tonic-gate _free_unlocked(void *old) 8650Sstevel@tonic-gate { 8660Sstevel@tonic-gate int i; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate if (old == NULL || !primary_link_map) 8690Sstevel@tonic-gate return; 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate /* 8720Sstevel@tonic-gate * Make sure the same data block is not freed twice. 8730Sstevel@tonic-gate * 3 cases are checked. It returns immediately if either 8740Sstevel@tonic-gate * one of the conditions is true. 8750Sstevel@tonic-gate * 1. Last freed. 8760Sstevel@tonic-gate * 2. Not in use or freed already. 8770Sstevel@tonic-gate * 3. In the free list. 8780Sstevel@tonic-gate */ 8790Sstevel@tonic-gate if (old == Lfree) 8800Sstevel@tonic-gate return; 8810Sstevel@tonic-gate if (!ISBIT0(SIZE(BLOCK(old)))) 8820Sstevel@tonic-gate return; 8830Sstevel@tonic-gate for (i = 0; i < freeidx; i++) 8840Sstevel@tonic-gate if (old == flist[i]) 8850Sstevel@tonic-gate return; 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate if (flist[freeidx] != NULL) 8880Sstevel@tonic-gate realfree(flist[freeidx]); 8890Sstevel@tonic-gate flist[freeidx] = Lfree = old; 8900Sstevel@tonic-gate freeidx = (freeidx + 1) & FREEMASK; /* one forward */ 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate /* 8940Sstevel@tonic-gate * cleanfree() frees all the blocks pointed to be flist. 8950Sstevel@tonic-gate * 8960Sstevel@tonic-gate * realloc() should work if it is called with a pointer 8970Sstevel@tonic-gate * to a block that was freed since the last call to malloc() or 8980Sstevel@tonic-gate * realloc(). If cleanfree() is called from realloc(), ptr 8990Sstevel@tonic-gate * is set to the old block and that block should not be 9000Sstevel@tonic-gate * freed since it is actually being reallocated. 9010Sstevel@tonic-gate */ 9020Sstevel@tonic-gate static void 9030Sstevel@tonic-gate cleanfree(void *ptr) 9040Sstevel@tonic-gate { 9050Sstevel@tonic-gate char **flp; 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate flp = (char **)&(flist[freeidx]); 9080Sstevel@tonic-gate for (;;) { 9090Sstevel@tonic-gate if (flp == (char **)&(flist[0])) 9100Sstevel@tonic-gate flp = (char **)&(flist[FREESIZE]); 9110Sstevel@tonic-gate if (*--flp == NULL) 9120Sstevel@tonic-gate break; 9130Sstevel@tonic-gate if (*flp != ptr) 9140Sstevel@tonic-gate realfree(*flp); 9150Sstevel@tonic-gate *flp = NULL; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate freeidx = 0; 9180Sstevel@tonic-gate Lfree = NULL; 9190Sstevel@tonic-gate } 920