Home | History | Annotate | Download | only in common
      1     0  stevel /*
      2     0  stevel  * CDDL HEADER START
      3     0  stevel  *
      4     0  stevel  * The contents of this file are subject to the terms of the
      5  2658     raf  * Common Development and Distribution License (the "License").
      6  2658     raf  * You may not use this file except in compliance with the License.
      7     0  stevel  *
      8     0  stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0  stevel  * or http://www.opensolaris.org/os/licensing.
     10     0  stevel  * See the License for the specific language governing permissions
     11     0  stevel  * and limitations under the License.
     12     0  stevel  *
     13     0  stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0  stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0  stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0  stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0  stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0  stevel  *
     19     0  stevel  * CDDL HEADER END
     20     0  stevel  */
     21    35  craigm 
     22     0  stevel /*
     23  6812     raf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24    35  craigm  * Use is subject to license terms.
     25     0  stevel  */
     26     0  stevel 
     27     0  stevel /*	Copyright (c) 1988 AT&T	*/
     28     0  stevel /*	  All Rights Reserved	*/
     29     0  stevel 
     30    35  craigm #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31     0  stevel 
     32     0  stevel /*
     33     0  stevel  *	Memory management: malloc(), realloc(), free(), memalign().
     34     0  stevel  *
     35     0  stevel  *	The following #-parameters may be redefined:
     36     0  stevel  *	GETCORE: a function to get more core memory.
     37     0  stevel  *		GETCORE(0) is assumed to return the next available
     38     0  stevel  *		address. Default is 'sbrk'.
     39     0  stevel  *	ERRCORE: the error code as returned by GETCORE.
     40     0  stevel  *		Default is ((char *)(-1)).
     41     0  stevel  *	CORESIZE: a desired unit (measured in bytes) to be used
     42     0  stevel  *		with GETCORE. Default is (1024*ALIGN).
     43     0  stevel  *
     44     0  stevel  *	This algorithm is based on a best fit strategy with lists of
     45     0  stevel  *	free elts maintained in a self-adjusting binary tree. Each list
     46     0  stevel  *	contains all elts of the same size. The tree is ordered by size.
     47     0  stevel  *	For results on self-adjusting trees, see the paper:
     48     0  stevel  *		Self-Adjusting Binary Trees,
     49     0  stevel  *		DD Sleator & RE Tarjan, JACM 1985.
     50     0  stevel  *
     51     0  stevel  *	The header of a block contains the size of the data part in bytes.
     52     0  stevel  *	Since the size of a block is 0%4, the low two bits of the header
     53     0  stevel  *	are free and used as follows:
     54     0  stevel  *
     55     0  stevel  *		BIT0:	1 for busy (block is in use), 0 for free.
     56     0  stevel  *		BIT1:	if the block is busy, this bit is 1 if the
     57     0  stevel  *			preceding block in contiguous memory is free.
     58     0  stevel  *			Otherwise, it is always 0.
     59     0  stevel  */
     60     0  stevel 
     61     0  stevel #include "mallint.h"
     62     0  stevel 
     63     0  stevel static	mutex_t	__watch_malloc_lock = DEFAULTMUTEX;
     64     0  stevel 
     65     0  stevel static	TREE	*Root;		/* root of the free tree */
     66     0  stevel static	TREE	*Bottom;	/* the last free chunk in the arena */
     67     0  stevel static	char	*Baddr;		/* current high address of the arena */
     68     0  stevel 
     69     0  stevel static	void	t_delete(TREE *);
     70     0  stevel static	void	t_splay(TREE *);
     71     0  stevel static	void	realfree(void *);
     72     0  stevel static	void	*malloc_unlocked(size_t);
     73     0  stevel static	void	free_unlocked(void *);
     74     0  stevel static	TREE	*morecore(size_t);
     75     0  stevel 
     76     0  stevel static	void	protect(TREE *);
     77     0  stevel static	void	unprotect(TREE *);
     78     0  stevel 
     79     0  stevel #define	FREEPAT	0
     80     0  stevel #define	LIVEPAT	1
     81     0  stevel 
     82     0  stevel /*
     83     0  stevel  * Patterns to be copied into freed blocks and allocated blocks.
     84     0  stevel  * 0xfeedbeef and 0xfeedface are invalid pointer values in all programs.
     85     0  stevel  */
     86     0  stevel static	uint64_t	patterns[2] = {
     87    35  craigm 	0xdeadbeefdeadbeefULL,	/* pattern in a freed block */
     88    35  craigm 	0xbaddcafebaddcafeULL	/* pattern in an allocated block */
     89     0  stevel };
     90     0  stevel 
     91     0  stevel static void
     92     0  stevel copy_pattern(int pat, TREE *tp)
     93     0  stevel {
     94     0  stevel 	uint64_t pattern = patterns[pat];
     95     0  stevel 	size_t sz = SIZE(tp) / sizeof (uint64_t);
     96     0  stevel 	/* LINTED improper alignment */
     97     0  stevel 	uint64_t *datap = (uint64_t *)DATA(tp);
     98     0  stevel 
     99     0  stevel 	while (sz--)
    100     0  stevel 		*datap++ = pattern;
    101     0  stevel }
    102     0  stevel 
    103     0  stevel /*
    104     0  stevel  * Keep lists of small blocks, LIFO order.
    105     0  stevel  */
    106     0  stevel static	TREE	*List[MINSIZE/WORDSIZE-1];
    107     0  stevel static	TREE	*Last[MINSIZE/WORDSIZE-1];
    108     0  stevel 
    109     0  stevel /* number of blocks to get at one time */
    110     0  stevel #define	NPS	(WORDSIZE*8)
    111     0  stevel 
    112     0  stevel static void *
    113     0  stevel smalloc(size_t size)
    114     0  stevel {
    115     0  stevel 	TREE	*tp;
    116     0  stevel 	size_t	i;
    117     0  stevel 
    118     0  stevel 	ASSERT(size % WORDSIZE == 0);
    119     0  stevel 	/* want to return a unique pointer on malloc(0) */
    120     0  stevel 	if (size == 0)
    121     0  stevel 		size = WORDSIZE;
    122     0  stevel 
    123     0  stevel 	/* list to use */
    124     0  stevel 	i = size / WORDSIZE - 1;
    125     0  stevel 
    126     0  stevel 	if (List[i] == NULL) {
    127     0  stevel 		TREE	*np;
    128     0  stevel 		int	n;
    129     0  stevel 		ASSERT((size + WORDSIZE) * NPS >= MINSIZE);
    130     0  stevel 
    131     0  stevel 		/* get NPS of these block types */
    132     0  stevel 		if ((np = malloc_unlocked((size + WORDSIZE)*NPS)) == NULL)
    133     0  stevel 			return (NULL);
    134     0  stevel 
    135     0  stevel 		/* make them into a link list */
    136     0  stevel 		for (n = 0, List[i] = np; n < NPS; ++n) {
    137     0  stevel 			tp = np;
    138     0  stevel 			SIZE(tp) = size;
    139     0  stevel 			copy_pattern(FREEPAT, tp);
    140     0  stevel 			if (n == NPS - 1) {
    141     0  stevel 				Last[i] = tp;
    142     0  stevel 				np = NULL;
    143     0  stevel 			} else {
    144     0  stevel 				/* LINTED improper alignment */
    145     0  stevel 				np = NEXT(tp);
    146     0  stevel 			}
    147     0  stevel 			AFTER(tp) = np;
    148     0  stevel 			protect(tp);
    149     0  stevel 		}
    150     0  stevel 	}
    151     0  stevel 
    152     0  stevel 	/* allocate from the head of the queue */
    153     0  stevel 	tp = List[i];
    154     0  stevel 	unprotect(tp);
    155     0  stevel 	if ((List[i] = AFTER(tp)) == NULL)
    156     0  stevel 		Last[i] = NULL;
    157     0  stevel 	copy_pattern(LIVEPAT, tp);
    158     0  stevel 	SETBIT0(SIZE(tp));
    159     0  stevel 	protect(tp);
    160     0  stevel 	return (DATA(tp));
    161     0  stevel }
    162     0  stevel 
    163     0  stevel void *
    164     0  stevel malloc(size_t size)
    165     0  stevel {
    166     0  stevel 	void	*ret;
    167  3866     raf 	(void) mutex_lock(&__watch_malloc_lock);
    168     0  stevel 	ret = malloc_unlocked(size);
    169  3866     raf 	(void) mutex_unlock(&__watch_malloc_lock);
    170     0  stevel 	return (ret);
    171     0  stevel }
    172     0  stevel 
    173     0  stevel static void *
    174     0  stevel malloc_unlocked(size_t size)
    175     0  stevel {
    176     0  stevel 	size_t	n;
    177     0  stevel 	TREE	*tp, *sp, *tmp;
    178     0  stevel 
    179     0  stevel 	COUNT(nmalloc);
    180     0  stevel 	ASSERT(WORDSIZE == ALIGN);
    181     0  stevel 
    182     0  stevel 	/* check for size that could overflow calculations */
    183     0  stevel 	if (size > MAX_MALLOC) {
    184     0  stevel 		errno = ENOMEM;
    185     0  stevel 		return (NULL);
    186     0  stevel 	}
    187     0  stevel 	/* make sure that size is 0 mod ALIGN */
    188     0  stevel 	ROUND(size);
    189     0  stevel 
    190     0  stevel 	/* small blocks */
    191     0  stevel 	if (size < MINSIZE)
    192     0  stevel 		return (smalloc(size));
    193     0  stevel 
    194     0  stevel 	/* search for an elt of the right size */
    195     0  stevel 	sp = NULL;
    196     0  stevel 	n = 0;
    197     0  stevel 	if (Root) {
    198     0  stevel 		tp = Root;
    199     0  stevel 		for (;;) {
    200     0  stevel 			unprotect(tp);
    201     0  stevel 			if (SIZE(tp) >= size) {	/* branch left */
    202     0  stevel 				if (n == 0 || n >= SIZE(tp)) {
    203     0  stevel 					sp = tp;
    204     0  stevel 					n = SIZE(tp);
    205     0  stevel 				}
    206     0  stevel 				if ((tmp = LEFT(tp)) != NULL) {
    207     0  stevel 					protect(tp);
    208     0  stevel 					tp = tmp;
    209     0  stevel 				} else {
    210     0  stevel 					protect(tp);
    211     0  stevel 					break;
    212     0  stevel 				}
    213     0  stevel 			} else {		/* branch right */
    214     0  stevel 				if ((tmp = RIGHT(tp)) != NULL) {
    215     0  stevel 					protect(tp);
    216     0  stevel 					tp = tmp;
    217     0  stevel 				} else {
    218     0  stevel 					protect(tp);
    219     0  stevel 					break;
    220     0  stevel 				}
    221     0  stevel 			}
    222     0  stevel 		}
    223     0  stevel 
    224     0  stevel 		if (sp) {
    225     0  stevel 			unprotect(sp);
    226     0  stevel 			t_delete(sp);
    227     0  stevel 		} else if (tp != Root) {
    228     0  stevel 			/* make the searched-to element the root */
    229     0  stevel 			unprotect(tp);
    230     0  stevel 			t_splay(tp);
    231     0  stevel 			protect(tp);
    232     0  stevel 			Root = tp;
    233     0  stevel 		}
    234     0  stevel 	}
    235     0  stevel 
    236     0  stevel 	/* if found none fitted in the tree */
    237     0  stevel 	if (sp == NULL) {
    238     0  stevel 		if (Bottom) {
    239     0  stevel 			unprotect(Bottom);
    240     0  stevel 			if (size <= SIZE(Bottom)) {
    241     0  stevel 				sp = Bottom;
    242     0  stevel 				CLRBITS01(SIZE(sp));
    243     0  stevel 			} else {
    244     0  stevel 				protect(Bottom);
    245     0  stevel 				if ((sp = morecore(size)) == NULL)
    246     0  stevel 					return (NULL);
    247     0  stevel 			}
    248     0  stevel 		} else {
    249     0  stevel 			if ((sp = morecore(size)) == NULL)
    250     0  stevel 				return (NULL);
    251     0  stevel 		}
    252     0  stevel 	}
    253     0  stevel 
    254     0  stevel 	/* tell the forward neighbor that we're busy */
    255     0  stevel 	/* LINTED improper alignment */
    256     0  stevel 	tmp = NEXT(sp);
    257     0  stevel 	unprotect(tmp);
    258     0  stevel 	CLRBIT1(SIZE(tmp));
    259     0  stevel 	ASSERT(ISBIT0(SIZE(tmp)));
    260     0  stevel 	protect(tmp);
    261     0  stevel 
    262     0  stevel leftover:
    263     0  stevel 	/* if the leftover is enough for a new free piece */
    264     0  stevel 	if ((n = (SIZE(sp) - size)) >= MINSIZE + WORDSIZE) {
    265     0  stevel 		n -= WORDSIZE;
    266     0  stevel 		SIZE(sp) = size;
    267     0  stevel 		/* LINTED improper alignment */
    268     0  stevel 		tp = NEXT(sp);
    269     0  stevel 		SIZE(tp) = n | BIT0;
    270     0  stevel 		realfree(DATA(tp));
    271     0  stevel 	} else if (BOTTOM(sp))
    272     0  stevel 		Bottom = NULL;
    273     0  stevel 
    274     0  stevel 	/* return the allocated space */
    275     0  stevel 	copy_pattern(LIVEPAT, sp);
    276     0  stevel 	SIZE(sp) |= BIT0;
    277     0  stevel 	protect(sp);
    278     0  stevel 	return (DATA(sp));
    279     0  stevel }
    280     0  stevel 
    281     0  stevel /*
    282     0  stevel  *	realloc().
    283     0  stevel  *	If the block size is increasing, we try forward merging first.
    284     0  stevel  *	This is not best-fit but it avoids some data recopying.
    285     0  stevel  */
    286     0  stevel void *
    287     0  stevel realloc(void *old, size_t size)
    288     0  stevel {
    289     0  stevel 	TREE	*tp, *np;
    290     0  stevel 	size_t	ts;
    291     0  stevel 	char	*new;
    292     0  stevel 
    293     0  stevel 	COUNT(nrealloc);
    294     0  stevel 
    295     0  stevel 	/* check for size that could overflow calculations */
    296     0  stevel 	if (size > MAX_MALLOC) {
    297     0  stevel 		errno = ENOMEM;
    298     0  stevel 		return (NULL);
    299     0  stevel 	}
    300     0  stevel 
    301     0  stevel 	/* pointer to the block */
    302  3866     raf 	(void) mutex_lock(&__watch_malloc_lock);
    303     0  stevel 	if (old == NULL) {
    304     0  stevel 		new = malloc_unlocked(size);
    305  3866     raf 		(void) mutex_unlock(&__watch_malloc_lock);
    306     0  stevel 		return (new);
    307     0  stevel 	}
    308     0  stevel 
    309     0  stevel 	/* make sure that size is 0 mod ALIGN */
    310     0  stevel 	ROUND(size);
    311     0  stevel 
    312     0  stevel 	/* LINTED improper alignment */
    313     0  stevel 	tp = BLOCK(old);
    314     0  stevel 	unprotect(tp);
    315     0  stevel 	ts = SIZE(tp);
    316     0  stevel 
    317     0  stevel 	/* if the block was freed, data has been destroyed. */
    318     0  stevel 	if (!ISBIT0(ts)) {
    319     0  stevel 		/* XXX; complain here! */
    320     0  stevel 		protect(tp);
    321  3866     raf 		(void) mutex_unlock(&__watch_malloc_lock);
    322     0  stevel 		errno = EINVAL;
    323     0  stevel 		return (NULL);
    324     0  stevel 	}
    325     0  stevel 
    326     0  stevel 	CLRBITS01(SIZE(tp));
    327     0  stevel 	if (size == SIZE(tp)) {	/* nothing to do */
    328     0  stevel 		SIZE(tp) = ts;
    329     0  stevel 		protect(tp);
    330  3866     raf 		(void) mutex_unlock(&__watch_malloc_lock);
    331     0  stevel 		return (old);
    332     0  stevel 	}
    333     0  stevel 
    334     0  stevel 	/* special cases involving small blocks */
    335     0  stevel 	if (size < MINSIZE || SIZE(tp) < MINSIZE) {
    336     0  stevel 		if (size == 0) {
    337     0  stevel 			SETOLD01(SIZE(tp), ts);
    338     0  stevel 			free_unlocked(old);
    339  3866     raf 			(void) mutex_unlock(&__watch_malloc_lock);
    340     0  stevel 			return (NULL);
    341     0  stevel 		}
    342     0  stevel 		goto call_malloc;
    343     0  stevel 	}
    344     0  stevel 
    345     0  stevel 	/* block is increasing in size, try merging the next block */
    346     0  stevel 	if (size > SIZE(tp)) {
    347     0  stevel 		/* LINTED improper alignment */
    348     0  stevel 		np = NEXT(tp);
    349     0  stevel 		unprotect(np);
    350     0  stevel 		if (ISBIT0(SIZE(np)))
    351     0  stevel 			protect(np);
    352     0  stevel 		else {
    353     0  stevel 			TREE *tmp;
    354     0  stevel 			ASSERT(SIZE(np) >= MINSIZE);
    355     0  stevel 			ASSERT(!ISBIT1(SIZE(np)));
    356     0  stevel 			SIZE(tp) += SIZE(np) + WORDSIZE;
    357     0  stevel 			if (np != Bottom)
    358     0  stevel 				t_delete(np);
    359     0  stevel 			else
    360     0  stevel 				Bottom = NULL;
    361     0  stevel 			/* LINTED improper alignment */
    362     0  stevel 			tmp = NEXT(np);
    363     0  stevel 			unprotect(tmp);
    364     0  stevel 			CLRBIT1(SIZE(tmp));
    365     0  stevel 			protect(tmp);
    366     0  stevel 		}
    367     0  stevel 
    368     0  stevel 		/* not enough & at TRUE end of memory, try extending core */
    369     0  stevel 		if (size > SIZE(tp) && BOTTOM(tp) && GETCORE(0) == Baddr) {
    370     0  stevel 			Bottom = tp;
    371     0  stevel 			protect(Bottom);
    372     0  stevel 			if ((tp = morecore(size)) == NULL) {
    373     0  stevel 				tp = Bottom;
    374     0  stevel 				Bottom = NULL;
    375     0  stevel 				unprotect(tp);
    376     0  stevel 			}
    377     0  stevel 		}
    378     0  stevel 	}
    379     0  stevel 
    380     0  stevel 	/* got enough space to use */
    381     0  stevel 	if (size <= SIZE(tp)) {
    382     0  stevel 		size_t n;
    383     0  stevel chop_big:
    384     0  stevel 		if ((n = (SIZE(tp) - size)) >= MINSIZE + WORDSIZE) {
    385     0  stevel 			n -= WORDSIZE;
    386     0  stevel 			SIZE(tp) = size;
    387     0  stevel 			/* LINTED improper alignment */
    388     0  stevel 			np = NEXT(tp);
    389     0  stevel 			SIZE(np) = n | BIT0;
    390     0  stevel 			realfree(DATA(np));
    391     0  stevel 		} else if (BOTTOM(tp))
    392     0  stevel 			Bottom = NULL;
    393     0  stevel 
    394     0  stevel 		/* the previous block may be free */
    395     0  stevel 		SETOLD01(SIZE(tp), ts);
    396     0  stevel 		protect(tp);
    397  3866     raf 		(void) mutex_unlock(&__watch_malloc_lock);
    398     0  stevel 		return (old);
    399     0  stevel 	}
    400     0  stevel 
    401     0  stevel call_malloc:	/* call malloc to get a new block */
    402     0  stevel 	SETOLD01(SIZE(tp), ts);
    403     0  stevel 	if ((new = malloc_unlocked(size)) != NULL) {
    404     0  stevel 		CLRBITS01(ts);
    405     0  stevel 		if (ts > size)
    406     0  stevel 			ts = size;
    407     0  stevel 		(void) memcpy(new, old, ts);
    408     0  stevel 		free_unlocked(old);
    409  3866     raf 		(void) mutex_unlock(&__watch_malloc_lock);
    410     0  stevel 		return (new);
    411     0  stevel 	}
    412     0  stevel 
    413     0  stevel 	/*
    414     0  stevel 	 * Attempt special case recovery allocations since malloc() failed:
    415     0  stevel 	 *
    416     0  stevel 	 * 1. size <= SIZE(tp) < MINSIZE
    417     0  stevel 	 *	Simply return the existing block
    418     0  stevel 	 * 2. SIZE(tp) < size < MINSIZE
    419     0  stevel 	 *	malloc() may have failed to allocate the chunk of
    420     0  stevel 	 *	small blocks. Try asking for MINSIZE bytes.
    421     0  stevel 	 * 3. size < MINSIZE <= SIZE(tp)
    422     0  stevel 	 *	malloc() may have failed as with 2.  Change to
    423     0  stevel 	 *	MINSIZE allocation which is taken from the beginning
    424     0  stevel 	 *	of the current block.
    425     0  stevel 	 * 4. MINSIZE <= SIZE(tp) < size
    426     0  stevel 	 *	If the previous block is free and the combination of
    427     0  stevel 	 *	these two blocks has at least size bytes, then merge
    428     0  stevel 	 *	the two blocks copying the existing contents backwards.
    429     0  stevel 	 */
    430     0  stevel 	CLRBITS01(SIZE(tp));
    431     0  stevel 	if (SIZE(tp) < MINSIZE) {
    432     0  stevel 		if (size < SIZE(tp))		/* case 1. */ {
    433     0  stevel 			SETOLD01(SIZE(tp), ts);
    434     0  stevel 			protect(tp);
    435  3866     raf 			(void) mutex_unlock(&__watch_malloc_lock);
    436     0  stevel 			return (old);
    437     0  stevel 		} else if (size < MINSIZE)	/* case 2. */ {
    438     0  stevel 			size = MINSIZE;
    439     0  stevel 			goto call_malloc;
    440     0  stevel 		}
    441     0  stevel 	} else if (size < MINSIZE)		/* case 3. */ {
    442     0  stevel 		size = MINSIZE;
    443     0  stevel 		goto chop_big;
    444     0  stevel 	} else if (ISBIT1(ts)) {
    445     0  stevel 		np = LAST(tp);
    446     0  stevel 		unprotect(np);
    447     0  stevel 		if ((SIZE(np) + SIZE(tp) + WORDSIZE) >= size) {
    448     0  stevel 			ASSERT(!ISBIT0(SIZE(np)));
    449     0  stevel 			t_delete(np);
    450     0  stevel 			SIZE(np) += SIZE(tp) + WORDSIZE;
    451     0  stevel 			/*
    452     0  stevel 			 * Since the copy may overlap, use memmove().
    453     0  stevel 			 */
    454     0  stevel 			(void) memmove(DATA(np), old, SIZE(tp));
    455     0  stevel 			old = DATA(np);
    456     0  stevel 			tp = np;
    457     0  stevel 			CLRBIT1(ts);
    458     0  stevel 			goto chop_big;
    459     0  stevel 		}
    460     0  stevel 		protect(np);
    461     0  stevel 	}
    462     0  stevel 	SETOLD01(SIZE(tp), ts);
    463     0  stevel 	protect(tp);
    464  3866     raf 	(void) mutex_unlock(&__watch_malloc_lock);
    465     0  stevel 	/* malloc() sets errno */
    466     0  stevel 	return (NULL);
    467     0  stevel }
    468     0  stevel 
    469     0  stevel /*
    470     0  stevel  *	realfree().
    471     0  stevel  *	Coalescing of adjacent free blocks is done first.
    472     0  stevel  *	Then, the new free block is leaf-inserted into the free tree
    473     0  stevel  *	without splaying. This strategy does not guarantee the amortized
    474     0  stevel  *	O(nlogn) behaviour for the insert/delete/find set of operations
    475     0  stevel  *	on the tree. In practice, however, free is much more infrequent
    476     0  stevel  *	than malloc/realloc and the tree searches performed by these
    477     0  stevel  *	functions adequately keep the tree in balance.
    478     0  stevel  */
    479     0  stevel static void
    480     0  stevel realfree(void *old)
    481     0  stevel {
    482     0  stevel 	TREE	*tp, *sp, *np, *tmp;
    483     0  stevel 	size_t	ts, size;
    484     0  stevel 
    485     0  stevel 	COUNT(nfree);
    486     0  stevel 
    487     0  stevel 	/* pointer to the block */
    488     0  stevel 	/* LINTED improper alignment */
    489     0  stevel 	tp = BLOCK(old);
    490     0  stevel 	unprotect(tp);
    491     0  stevel 	ts = SIZE(tp);
    492     0  stevel 	if (!ISBIT0(ts)) {	/* block is not busy; previously freed? */
    493     0  stevel 		protect(tp);	/* force a watchpoint trap */
    494     0  stevel 		CLRBIT0(SIZE(tp));
    495     0  stevel 		return;
    496     0  stevel 	}
    497     0  stevel 	CLRBITS01(SIZE(tp));
    498     0  stevel 	copy_pattern(FREEPAT, tp);
    499     0  stevel 
    500     0  stevel 	/* small block, return it to the tail of its queue */
    501     0  stevel 	if (SIZE(tp) < MINSIZE) {
    502     0  stevel 		ASSERT(SIZE(tp) / WORDSIZE >= 1);
    503     0  stevel 		ts = SIZE(tp) / WORDSIZE - 1;
    504     0  stevel 		AFTER(tp) = NULL;
    505     0  stevel 		protect(tp);
    506     0  stevel 		if (List[ts] == NULL) {
    507     0  stevel 			List[ts] = tp;
    508     0  stevel 			Last[ts] = tp;
    509     0  stevel 		} else {
    510     0  stevel 			sp = Last[ts];
    511     0  stevel 			unprotect(sp);
    512     0  stevel 			AFTER(sp) = tp;
    513     0  stevel 			protect(sp);
    514     0  stevel 			Last[ts] = tp;
    515     0  stevel 		}
    516     0  stevel 		return;
    517     0  stevel 	}
    518     0  stevel 
    519     0  stevel 	/* see if coalescing with next block is warranted */
    520     0  stevel 	/* LINTED improper alignment */
    521     0  stevel 	np = NEXT(tp);
    522     0  stevel 	unprotect(np);
    523     0  stevel 	if (ISBIT0(SIZE(np)))
    524     0  stevel 		protect(np);
    525     0  stevel 	else {
    526     0  stevel 		if (np != Bottom)
    527     0  stevel 			t_delete(np);
    528     0  stevel 		SIZE(tp) += SIZE(np) + WORDSIZE;
    529     0  stevel 	}
    530     0  stevel 
    531     0  stevel 	/* the same with the preceding block */
    532     0  stevel 	if (ISBIT1(ts)) {
    533     0  stevel 		np = LAST(tp);
    534     0  stevel 		unprotect(np);
    535     0  stevel 		ASSERT(!ISBIT0(SIZE(np)));
    536     0  stevel 		ASSERT(np != Bottom);
    537     0  stevel 		t_delete(np);
    538     0  stevel 		SIZE(np) += SIZE(tp) + WORDSIZE;
    539     0  stevel 		tp = np;
    540     0  stevel 	}
    541     0  stevel 
    542     0  stevel 	/* initialize tree info */
    543     0  stevel 	PARENT(tp) = LEFT(tp) = RIGHT(tp) = LINKFOR(tp) = NULL;
    544     0  stevel 
    545     0  stevel 	/* set bottom block, or insert in the free tree */
    546     0  stevel 	if (BOTTOM(tp))
    547     0  stevel 		Bottom = tp;
    548     0  stevel 	else {
    549     0  stevel 		/* search for the place to insert */
    550     0  stevel 		if (Root) {
    551     0  stevel 			size = SIZE(tp);
    552     0  stevel 			np = Root;
    553     0  stevel 			for (;;) {
    554     0  stevel 				unprotect(np);
    555     0  stevel 				if (SIZE(np) > size) {
    556     0  stevel 					if ((tmp = LEFT(np)) != NULL) {
    557     0  stevel 						protect(np);
    558     0  stevel 						np = tmp;
    559     0  stevel 					} else {
    560     0  stevel 						LEFT(np) = tp;
    561     0  stevel 						PARENT(tp) = np;
    562     0  stevel 						protect(np);
    563     0  stevel 						break;
    564     0  stevel 					}
    565     0  stevel 				} else if (SIZE(np) < size) {
    566     0  stevel 					if ((tmp = RIGHT(np)) != NULL) {
    567     0  stevel 						protect(np);
    568     0  stevel 						np = tmp;
    569     0  stevel 					} else {
    570     0  stevel 						RIGHT(np) = tp;
    571     0  stevel 						PARENT(tp) = np;
    572     0  stevel 						protect(np);
    573     0  stevel 						break;
    574     0  stevel 					}
    575     0  stevel 				} else {
    576     0  stevel 					if ((sp = PARENT(np)) != NULL) {
    577     0  stevel 						unprotect(sp);
    578     0  stevel 						if (np == LEFT(sp))
    579     0  stevel 							LEFT(sp) = tp;
    580     0  stevel 						else
    581     0  stevel 							RIGHT(sp) = tp;
    582     0  stevel 						PARENT(tp) = sp;
    583     0  stevel 						protect(sp);
    584     0  stevel 					} else
    585     0  stevel 						Root = tp;
    586     0  stevel 
    587     0  stevel 					/* insert to head of list */
    588     0  stevel 					if ((sp = LEFT(np)) != NULL) {
    589     0  stevel 						unprotect(sp);
    590     0  stevel 						PARENT(sp) = tp;
    591     0  stevel 						protect(sp);
    592     0  stevel 					}
    593     0  stevel 					LEFT(tp) = sp;
    594     0  stevel 
    595     0  stevel 					if ((sp = RIGHT(np)) != NULL) {
    596     0  stevel 						unprotect(sp);
    597     0  stevel 						PARENT(sp) = tp;
    598     0  stevel 						protect(sp);
    599     0  stevel 					}
    600     0  stevel 					RIGHT(tp) = sp;
    601     0  stevel 
    602     0  stevel 					/* doubly link list */
    603     0  stevel 					LINKFOR(tp) = np;
    604     0  stevel 					LINKBAK(np) = tp;
    605     0  stevel 					SETNOTREE(np);
    606     0  stevel 					protect(np);
    607     0  stevel 
    608     0  stevel 					break;
    609     0  stevel 				}
    610     0  stevel 			}
    611     0  stevel 		} else {
    612     0  stevel 			Root = tp;
    613     0  stevel 		}
    614     0  stevel 	}
    615     0  stevel 
    616     0  stevel 	/*
    617     0  stevel 	 * Tell next block that this one is free.
    618     0  stevel 	 * The first WORD of the next block contains self's address.
    619     0  stevel 	 */
    620     0  stevel 	/* LINTED improper alignment */
    621     0  stevel 	tmp = NEXT(tp);
    622     0  stevel 	unprotect(tmp);
    623     0  stevel 	/* LINTED improper alignment */
    624     0  stevel 	*(SELFP(tp)) = tp;
    625     0  stevel 	SETBIT1(SIZE(tmp));
    626     0  stevel 	ASSERT(ISBIT0(SIZE(tmp)));
    627     0  stevel 	protect(tmp);
    628     0  stevel 	protect(tp);
    629     0  stevel }
    630     0  stevel 
    631     0  stevel /*
    632     0  stevel  * Get more core. Gaps in memory are noted as busy blocks.
    633     0  stevel  */
    634     0  stevel static TREE *
    635     0  stevel morecore(size_t size)
    636     0  stevel {
    637     0  stevel 	TREE	*tp;
    638     0  stevel 	size_t	n, offset, requestsize;
    639     0  stevel 	char	*addr;
    640     0  stevel 
    641     0  stevel 	/* compute new amount of memory to get */
    642     0  stevel 	tp = Bottom;
    643     0  stevel 	n = size + 2 * WORDSIZE;
    644     0  stevel 	addr = GETCORE(0);
    645     0  stevel 
    646     0  stevel 	if (addr == ERRCORE)
    647     0  stevel 		/* errno set by GETCORE sbrk */
    648     0  stevel 		return (NULL);
    649     0  stevel 
    650     0  stevel 	/* need to pad size out so that addr is aligned */
    651     0  stevel 	if ((((size_t)addr) % ALIGN) != 0)
    652     0  stevel 		offset = ALIGN - (size_t)addr % ALIGN;
    653     0  stevel 	else
    654     0  stevel 		offset = 0;
    655     0  stevel 
    656     0  stevel 	if (tp)
    657     0  stevel 		unprotect(tp);
    658     0  stevel 
    659     0  stevel 	/* if not segmented memory, what we need may be smaller */
    660     0  stevel 	if (addr == Baddr) {
    661     0  stevel 		n -= WORDSIZE;
    662     0  stevel 		if (tp != NULL)
    663     0  stevel 			n -= SIZE(tp);
    664     0  stevel 	}
    665     0  stevel 
    666     0  stevel 	/* get a multiple of CORESIZE */
    667     0  stevel 	n = ((n - 1) / CORESIZE + 1) * CORESIZE;
    668     0  stevel 	requestsize = n + offset;
    669     0  stevel 
    670     0  stevel 	/* check if nsize request could overflow in GETCORE */
    671     0  stevel 	if (requestsize > MAX_MALLOC - (size_t)addr) {
    672     0  stevel 		if (tp)
    673     0  stevel 			protect(tp);
    674     0  stevel 		errno = ENOMEM;
    675     0  stevel 		return (NULL);
    676     0  stevel 	}
    677     0  stevel 
    678     0  stevel 	if (requestsize > MAX_GETCORE) {
    679     0  stevel 		intptr_t	delta;
    680     0  stevel 		/*
    681     0  stevel 		 * the value required is too big for GETCORE() to deal with
    682     0  stevel 		 * in one go, so use GETCORE() at most 2 times instead.
    683     0  stevel 		 * Argument to GETCORE() must be multiple of ALIGN.
    684     0  stevel 		 * If not, GETCORE(-MAX_GETCORE) will not return brk point
    685     0  stevel 		 * to previous value, but will be ALIGN more.
    686     0  stevel 		 * This would leave a small hole.
    687     0  stevel 		 */
    688     0  stevel 		delta = MAX_GETCORE;
    689     0  stevel 		while (delta > 0) {
    690     0  stevel 			if (GETCORE(delta) == ERRCORE) {
    691     0  stevel 				if (tp)
    692     0  stevel 					protect(tp);
    693     0  stevel 				if (addr != GETCORE(0))
    694     0  stevel 					(void) GETCORE(-MAX_GETCORE);
    695     0  stevel 				return (NULL);
    696     0  stevel 			}
    697     0  stevel 			requestsize -= MAX_GETCORE;
    698     0  stevel 			delta = requestsize;
    699     0  stevel 		}
    700     0  stevel 	} else if (GETCORE(requestsize) == ERRCORE) {
    701     0  stevel 		if (tp)
    702     0  stevel 			protect(tp);
    703     0  stevel 		return (NULL);
    704     0  stevel 	}
    705     0  stevel 
    706     0  stevel 	/* contiguous memory */
    707     0  stevel 	if (addr == Baddr) {
    708     0  stevel 		ASSERT(offset == 0);
    709     0  stevel 		if (tp) {
    710     0  stevel 			addr = ((char *)tp);
    711     0  stevel 			n += SIZE(tp) + 2 * WORDSIZE;
    712     0  stevel 		} else {
    713     0  stevel 			addr = Baddr - WORDSIZE;
    714     0  stevel 			n += WORDSIZE;
    715     0  stevel 		}
    716     0  stevel 	} else {
    717     0  stevel 		addr += offset;
    718     0  stevel 	}
    719     0  stevel 
    720     0  stevel 	/* new bottom address */
    721     0  stevel 	Baddr = addr + n;
    722     0  stevel 
    723     0  stevel 	/* new bottom block */
    724     0  stevel 	/* LINTED improper alignment */
    725     0  stevel 	tp = ((TREE *)addr);
    726     0  stevel 	SIZE(tp) = n - 2 * WORDSIZE;
    727     0  stevel 	ASSERT((SIZE(tp) % ALIGN) == 0);
    728     0  stevel 
    729     0  stevel 	/* reserved the last word to head any noncontiguous memory */
    730     0  stevel 	/* LINTED improper alignment */
    731     0  stevel 	SETBIT0(SIZE(NEXT(tp)));
    732     0  stevel 
    733     0  stevel 	/* non-contiguous memory, free old bottom block */
    734     0  stevel 	if (Bottom && Bottom != tp) {
    735     0  stevel 		SETBIT0(SIZE(Bottom));
    736     0  stevel 		realfree(DATA(Bottom));
    737     0  stevel 	}
    738     0  stevel 
    739     0  stevel 	return (tp);
    740     0  stevel }
    741     0  stevel 
    742     0  stevel /*
    743     0  stevel  * Utility function to avoid protecting a tree node twice.
    744     0  stevel  * Return true if tp is in the NULL-terminated array of tree nodes.
    745     0  stevel  */
    746     0  stevel static int
    747     0  stevel in_list(TREE *tp, TREE **npp)
    748     0  stevel {
    749     0  stevel 	TREE *sp;
    750     0  stevel 
    751     0  stevel 	while ((sp = *npp++) != NULL)
    752     0  stevel 		if (tp == sp)
    753     0  stevel 			return (1);
    754     0  stevel 	return (0);
    755     0  stevel }
    756     0  stevel 
    757     0  stevel /*
    758     0  stevel  * Tree rotation functions (BU: bottom-up, TD: top-down).
    759     0  stevel  * All functions are entered with the arguments unprotected.
    760     0  stevel  * They must return in the same condition, with all other elements
    761     0  stevel  * that have been unprotected during the operation re-protected.
    762     0  stevel  */
    763     0  stevel static void
    764     0  stevel LEFT1(TREE *x, TREE *y)
    765     0  stevel {
    766     0  stevel 	TREE *node[3];
    767     0  stevel 	TREE **npp = node;
    768     0  stevel 	TREE *tp;
    769     0  stevel 
    770     0  stevel 	if ((RIGHT(x) = LEFT(y)) != NULL) {
    771     0  stevel 		unprotect(*npp++ = RIGHT(x));
    772     0  stevel 		PARENT(RIGHT(x)) = x;
    773     0  stevel 	}
    774     0  stevel 	if ((PARENT(y) = PARENT(x)) != NULL) {
    775     0  stevel 		unprotect(*npp++ = PARENT(x));
    776     0  stevel 		if (LEFT(PARENT(x)) == x)
    777     0  stevel 			LEFT(PARENT(y)) = y;
    778     0  stevel 		else
    779     0  stevel 			RIGHT(PARENT(y)) = y;
    780     0  stevel 	}
    781     0  stevel 	LEFT(y) = x;
    782     0  stevel 	PARENT(x) = y;
    783     0  stevel 
    784     0  stevel 	*npp = NULL;
    785     0  stevel 	npp = node;
    786     0  stevel 	while ((tp = *npp++) != NULL)
    787     0  stevel 		if (tp != x && tp != y && !in_list(tp, npp))
    788     0  stevel 			protect(tp);
    789     0  stevel }
    790     0  stevel 
    791     0  stevel static void
    792     0  stevel RIGHT1(TREE *x, TREE *y)
    793     0  stevel {
    794     0  stevel 	TREE *node[3];
    795     0  stevel 	TREE **npp = node;
    796     0  stevel 	TREE *tp;
    797     0  stevel 
    798     0  stevel 	if ((LEFT(x) = RIGHT(y)) != NULL) {
    799     0  stevel 		unprotect(*npp++ = LEFT(x));
    800     0  stevel 		PARENT(LEFT(x)) = x;
    801     0  stevel 	}
    802     0  stevel 	if ((PARENT(y) = PARENT(x)) != NULL) {
    803     0  stevel 		unprotect(*npp++ = PARENT(x));
    804     0  stevel 		if (LEFT(PARENT(x)) == x)
    805     0  stevel 			LEFT(PARENT(y)) = y;
    806     0  stevel 		else
    807     0  stevel 			RIGHT(PARENT(y)) = y;
    808     0  stevel 	}
    809     0  stevel 	RIGHT(y) = x;
    810     0  stevel 	PARENT(x) = y;
    811     0  stevel 
    812     0  stevel 	*npp = NULL;
    813     0  stevel 	npp = node;
    814     0  stevel 	while ((tp = *npp++) != NULL)
    815     0  stevel 		if (tp != x && tp != y && !in_list(tp, npp))
    816     0  stevel 			protect(tp);
    817     0  stevel }
    818     0  stevel 
    819     0  stevel static void
    820     0  stevel BULEFT2(TREE *x, TREE *y, TREE *z)
    821     0  stevel {
    822     0  stevel 	TREE *node[4];
    823     0  stevel 	TREE **npp = node;
    824     0  stevel 	TREE *tp;
    825     0  stevel 
    826     0  stevel 	if ((RIGHT(x) = LEFT(y)) != NULL) {
    827     0  stevel 		unprotect(*npp++ = RIGHT(x));
    828     0  stevel 		PARENT(RIGHT(x)) = x;
    829     0  stevel 	}
    830     0  stevel 	if ((RIGHT(y) = LEFT(z)) != NULL) {
    831     0  stevel 		unprotect(*npp++ = RIGHT(y));
    832     0  stevel 		PARENT(RIGHT(y)) = y;
    833     0  stevel 	}
    834     0  stevel 	if ((PARENT(z) = PARENT(x)) != NULL) {
    835     0  stevel 		unprotect(*npp++ = PARENT(x));
    836     0  stevel 		if (LEFT(PARENT(x)) == x)
    837     0  stevel 			LEFT(PARENT(z)) = z;
    838     0  stevel 		else
    839     0  stevel 			RIGHT(PARENT(z)) = z;
    840     0  stevel 	}
    841     0  stevel 	LEFT(z) = y;
    842     0  stevel 	PARENT(y) = z;
    843     0  stevel 	LEFT(y) = x;
    844     0  stevel 	PARENT(x) = y;
    845     0  stevel 
    846     0  stevel 	*npp = NULL;
    847     0  stevel 	npp = node;
    848     0  stevel 	while ((tp = *npp++) != NULL)
    849     0  stevel 		if (tp != x && tp != y && tp != z && !in_list(tp, npp))
    850     0  stevel 			protect(tp);
    851     0  stevel }
    852     0  stevel 
    853     0  stevel static void
    854     0  stevel BURIGHT2(TREE *x, TREE *y, TREE *z)
    855     0  stevel {
    856     0  stevel 	TREE *node[4];
    857     0  stevel 	TREE **npp = node;
    858     0  stevel 	TREE *tp;
    859     0  stevel 
    860     0  stevel 	if ((LEFT(x) = RIGHT(y)) != NULL) {
    861     0  stevel 		unprotect(*npp++ = LEFT(x));
    862     0  stevel 		PARENT(LEFT(x)) = x;
    863     0  stevel 	}
    864     0  stevel 	if ((LEFT(y) = RIGHT(z)) != NULL) {
    865     0  stevel 		unprotect(*npp++ = LEFT(y));
    866     0  stevel 		PARENT(LEFT(y)) = y;
    867     0  stevel 	}
    868     0  stevel 	if ((PARENT(z) = PARENT(x)) != NULL) {
    869     0  stevel 		unprotect(*npp++ = PARENT(x));
    870     0  stevel 		if (LEFT(PARENT(x)) == x)
    871     0  stevel 			LEFT(PARENT(z)) = z;
    872     0  stevel 		else
    873     0  stevel 			RIGHT(PARENT(z)) = z;
    874     0  stevel 	}
    875     0  stevel 	RIGHT(z) = y;
    876     0  stevel 	PARENT(y) = z;
    877     0  stevel 	RIGHT(y) = x;
    878     0  stevel 	PARENT(x) = y;
    879     0  stevel 
    880     0  stevel 	*npp = NULL;
    881     0  stevel 	npp = node;
    882     0  stevel 	while ((tp = *npp++) != NULL)
    883     0  stevel 		if (tp != x && tp != y && tp != z && !in_list(tp, npp))
    884     0  stevel 			protect(tp);
    885     0  stevel }
    886     0  stevel 
    887     0  stevel static void
    888     0  stevel TDLEFT2(TREE *x, TREE *y, TREE *z)
    889     0  stevel {
    890     0  stevel 	TREE *node[3];
    891     0  stevel 	TREE **npp = node;
    892     0  stevel 	TREE *tp;
    893     0  stevel 
    894     0  stevel 	if ((RIGHT(y) = LEFT(z)) != NULL) {
    895     0  stevel 		unprotect(*npp++ = RIGHT(y));
    896     0  stevel 		PARENT(RIGHT(y)) = y;
    897     0  stevel 	}
    898     0  stevel 	if ((PARENT(z) = PARENT(x)) != NULL) {
    899     0  stevel 		unprotect(*npp++ = PARENT(x));
    900     0  stevel 		if (LEFT(PARENT(x)) == x)
    901     0  stevel 			LEFT(PARENT(z)) = z;
    902     0  stevel 		else
    903     0  stevel 			RIGHT(PARENT(z)) = z;
    904     0  stevel 	}
    905     0  stevel 	PARENT(x) = z;
    906     0  stevel 	LEFT(z) = x;
    907     0  stevel 
    908     0  stevel 	*npp = NULL;
    909     0  stevel 	npp = node;
    910     0  stevel 	while ((tp = *npp++) != NULL)
    911     0  stevel 		if (tp != x && tp != y && tp != z && !in_list(tp, npp))
    912     0  stevel 			protect(tp);
    913     0  stevel }
    914     0  stevel 
    915     0  stevel #if 0	/* Not used, for now */
    916     0  stevel static void
    917     0  stevel TDRIGHT2(TREE *x, TREE *y, TREE *z)
    918     0  stevel {
    919     0  stevel 	TREE *node[3];
    920     0  stevel 	TREE **npp = node;
    921     0  stevel 	TREE *tp;
    922     0  stevel 
    923     0  stevel 	if ((LEFT(y) = RIGHT(z)) != NULL) {
    924     0  stevel 		unprotect(*npp++ = LEFT(y));
    925     0  stevel 		PARENT(LEFT(y)) = y;
    926     0  stevel 	}
    927     0  stevel 	if ((PARENT(z) = PARENT(x)) != NULL) {
    928     0  stevel 		unprotect(*npp++ = PARENT(x));
    929     0  stevel 		if (LEFT(PARENT(x)) == x)
    930     0  stevel 			LEFT(PARENT(z)) = z;
    931     0  stevel 		else
    932     0  stevel 			RIGHT(PARENT(z)) = z;
    933     0  stevel 	}
    934     0  stevel 	PARENT(x) = z;
    935     0  stevel 	RIGHT(z) = x;
    936     0  stevel 
    937     0  stevel 	*npp = NULL;
    938     0  stevel 	npp = node;
    939     0  stevel 	while ((tp = *npp++) != NULL)
    940     0  stevel 		if (tp != x && tp != y && tp != z && !in_list(tp, npp))
    941     0  stevel 			protect(tp);
    942     0  stevel }
    943     0  stevel #endif
    944     0  stevel 
    945     0  stevel /*
    946     0  stevel  *	Delete a tree element
    947     0  stevel  */
    948     0  stevel static void
    949     0  stevel t_delete(TREE *op)
    950     0  stevel {
    951     0  stevel 	TREE *tp, *sp, *gp;
    952     0  stevel 
    953     0  stevel 	/* if this is a non-tree node */
    954     0  stevel 	if (ISNOTREE(op)) {
    955     0  stevel 		tp = LINKBAK(op);
    956     0  stevel 		unprotect(tp);
    957     0  stevel 		if ((sp = LINKFOR(op)) != NULL) {
    958     0  stevel 			unprotect(sp);
    959     0  stevel 			LINKBAK(sp) = tp;
    960     0  stevel 			protect(sp);
    961     0  stevel 		}
    962     0  stevel 		LINKFOR(tp) = sp;
    963     0  stevel 		protect(tp);
    964     0  stevel 		return;
    965     0  stevel 	}
    966     0  stevel 
    967     0  stevel 	/* make op the root of the tree */
    968     0  stevel 	if (PARENT(op))
    969     0  stevel 		t_splay(op);
    970     0  stevel 
    971     0  stevel 	/* if this is the start of a list */
    972     0  stevel 	if ((tp = LINKFOR(op)) != NULL) {
    973     0  stevel 		unprotect(tp);
    974     0  stevel 		PARENT(tp) = NULL;
    975     0  stevel 		if ((sp = LEFT(op)) != NULL) {
    976     0  stevel 			unprotect(sp);
    977     0  stevel 			PARENT(sp) = tp;
    978     0  stevel 			protect(sp);
    979     0  stevel 		}
    980     0  stevel 		LEFT(tp) = sp;
    981     0  stevel 
    982     0  stevel 		if ((sp = RIGHT(op)) != NULL) {
    983     0  stevel 			unprotect(sp);
    984     0  stevel 			PARENT(sp) = tp;
    985     0  stevel 			protect(sp);
    986     0  stevel 		}
    987     0  stevel 		RIGHT(tp) = sp;
    988     0  stevel 
    989     0  stevel 		Root = tp;
    990     0  stevel 		protect(tp);
    991     0  stevel 		return;
    992     0  stevel 	}
    993     0  stevel 
    994     0  stevel 	/* if op has a non-null left subtree */
    995     0  stevel 	if ((tp = LEFT(op)) != NULL) {
    996     0  stevel 		unprotect(tp);
    997     0  stevel 		PARENT(tp) = NULL;
    998     0  stevel 		if (RIGHT(op)) {
    999     0  stevel 			/* make the right-end of the left subtree its root */
   1000     0  stevel 			while ((sp = RIGHT(tp)) != NULL) {
   1001     0  stevel 				unprotect(sp);
   1002     0  stevel 				if ((gp = RIGHT(sp)) != NULL) {
   1003     0  stevel 					unprotect(gp);
   1004     0  stevel 					TDLEFT2(tp, sp, gp);
   1005     0  stevel 					protect(sp);
   1006     0  stevel 					protect(tp);
   1007     0  stevel 					tp = gp;
   1008     0  stevel 				} else {
   1009     0  stevel 					LEFT1(tp, sp);
   1010     0  stevel 					protect(tp);
   1011     0  stevel 					tp = sp;
   1012     0  stevel 				}
   1013     0  stevel 			}
   1014     0  stevel 
   1015     0  stevel 			/* hook the right subtree of op to the above elt */
   1016     0  stevel 			RIGHT(tp) = sp = RIGHT(op);
   1017     0  stevel 			unprotect(sp);
   1018     0  stevel 			PARENT(sp) = tp;
   1019     0  stevel 			protect(sp);
   1020     0  stevel 		}
   1021     0  stevel 		protect(tp);
   1022     0  stevel 	} else if ((tp = RIGHT(op)) != NULL) {	/* no left subtree */
   1023     0  stevel 		unprotect(tp);
   1024     0  stevel 		PARENT(tp) = NULL;
   1025     0  stevel 		protect(tp);
   1026     0  stevel 	}
   1027     0  stevel 
   1028     0  stevel 	Root = tp;
   1029     0  stevel }
   1030     0  stevel 
   1031     0  stevel /*
   1032     0  stevel  *	Bottom up splaying (simple version).
   1033     0  stevel  *	The basic idea is to roughly cut in half the
   1034     0  stevel  *	path from Root to tp and make tp the new root.
   1035     0  stevel  */
   1036     0  stevel static void
   1037     0  stevel t_splay(TREE *tp)
   1038     0  stevel {
   1039     0  stevel 	TREE *pp, *gp;
   1040     0  stevel 
   1041     0  stevel 	/* iterate until tp is the root */
   1042     0  stevel 	while ((pp = PARENT(tp)) != NULL) {
   1043     0  stevel 		unprotect(pp);
   1044     0  stevel 		/* grandparent of tp */
   1045     0  stevel 		gp = PARENT(pp);
   1046     0  stevel 		if (gp)
   1047     0  stevel 			unprotect(gp);
   1048     0  stevel 
   1049     0  stevel 		/* x is a left child */
   1050     0  stevel 		if (LEFT(pp) == tp) {
   1051     0  stevel 			if (gp && LEFT(gp) == pp) {
   1052     0  stevel 				BURIGHT2(gp, pp, tp);
   1053     0  stevel 				protect(gp);
   1054     0  stevel 			} else {
   1055     0  stevel 				if (gp)
   1056     0  stevel 					protect(gp);
   1057     0  stevel 				RIGHT1(pp, tp);
   1058     0  stevel 			}
   1059     0  stevel 		} else {
   1060     0  stevel 			ASSERT(RIGHT(pp) == tp);
   1061     0  stevel 			if (gp && RIGHT(gp) == pp) {
   1062     0  stevel 				BULEFT2(gp, pp, tp);
   1063     0  stevel 				protect(gp);
   1064     0  stevel 			} else {
   1065     0  stevel 				if (gp)
   1066     0  stevel 					protect(gp);
   1067     0  stevel 				LEFT1(pp, tp);
   1068     0  stevel 			}
   1069     0  stevel 		}
   1070     0  stevel 		protect(pp);
   1071     0  stevel 		unprotect(tp);	/* just in case */
   1072     0  stevel 	}
   1073     0  stevel }
   1074     0  stevel 
   1075     0  stevel void
   1076     0  stevel free(void *old)
   1077     0  stevel {
   1078  3866     raf 	(void) mutex_lock(&__watch_malloc_lock);
   1079     0  stevel 	free_unlocked(old);
   1080  3866     raf 	(void) mutex_unlock(&__watch_malloc_lock);
   1081     0  stevel }
   1082     0  stevel 
   1083     0  stevel 
   1084     0  stevel static void
   1085     0  stevel free_unlocked(void *old)
   1086     0  stevel {
   1087     0  stevel 	if (old != NULL)
   1088     0  stevel 		realfree(old);
   1089     0  stevel }
   1090     0  stevel 
   1091     0  stevel 
   1092     0  stevel /*
   1093     0  stevel  * memalign(align,nbytes)
   1094     0  stevel  *
   1095     0  stevel  * Description:
   1096     0  stevel  *	Returns a block of specified size on a specified alignment boundary.
   1097     0  stevel  *
   1098     0  stevel  * Algorithm:
   1099     0  stevel  *	Malloc enough to ensure that a block can be aligned correctly.
   1100     0  stevel  *	Find the alignment point and return the fragments
   1101     0  stevel  *	before and after the block.
   1102     0  stevel  *
   1103     0  stevel  * Errors:
   1104     0  stevel  *	Returns NULL and sets errno as follows:
   1105     0  stevel  *	[EINVAL]
   1106     0  stevel  *		if nbytes = 0,
   1107     0  stevel  *		or if alignment is misaligned,
   1108     0  stevel  *		or if the heap has been detectably corrupted.
   1109     0  stevel  *	[ENOMEM]
   1110     0  stevel  *		if the requested memory could not be allocated.
   1111     0  stevel  */
   1112     0  stevel 
   1113     0  stevel #define	misaligned(p)		((unsigned)(p) & 3)
   1114     0  stevel 		/* 4-byte "word" alignment is considered ok in LP64 */
   1115     0  stevel #define	nextblk(p, size)	((TREE *)((char *)(p) + (size)))
   1116     0  stevel 
   1117     0  stevel void *
   1118  2658     raf memalign(size_t align, size_t nbytes)
   1119     0  stevel {
   1120     0  stevel 	size_t	reqsize;	/* Num of bytes to get from malloc() */
   1121     0  stevel 	TREE	*p;		/* Ptr returned from malloc() */
   1122     0  stevel 	TREE	*blk;		/* For addressing fragment blocks */
   1123     0  stevel 	size_t	blksize;	/* Current (shrinking) block size */
   1124     0  stevel 	TREE	*alignedp;	/* Ptr to properly aligned boundary */
   1125     0  stevel 	TREE	*aligned_blk;	/* The block to be returned */
   1126     0  stevel 	size_t	frag_size;	/* size of fragments fore and aft */
   1127     0  stevel 	size_t	x;
   1128     0  stevel 
   1129     0  stevel 	/*
   1130     0  stevel 	 * check for valid size and alignment parameters
   1131     0  stevel 	 * MAX_ALIGN check prevents overflow in later calculation.
   1132     0  stevel 	 */
   1133     0  stevel 	if (nbytes == 0 || misaligned(align) || align == 0 ||
   1134     0  stevel 	    align > MAX_ALIGN) {
   1135     0  stevel 		errno = EINVAL;
   1136     0  stevel 		return (NULL);
   1137     0  stevel 	}
   1138     0  stevel 
   1139     0  stevel 	/*
   1140     0  stevel 	 * Malloc enough memory to guarantee that the result can be
   1141     0  stevel 	 * aligned correctly. The worst case is when malloc returns
   1142     0  stevel 	 * a block so close to the next alignment boundary that a
   1143     0  stevel 	 * fragment of minimum size cannot be created.  In order to
   1144     0  stevel 	 * make sure we can handle this, we need to force the
   1145     0  stevel 	 * alignment to be at least as large as the minimum frag size
   1146     0  stevel 	 * (MINSIZE + WORDSIZE).
   1147     0  stevel 	 */
   1148     0  stevel 
   1149     0  stevel 	/* check for size that could overflow ROUND calculation */
   1150     0  stevel 	if (nbytes > MAX_MALLOC) {
   1151     0  stevel 		errno = ENOMEM;
   1152     0  stevel 		return (NULL);
   1153     0  stevel 	}
   1154     0  stevel 	ROUND(nbytes);
   1155     0  stevel 	if (nbytes < MINSIZE)
   1156     0  stevel 		nbytes = MINSIZE;
   1157     0  stevel 	ROUND(align);
   1158     0  stevel 	while (align < MINSIZE + WORDSIZE)
   1159     0  stevel 		align <<= 1;
   1160     0  stevel 	reqsize = nbytes + align + (MINSIZE + WORDSIZE);
   1161     0  stevel 	/* check for overflow */
   1162     0  stevel 	if (reqsize < nbytes) {
   1163     0  stevel 		errno = ENOMEM;
   1164     0  stevel 		return (NULL);
   1165     0  stevel 	}
   1166     0  stevel 	p = (TREE *) malloc(reqsize);
   1167     0  stevel 	if (p == (TREE *) NULL) {
   1168     0  stevel 		/* malloc sets errno */
   1169     0  stevel 		return (NULL);
   1170     0  stevel 	}
   1171  3866     raf 	(void) mutex_lock(&__watch_malloc_lock);
   1172     0  stevel 
   1173     0  stevel 	/*
   1174     0  stevel 	 * get size of the entire block (overhead and all)
   1175     0  stevel 	 */
   1176     0  stevel 	/* LINTED improper alignment */
   1177     0  stevel 	blk = BLOCK(p);			/* back up to get length word */
   1178     0  stevel 	unprotect(blk);
   1179     0  stevel 	blksize = SIZE(blk);
   1180     0  stevel 	CLRBITS01(blksize);
   1181     0  stevel 
   1182     0  stevel 	/*
   1183     0  stevel 	 * locate the proper alignment boundary within the block.
   1184     0  stevel 	 */
   1185     0  stevel 	x = (size_t)p;
   1186     0  stevel 	if (x % align != 0)
   1187     0  stevel 		x += align - (x % align);
   1188     0  stevel 	alignedp = (TREE *)x;
   1189     0  stevel 	/* LINTED improper alignment */
   1190     0  stevel 	aligned_blk = BLOCK(alignedp);
   1191     0  stevel 
   1192     0  stevel 	/*
   1193     0  stevel 	 * Check out the space to the left of the alignment
   1194     0  stevel 	 * boundary, and split off a fragment if necessary.
   1195     0  stevel 	 */
   1196     0  stevel 	frag_size = (size_t)aligned_blk - (size_t)blk;
   1197     0  stevel 	if (frag_size != 0) {
   1198     0  stevel 		/*
   1199     0  stevel 		 * Create a fragment to the left of the aligned block.
   1200     0  stevel 		 */
   1201     0  stevel 		if (frag_size < MINSIZE + WORDSIZE) {
   1202     0  stevel 			/*
   1203     0  stevel 			 * Not enough space. So make the split
   1204     0  stevel 			 * at the other end of the alignment unit.
   1205     0  stevel 			 * We know this yields enough space, because
   1206     0  stevel 			 * we forced align >= MINSIZE + WORDSIZE above.
   1207     0  stevel 			 */
   1208     0  stevel 			frag_size += align;
   1209     0  stevel 			/* LINTED improper alignment */
   1210     0  stevel 			aligned_blk = nextblk(aligned_blk, align);
   1211     0  stevel 		}
   1212     0  stevel 		blksize -= frag_size;
   1213     0  stevel 		SIZE(aligned_blk) = blksize | BIT0;
   1214     0  stevel 		frag_size -= WORDSIZE;
   1215     0  stevel 		SIZE(blk) = frag_size | BIT0 | ISBIT1(SIZE(blk));
   1216     0  stevel 		free_unlocked(DATA(blk));
   1217     0  stevel 		/*
   1218     0  stevel 		 * free_unlocked(DATA(blk)) has the side-effect of calling
   1219     0  stevel 		 * protect() on the block following blk, that is, aligned_blk.
   1220     0  stevel 		 * We recover from this by unprotect()ing it here.
   1221     0  stevel 		 */
   1222     0  stevel 		unprotect(aligned_blk);
   1223     0  stevel 	}
   1224     0  stevel 
   1225     0  stevel 	/*
   1226     0  stevel 	 * Is there a (sufficiently large) fragment to the
   1227     0  stevel 	 * right of the aligned block?
   1228     0  stevel 	 */
   1229     0  stevel 	frag_size = blksize - nbytes;
   1230     0  stevel 	if (frag_size >= MINSIZE + WORDSIZE) {
   1231     0  stevel 		/*
   1232     0  stevel 		 * split and free a fragment on the right
   1233     0  stevel 		 */
   1234     0  stevel 		blksize = SIZE(aligned_blk);
   1235     0  stevel 		SIZE(aligned_blk) = nbytes;
   1236     0  stevel 		/* LINTED improper alignment */
   1237     0  stevel 		blk = NEXT(aligned_blk);
   1238     0  stevel 		SETOLD01(SIZE(aligned_blk), blksize);
   1239     0  stevel 		frag_size -= WORDSIZE;
   1240     0  stevel 		SIZE(blk) = frag_size | BIT0;
   1241     0  stevel 		free_unlocked(DATA(blk));
   1242     0  stevel 	}
   1243     0  stevel 	copy_pattern(LIVEPAT, aligned_blk);
   1244     0  stevel 	protect(aligned_blk);
   1245  3866     raf 	(void) mutex_unlock(&__watch_malloc_lock);
   1246     0  stevel 	return (DATA(aligned_blk));
   1247     0  stevel }
   1248     0  stevel 
   1249     0  stevel void *
   1250  2658     raf valloc(size_t size)
   1251     0  stevel {
   1252     0  stevel 	static unsigned pagesize;
   1253     0  stevel 	if (!pagesize)
   1254     0  stevel 		pagesize = _sysconf(_SC_PAGESIZE);
   1255     0  stevel 	return (memalign(pagesize, size));
   1256     0  stevel }
   1257     0  stevel 
   1258     0  stevel void *
   1259     0  stevel calloc(size_t num, size_t size)
   1260     0  stevel {
   1261     0  stevel 	void *mp;
   1262     0  stevel 	size_t total;
   1263     0  stevel 
   1264     0  stevel 	total = num * size;
   1265     0  stevel 
   1266     0  stevel 	/* check for overflow */
   1267     0  stevel 	if (num != 0 && total / num != size) {
   1268     0  stevel 		errno = ENOMEM;
   1269     0  stevel 		return (NULL);
   1270     0  stevel 	}
   1271     0  stevel 	if ((mp = malloc(total)) != NULL)
   1272     0  stevel 		(void) memset(mp, 0, total);
   1273     0  stevel 	return (mp);
   1274     0  stevel }
   1275     0  stevel 
   1276     0  stevel /* ARGSUSED1 */
   1277     0  stevel void
   1278  2658     raf cfree(void *p, size_t num, size_t size)
   1279     0  stevel {
   1280     0  stevel 	free(p);
   1281     0  stevel }
   1282     0  stevel 
   1283     0  stevel typedef struct {
   1284     0  stevel 	long cmd;
   1285     0  stevel 	prwatch_t prwatch;
   1286     0  stevel } ctl_t;
   1287     0  stevel 
   1288     0  stevel static pid_t my_pid = 0;	/* to check for whether we fork()d */
   1289     0  stevel static int dont_watch = 0;
   1290     0  stevel static int do_stop = 0;
   1291     0  stevel static int ctlfd = -1;
   1292     0  stevel struct stat ctlstatb;
   1293     0  stevel static int wflags = WA_WRITE;
   1294     0  stevel 
   1295     0  stevel static void
   1296     0  stevel init_watch()
   1297     0  stevel {
   1298     0  stevel 	char str[80];
   1299     0  stevel 	char *s;
   1300     0  stevel 
   1301     0  stevel 	my_pid = getpid();
   1302     0  stevel 
   1303     0  stevel 	dont_watch = 1;
   1304     0  stevel 
   1305     0  stevel 	if ((s = getenv("MALLOC_DEBUG")) == NULL)
   1306     0  stevel 		return;
   1307     0  stevel 
   1308     0  stevel 	s = strncpy(str, s, sizeof (str));
   1309     0  stevel 	while (s != NULL) {
   1310     0  stevel 		char *e = strchr(s, ',');
   1311     0  stevel 		if (e)
   1312     0  stevel 			*e++ = '\0';
   1313     0  stevel 		if (strcmp(s, "STOP") == 0)
   1314     0  stevel 			do_stop = 1;
   1315     0  stevel 		else if (strcmp(s, "WATCH") == 0)
   1316     0  stevel 			dont_watch = 0;
   1317     0  stevel 		else if (strcmp(s, "RW") == 0) {
   1318     0  stevel 			dont_watch = 0;
   1319     0  stevel 			wflags = WA_READ|WA_WRITE;
   1320     0  stevel 		}
   1321     0  stevel 		s = e;
   1322     0  stevel 	}
   1323     0  stevel 
   1324     0  stevel 	if (dont_watch)
   1325     0  stevel 		return;
   1326     0  stevel 
   1327     0  stevel 	if ((ctlfd = open("/proc/self/ctl", O_WRONLY)) < 0 ||
   1328     0  stevel 	    fstat(ctlfd, &ctlstatb) != 0) {
   1329     0  stevel 		if (ctlfd >= 0)
   1330     0  stevel 			(void) close(ctlfd);
   1331     0  stevel 		ctlfd = -1;
   1332     0  stevel 		dont_watch = 1;
   1333     0  stevel 		return;
   1334     0  stevel 	}
   1335     0  stevel 	/* close-on-exec */
   1336     0  stevel 	(void) fcntl(ctlfd, F_SETFD, 1);
   1337     0  stevel 
   1338     0  stevel 	if (do_stop) {
   1339     0  stevel 		int pfd;
   1340     0  stevel 		pstatus_t pstatus;
   1341     0  stevel 		struct {
   1342     0  stevel 			long cmd;
   1343     0  stevel 			fltset_t fltset;
   1344     0  stevel 		} ctl;
   1345     0  stevel 
   1346     0  stevel 		/*
   1347     0  stevel 		 * Play together with some /proc controller
   1348     0  stevel 		 * that has set other stop-on-fault flags.
   1349     0  stevel 		 */
   1350     0  stevel 		premptyset(&ctl.fltset);
   1351     0  stevel 		if ((pfd = open("/proc/self/status", O_RDONLY)) >= 0) {
   1352     0  stevel 			if (read(pfd, &pstatus, sizeof (pstatus))
   1353     0  stevel 			    == sizeof (pstatus))
   1354     0  stevel 				ctl.fltset = pstatus.pr_flttrace;
   1355     0  stevel 			(void) close(pfd);
   1356     0  stevel 		}
   1357     0  stevel 		praddset(&ctl.fltset, FLTWATCH);
   1358     0  stevel 		ctl.cmd = PCSFAULT;
   1359     0  stevel 		(void) write(ctlfd, &ctl, sizeof (ctl));
   1360     0  stevel 	}
   1361     0  stevel }
   1362     0  stevel 
   1363     0  stevel static int
   1364     0  stevel nowatch()
   1365     0  stevel {
   1366     0  stevel 	struct stat statb;
   1367     0  stevel 
   1368     0  stevel 	if (dont_watch)
   1369     0  stevel 		return (1);
   1370     0  stevel 	if (ctlfd < 0)	/* first time */
   1371     0  stevel 		init_watch();
   1372     0  stevel 	else if (fstat(ctlfd, &statb) != 0 ||
   1373     0  stevel 	    statb.st_dev != ctlstatb.st_dev ||
   1374     0  stevel 	    statb.st_ino != ctlstatb.st_ino) {
   1375     0  stevel 		/*
   1376     0  stevel 		 * Someone closed our file descriptor.
   1377     0  stevel 		 * Just open another one.
   1378     0  stevel 		 */
   1379     0  stevel 		if ((ctlfd = open("/proc/self/ctl", O_WRONLY)) < 0 ||
   1380     0  stevel 		    fstat(ctlfd, &ctlstatb) != 0) {
   1381     0  stevel 			if (ctlfd >= 0)
   1382     0  stevel 				(void) close(ctlfd);
   1383     0  stevel 			ctlfd = -1;
   1384     0  stevel 			dont_watch = 1;
   1385     0  stevel 			return (1);
   1386     0  stevel 		}
   1387     0  stevel 		/* close-on-exec */
   1388     0  stevel 		(void) fcntl(ctlfd, F_SETFD, 1);
   1389     0  stevel 	}
   1390     0  stevel 	if (my_pid != getpid()) {
   1391     0  stevel 		/*
   1392     0  stevel 		 * We fork()d since the last call to the allocator.
   1393     0  stevel 		 * watchpoints are not inherited across fork().
   1394     0  stevel 		 * XXX: how to recover from this ???
   1395     0  stevel 		 */
   1396     0  stevel 		dont_watch = 1;
   1397     0  stevel 		(void) close(ctlfd);
   1398     0  stevel 		ctlfd = -1;
   1399     0  stevel 	}
   1400     0  stevel 	return (dont_watch);
   1401     0  stevel }
   1402     0  stevel 
   1403     0  stevel static void
   1404     0  stevel protect(TREE *tp)
   1405     0  stevel {
   1406     0  stevel 	ctl_t ctl;
   1407     0  stevel 	size_t size, sz;
   1408     0  stevel 
   1409     0  stevel 	if (nowatch())
   1410     0  stevel 		return;
   1411     0  stevel 	if (tp == NULL || DATA(tp) == Baddr)
   1412     0  stevel 		return;
   1413     0  stevel 
   1414     0  stevel 	sz = size = SIZE(tp);
   1415     0  stevel 	CLRBITS01(size);
   1416     0  stevel 	if (size == 0)
   1417     0  stevel 		return;
   1418     0  stevel 	if (ISBIT0(sz))		/* block is busy, protect only the head */
   1419     0  stevel 		size = 0;
   1420     0  stevel 	ctl.cmd = PCWATCH;
   1421     0  stevel 	ctl.prwatch.pr_vaddr = (uintptr_t)tp;
   1422     0  stevel 	ctl.prwatch.pr_size = size + WORDSIZE;
   1423     0  stevel 	ctl.prwatch.pr_wflags = wflags;
   1424     0  stevel 	(void) write(ctlfd, &ctl, sizeof (ctl));
   1425     0  stevel }
   1426     0  stevel 
   1427     0  stevel static void
   1428     0  stevel unprotect(TREE *tp)
   1429     0  stevel {
   1430     0  stevel 	ctl_t ctl;
   1431     0  stevel 
   1432     0  stevel 	if (nowatch())
   1433     0  stevel 		return;
   1434     0  stevel 	if (tp == NULL || DATA(tp) == Baddr)
   1435     0  stevel 		return;
   1436     0  stevel 
   1437     0  stevel 	ctl.cmd = PCWATCH;
   1438     0  stevel 	ctl.prwatch.pr_vaddr = (uintptr_t)tp;
   1439     0  stevel 	ctl.prwatch.pr_size = WORDSIZE;		/* size is arbitrary */
   1440     0  stevel 	ctl.prwatch.pr_wflags = 0;		/* clear the watched area */
   1441     0  stevel 	(void) write(ctlfd, &ctl, sizeof (ctl));
   1442     0  stevel }
   1443  3866     raf 
   1444  3866     raf static void
   1445  3866     raf malloc_prepare()
   1446  3866     raf {
   1447  3866     raf 	(void) mutex_lock(&__watch_malloc_lock);
   1448  3866     raf }
   1449  3866     raf 
   1450  3866     raf static void
   1451  3866     raf malloc_release()
   1452  3866     raf {
   1453  3866     raf 	(void) mutex_unlock(&__watch_malloc_lock);
   1454  3866     raf }
   1455  3866     raf 
   1456  3866     raf #pragma init(malloc_init)
   1457  3866     raf static void
   1458  3866     raf malloc_init(void)
   1459  3866     raf {
   1460  3866     raf 	(void) pthread_atfork(malloc_prepare, malloc_release, malloc_release);
   1461  3866     raf }
   1462