xref: /onnv-gate/usr/src/lib/libuutil/common/uu_list.c (revision 7266:bbfd6395568b)
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
57240Srh87107  * Common Development and Distribution License (the "License").
67240Srh87107  * 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  */
210Sstevel@tonic-gate /*
227240Srh87107  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include "libuutil_common.h"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <stdlib.h>
310Sstevel@tonic-gate #include <string.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <sys/time.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #define	ELEM_TO_NODE(lp, e) \
360Sstevel@tonic-gate 	((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #define	NODE_TO_ELEM(lp, n) \
390Sstevel@tonic-gate 	((void *)((uintptr_t)(n) - (lp)->ul_offset))
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * uu_list_index_ts define a location for insertion.  They are simply a
430Sstevel@tonic-gate  * pointer to the object after the insertion point.  We store a mark
440Sstevel@tonic-gate  * in the low-bits of the index, to help prevent mistakes.
450Sstevel@tonic-gate  *
460Sstevel@tonic-gate  * When debugging, the index mark changes on every insert and delete, to
470Sstevel@tonic-gate  * catch stale references.
480Sstevel@tonic-gate  */
490Sstevel@tonic-gate #define	INDEX_MAX		(sizeof (uintptr_t) - 1)
500Sstevel@tonic-gate #define	INDEX_NEXT(m)		(((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #define	INDEX_TO_NODE(i)	((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
530Sstevel@tonic-gate #define	NODE_TO_INDEX(p, n)	(((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
540Sstevel@tonic-gate #define	INDEX_VALID(p, i)	(((i) & INDEX_MAX) == (p)->ul_index)
550Sstevel@tonic-gate #define	INDEX_CHECK(i)		(((i) & INDEX_MAX) != 0)
560Sstevel@tonic-gate 
570Sstevel@tonic-gate #define	POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static uu_list_pool_t	uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
600Sstevel@tonic-gate static pthread_mutex_t	uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
610Sstevel@tonic-gate 
620Sstevel@tonic-gate uu_list_pool_t *
uu_list_pool_create(const char * name,size_t objsize,size_t nodeoffset,uu_compare_fn_t * compare_func,uint32_t flags)630Sstevel@tonic-gate uu_list_pool_create(const char *name, size_t objsize,
640Sstevel@tonic-gate     size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	uu_list_pool_t *pp, *next, *prev;
670Sstevel@tonic-gate 
680Sstevel@tonic-gate 	if (name == NULL ||
690Sstevel@tonic-gate 	    uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
700Sstevel@tonic-gate 	    nodeoffset + sizeof (uu_list_node_t) > objsize) {
710Sstevel@tonic-gate 		uu_set_error(UU_ERROR_INVALID_ARGUMENT);
720Sstevel@tonic-gate 		return (NULL);
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	if (flags & ~UU_LIST_POOL_DEBUG) {
760Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
770Sstevel@tonic-gate 		return (NULL);
780Sstevel@tonic-gate 	}
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	pp = uu_zalloc(sizeof (uu_list_pool_t));
810Sstevel@tonic-gate 	if (pp == NULL) {
820Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
830Sstevel@tonic-gate 		return (NULL);
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	(void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
870Sstevel@tonic-gate 	pp->ulp_nodeoffset = nodeoffset;
880Sstevel@tonic-gate 	pp->ulp_objsize = objsize;
890Sstevel@tonic-gate 	pp->ulp_cmp = compare_func;
900Sstevel@tonic-gate 	if (flags & UU_LIST_POOL_DEBUG)
910Sstevel@tonic-gate 		pp->ulp_debug = 1;
920Sstevel@tonic-gate 	pp->ulp_last_index = 0;
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 	(void) pthread_mutex_init(&pp->ulp_lock, NULL);
950Sstevel@tonic-gate 
96407Sjwadams 	pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
97407Sjwadams 	pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
1000Sstevel@tonic-gate 	pp->ulp_next = next = &uu_null_lpool;
1010Sstevel@tonic-gate 	pp->ulp_prev = prev = next->ulp_prev;
1020Sstevel@tonic-gate 	next->ulp_prev = pp;
1030Sstevel@tonic-gate 	prev->ulp_next = pp;
1040Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate 	return (pp);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate void
uu_list_pool_destroy(uu_list_pool_t * pp)1100Sstevel@tonic-gate uu_list_pool_destroy(uu_list_pool_t *pp)
1110Sstevel@tonic-gate {
1120Sstevel@tonic-gate 	if (pp->ulp_debug) {
113407Sjwadams 		if (pp->ulp_null_list.ul_next_enc !=
114407Sjwadams 		    UU_PTR_ENCODE(&pp->ulp_null_list) ||
115407Sjwadams 		    pp->ulp_null_list.ul_prev_enc !=
116407Sjwadams 		    UU_PTR_ENCODE(&pp->ulp_null_list)) {
1170Sstevel@tonic-gate 			uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
1180Sstevel@tonic-gate 			    "outstanding lists, or is corrupt.\n",
1197240Srh87107 			    (int)sizeof (pp->ulp_name), pp->ulp_name,
1207240Srh87107 			    (void *)pp);
1210Sstevel@tonic-gate 		}
1220Sstevel@tonic-gate 	}
1230Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
1240Sstevel@tonic-gate 	pp->ulp_next->ulp_prev = pp->ulp_prev;
1250Sstevel@tonic-gate 	pp->ulp_prev->ulp_next = pp->ulp_next;
1260Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
1270Sstevel@tonic-gate 	pp->ulp_prev = NULL;
1280Sstevel@tonic-gate 	pp->ulp_next = NULL;
1290Sstevel@tonic-gate 	uu_free(pp);
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate void
uu_list_node_init(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)1330Sstevel@tonic-gate uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	if (pp->ulp_debug) {
1380Sstevel@tonic-gate 		uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
1390Sstevel@tonic-gate 		if (offset + sizeof (*np) > pp->ulp_objsize) {
1400Sstevel@tonic-gate 			uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
1410Sstevel@tonic-gate 			    "offset %ld doesn't fit in object (size %ld)\n",
1427240Srh87107 			    base, (void *)np, (void *)pp, pp->ulp_name,
1437240Srh87107 			    (long)offset, (long)pp->ulp_objsize);
1440Sstevel@tonic-gate 		}
1450Sstevel@tonic-gate 		if (offset != pp->ulp_nodeoffset) {
1460Sstevel@tonic-gate 			uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
1470Sstevel@tonic-gate 			    "offset %ld doesn't match pool's offset (%ld)\n",
1487240Srh87107 			    base, (void *)np, (void *)pp, pp->ulp_name,
1497240Srh87107 			    (long)offset, (long)pp->ulp_objsize);
1500Sstevel@tonic-gate 		}
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate 	np->uln_next = POOL_TO_MARKER(pp);
1530Sstevel@tonic-gate 	np->uln_prev = NULL;
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate void
uu_list_node_fini(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)1570Sstevel@tonic-gate uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	if (pp->ulp_debug) {
1620Sstevel@tonic-gate 		if (np->uln_next == NULL &&
1630Sstevel@tonic-gate 		    np->uln_prev == NULL) {
1640Sstevel@tonic-gate 			uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
1650Sstevel@tonic-gate 			    "node already finied\n",
1667240Srh87107 			    base, (void *)np_arg, (void *)pp, pp->ulp_name);
1670Sstevel@tonic-gate 		}
1680Sstevel@tonic-gate 		if (np->uln_next != POOL_TO_MARKER(pp) ||
1690Sstevel@tonic-gate 		    np->uln_prev != NULL) {
1700Sstevel@tonic-gate 			uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
1710Sstevel@tonic-gate 			    "node corrupt or on list\n",
1727240Srh87107 			    base, (void *)np_arg, (void *)pp, pp->ulp_name);
1730Sstevel@tonic-gate 		}
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate 	np->uln_next = NULL;
1760Sstevel@tonic-gate 	np->uln_prev = NULL;
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate uu_list_t *
uu_list_create(uu_list_pool_t * pp,void * parent,uint32_t flags)1800Sstevel@tonic-gate uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
1810Sstevel@tonic-gate {
1820Sstevel@tonic-gate 	uu_list_t *lp, *next, *prev;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
1850Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
1860Sstevel@tonic-gate 		return (NULL);
1870Sstevel@tonic-gate 	}
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
1900Sstevel@tonic-gate 		if (pp->ulp_debug)
1910Sstevel@tonic-gate 			uu_panic("uu_list_create(%p, ...): requested "
1920Sstevel@tonic-gate 			    "UU_LIST_SORTED, but pool has no comparison func\n",
1937240Srh87107 			    (void *)pp);
1940Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
1950Sstevel@tonic-gate 		return (NULL);
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	lp = uu_zalloc(sizeof (*lp));
1990Sstevel@tonic-gate 	if (lp == NULL) {
2000Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
2010Sstevel@tonic-gate 		return (NULL);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	lp->ul_pool = pp;
205407Sjwadams 	lp->ul_parent_enc = UU_PTR_ENCODE(parent);
2060Sstevel@tonic-gate 	lp->ul_offset = pp->ulp_nodeoffset;
2070Sstevel@tonic-gate 	lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
2080Sstevel@tonic-gate 	lp->ul_sorted = (flags & UU_LIST_SORTED);
2090Sstevel@tonic-gate 	lp->ul_numnodes = 0;
2100Sstevel@tonic-gate 	lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	lp->ul_null_node.uln_next = &lp->ul_null_node;
2130Sstevel@tonic-gate 	lp->ul_null_node.uln_prev = &lp->ul_null_node;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
2160Sstevel@tonic-gate 	lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pp->ulp_lock);
219407Sjwadams 	next = &pp->ulp_null_list;
220407Sjwadams 	prev = UU_PTR_DECODE(next->ul_prev_enc);
221407Sjwadams 	lp->ul_next_enc = UU_PTR_ENCODE(next);
222407Sjwadams 	lp->ul_prev_enc = UU_PTR_ENCODE(prev);
223407Sjwadams 	next->ul_prev_enc = UU_PTR_ENCODE(lp);
224407Sjwadams 	prev->ul_next_enc = UU_PTR_ENCODE(lp);
2250Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pp->ulp_lock);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	return (lp);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate void
uu_list_destroy(uu_list_t * lp)2310Sstevel@tonic-gate uu_list_destroy(uu_list_t *lp)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	uu_list_pool_t *pp = lp->ul_pool;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	if (lp->ul_debug) {
2360Sstevel@tonic-gate 		if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
2370Sstevel@tonic-gate 		    lp->ul_null_node.uln_prev != &lp->ul_null_node) {
2380Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  list not empty\n",
2397240Srh87107 			    (void *)lp);
2400Sstevel@tonic-gate 		}
2410Sstevel@tonic-gate 		if (lp->ul_numnodes != 0) {
2420Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  numnodes is nonzero, "
2437240Srh87107 			    "but list is empty\n", (void *)lp);
2440Sstevel@tonic-gate 		}
2450Sstevel@tonic-gate 		if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
2460Sstevel@tonic-gate 		    lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
2470Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  outstanding walkers\n",
2487240Srh87107 			    (void *)lp);
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pp->ulp_lock);
253407Sjwadams 	UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
254407Sjwadams 	UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
2550Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pp->ulp_lock);
256407Sjwadams 	lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
257407Sjwadams 	lp->ul_next_enc = UU_PTR_ENCODE(NULL);
2580Sstevel@tonic-gate 	lp->ul_pool = NULL;
2590Sstevel@tonic-gate 	uu_free(lp);
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate static void
list_insert(uu_list_t * lp,uu_list_node_impl_t * np,uu_list_node_impl_t * prev,uu_list_node_impl_t * next)2630Sstevel@tonic-gate list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
2640Sstevel@tonic-gate     uu_list_node_impl_t *next)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	if (lp->ul_debug) {
2670Sstevel@tonic-gate 		if (next->uln_prev != prev || prev->uln_next != next)
2680Sstevel@tonic-gate 			uu_panic("insert(%p): internal error: %p and %p not "
2697240Srh87107 			    "neighbors\n", (void *)lp, (void *)next,
2707240Srh87107 			    (void *)prev);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 		if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
2730Sstevel@tonic-gate 		    np->uln_prev != NULL) {
2740Sstevel@tonic-gate 			uu_panic("insert(%p): elem %p node %p corrupt, "
2750Sstevel@tonic-gate 			    "not initialized, or already in a list.\n",
2767240Srh87107 			    (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
2770Sstevel@tonic-gate 		}
2780Sstevel@tonic-gate 		/*
2790Sstevel@tonic-gate 		 * invalidate outstanding uu_list_index_ts.
2800Sstevel@tonic-gate 		 */
2810Sstevel@tonic-gate 		lp->ul_index = INDEX_NEXT(lp->ul_index);
2820Sstevel@tonic-gate 	}
2830Sstevel@tonic-gate 	np->uln_next = next;
2840Sstevel@tonic-gate 	np->uln_prev = prev;
2850Sstevel@tonic-gate 	next->uln_prev = np;
2860Sstevel@tonic-gate 	prev->uln_next = np;
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	lp->ul_numnodes++;
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate void
uu_list_insert(uu_list_t * lp,void * elem,uu_list_index_t idx)2920Sstevel@tonic-gate uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	uu_list_node_impl_t *np;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	np = INDEX_TO_NODE(idx);
2970Sstevel@tonic-gate 	if (np == NULL)
2980Sstevel@tonic-gate 		np = &lp->ul_null_node;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	if (lp->ul_debug) {
3010Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3020Sstevel@tonic-gate 			uu_panic("uu_list_insert(%p, %p, %p): %s\n",
3037240Srh87107 			    (void *)lp, elem, (void *)idx,
3040Sstevel@tonic-gate 			    INDEX_CHECK(idx)? "outdated index" :
3050Sstevel@tonic-gate 			    "invalid index");
3060Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3070Sstevel@tonic-gate 			uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
3087240Srh87107 			    "index\n", (void *)lp, elem, (void *)idx);
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate void *
uu_list_find(uu_list_t * lp,void * elem,void * private,uu_list_index_t * out)3150Sstevel@tonic-gate uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
3160Sstevel@tonic-gate {
3170Sstevel@tonic-gate 	int sorted = lp->ul_sorted;
3180Sstevel@tonic-gate 	uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
3190Sstevel@tonic-gate 	uu_list_node_impl_t *np;
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (func == NULL) {
3220Sstevel@tonic-gate 		if (out != NULL)
3230Sstevel@tonic-gate 			*out = 0;
3240Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
3250Sstevel@tonic-gate 		return (NULL);
3260Sstevel@tonic-gate 	}
3270Sstevel@tonic-gate 	for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
3280Sstevel@tonic-gate 	    np = np->uln_next) {
3290Sstevel@tonic-gate 		void *ep = NODE_TO_ELEM(lp, np);
3300Sstevel@tonic-gate 		int cmp = func(ep, elem, private);
3310Sstevel@tonic-gate 		if (cmp == 0) {
3320Sstevel@tonic-gate 			if (out != NULL)
3330Sstevel@tonic-gate 				*out = NODE_TO_INDEX(lp, np);
3340Sstevel@tonic-gate 			return (ep);
3350Sstevel@tonic-gate 		}
3360Sstevel@tonic-gate 		if (sorted && cmp > 0) {
3370Sstevel@tonic-gate 			if (out != NULL)
3380Sstevel@tonic-gate 				*out = NODE_TO_INDEX(lp, np);
3390Sstevel@tonic-gate 			return (NULL);
3400Sstevel@tonic-gate 		}
3410Sstevel@tonic-gate 	}
3420Sstevel@tonic-gate 	if (out != NULL)
3430Sstevel@tonic-gate 		*out = NODE_TO_INDEX(lp, 0);
3440Sstevel@tonic-gate 	return (NULL);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate void *
uu_list_nearest_next(uu_list_t * lp,uu_list_index_t idx)3480Sstevel@tonic-gate uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
3490Sstevel@tonic-gate {
3500Sstevel@tonic-gate 	uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	if (np == NULL)
3530Sstevel@tonic-gate 		np = &lp->ul_null_node;
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	if (lp->ul_debug) {
3560Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3570Sstevel@tonic-gate 			uu_panic("uu_list_nearest_next(%p, %p): %s\n",
3587240Srh87107 			    (void *)lp, (void *)idx,
3597240Srh87107 			    INDEX_CHECK(idx)? "outdated index" :
3600Sstevel@tonic-gate 			    "invalid index");
3610Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3620Sstevel@tonic-gate 			uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
3637240Srh87107 			    "index\n", (void *)lp, (void *)idx);
3640Sstevel@tonic-gate 	}
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if (np == &lp->ul_null_node)
3670Sstevel@tonic-gate 		return (NULL);
3680Sstevel@tonic-gate 	else
3690Sstevel@tonic-gate 		return (NODE_TO_ELEM(lp, np));
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate void *
uu_list_nearest_prev(uu_list_t * lp,uu_list_index_t idx)3730Sstevel@tonic-gate uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 	uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	if (np == NULL)
3780Sstevel@tonic-gate 		np = &lp->ul_null_node;
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	if (lp->ul_debug) {
3810Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3820Sstevel@tonic-gate 			uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
3837240Srh87107 			    (void *)lp, (void *)idx, INDEX_CHECK(idx)?
3847240Srh87107 			    "outdated index" : "invalid index");
3850Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3860Sstevel@tonic-gate 			uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
3877240Srh87107 			    "index\n", (void *)lp, (void *)idx);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if ((np = np->uln_prev) == &lp->ul_null_node)
3910Sstevel@tonic-gate 		return (NULL);
3920Sstevel@tonic-gate 	else
3930Sstevel@tonic-gate 		return (NODE_TO_ELEM(lp, np));
3940Sstevel@tonic-gate }
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate static void
list_walk_init(uu_list_walk_t * wp,uu_list_t * lp,uint32_t flags)3970Sstevel@tonic-gate list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
3980Sstevel@tonic-gate {
3990Sstevel@tonic-gate 	uu_list_walk_t *next, *prev;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	int robust = (flags & UU_WALK_ROBUST);
4020Sstevel@tonic-gate 	int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	(void) memset(wp, 0, sizeof (*wp));
4050Sstevel@tonic-gate 	wp->ulw_list = lp;
4060Sstevel@tonic-gate 	wp->ulw_robust = robust;
4070Sstevel@tonic-gate 	wp->ulw_dir = direction;
4080Sstevel@tonic-gate 	if (direction > 0)
4090Sstevel@tonic-gate 		wp->ulw_next_result = lp->ul_null_node.uln_next;
4100Sstevel@tonic-gate 	else
4110Sstevel@tonic-gate 		wp->ulw_next_result = lp->ul_null_node.uln_prev;
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	if (lp->ul_debug || robust) {
414*7266Sbustos 		/*
415*7266Sbustos 		 * Add this walker to the list's list of walkers so
416*7266Sbustos 		 * uu_list_remove() can advance us if somebody tries to
417*7266Sbustos 		 * remove ulw_next_result.
418*7266Sbustos 		 */
4190Sstevel@tonic-gate 		wp->ulw_next = next = &lp->ul_null_walk;
4200Sstevel@tonic-gate 		wp->ulw_prev = prev = next->ulw_prev;
4210Sstevel@tonic-gate 		next->ulw_prev = wp;
4220Sstevel@tonic-gate 		prev->ulw_next = wp;
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate static uu_list_node_impl_t *
list_walk_advance(uu_list_walk_t * wp,uu_list_t * lp)4270Sstevel@tonic-gate list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
4280Sstevel@tonic-gate {
4290Sstevel@tonic-gate 	uu_list_node_impl_t *np = wp->ulw_next_result;
4300Sstevel@tonic-gate 	uu_list_node_impl_t *next;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (np == &lp->ul_null_node)
4330Sstevel@tonic-gate 		return (NULL);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate 	wp->ulw_next_result = next;
4380Sstevel@tonic-gate 	return (np);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate static void
list_walk_fini(uu_list_walk_t * wp)4420Sstevel@tonic-gate list_walk_fini(uu_list_walk_t *wp)
4430Sstevel@tonic-gate {
4440Sstevel@tonic-gate 	/* GLXXX debugging? */
4450Sstevel@tonic-gate 	if (wp->ulw_next != NULL) {
4460Sstevel@tonic-gate 		wp->ulw_next->ulw_prev = wp->ulw_prev;
4470Sstevel@tonic-gate 		wp->ulw_prev->ulw_next = wp->ulw_next;
4480Sstevel@tonic-gate 		wp->ulw_next = NULL;
4490Sstevel@tonic-gate 		wp->ulw_prev = NULL;
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 	wp->ulw_list = NULL;
4520Sstevel@tonic-gate 	wp->ulw_next_result = NULL;
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate uu_list_walk_t *
uu_list_walk_start(uu_list_t * lp,uint32_t flags)4560Sstevel@tonic-gate uu_list_walk_start(uu_list_t *lp, uint32_t flags)
4570Sstevel@tonic-gate {
4580Sstevel@tonic-gate 	uu_list_walk_t *wp;
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
4610Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
4620Sstevel@tonic-gate 		return (NULL);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	wp = uu_zalloc(sizeof (*wp));
4660Sstevel@tonic-gate 	if (wp == NULL) {
4670Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
4680Sstevel@tonic-gate 		return (NULL);
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	list_walk_init(wp, lp, flags);
4720Sstevel@tonic-gate 	return (wp);
4730Sstevel@tonic-gate }
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate void *
uu_list_walk_next(uu_list_walk_t * wp)4760Sstevel@tonic-gate uu_list_walk_next(uu_list_walk_t *wp)
4770Sstevel@tonic-gate {
4780Sstevel@tonic-gate 	uu_list_t *lp = wp->ulw_list;
4790Sstevel@tonic-gate 	uu_list_node_impl_t *np = list_walk_advance(wp, lp);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if (np == NULL)
4820Sstevel@tonic-gate 		return (NULL);
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, np));
4850Sstevel@tonic-gate }
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate void
uu_list_walk_end(uu_list_walk_t * wp)4880Sstevel@tonic-gate uu_list_walk_end(uu_list_walk_t *wp)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	list_walk_fini(wp);
4910Sstevel@tonic-gate 	uu_free(wp);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate int
uu_list_walk(uu_list_t * lp,uu_walk_fn_t * func,void * private,uint32_t flags)4950Sstevel@tonic-gate uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate 	uu_list_node_impl_t *np;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	int status = UU_WALK_NEXT;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	int robust = (flags & UU_WALK_ROBUST);
5020Sstevel@tonic-gate 	int reverse = (flags & UU_WALK_REVERSE);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
5050Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
5060Sstevel@tonic-gate 		return (-1);
5070Sstevel@tonic-gate 	}
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	if (lp->ul_debug || robust) {
5100Sstevel@tonic-gate 		uu_list_walk_t my_walk;
5110Sstevel@tonic-gate 		void *e;
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		list_walk_init(&my_walk, lp, flags);
5140Sstevel@tonic-gate 		while (status == UU_WALK_NEXT &&
5150Sstevel@tonic-gate 		    (e = uu_list_walk_next(&my_walk)) != NULL)
5160Sstevel@tonic-gate 			status = (*func)(e, private);
5170Sstevel@tonic-gate 		list_walk_fini(&my_walk);
5180Sstevel@tonic-gate 	} else {
5190Sstevel@tonic-gate 		if (!reverse) {
5200Sstevel@tonic-gate 			for (np = lp->ul_null_node.uln_next;
5210Sstevel@tonic-gate 			    status == UU_WALK_NEXT && np != &lp->ul_null_node;
5220Sstevel@tonic-gate 			    np = np->uln_next) {
5230Sstevel@tonic-gate 				status = (*func)(NODE_TO_ELEM(lp, np), private);
5240Sstevel@tonic-gate 			}
5250Sstevel@tonic-gate 		} else {
5260Sstevel@tonic-gate 			for (np = lp->ul_null_node.uln_prev;
5270Sstevel@tonic-gate 			    status == UU_WALK_NEXT && np != &lp->ul_null_node;
5280Sstevel@tonic-gate 			    np = np->uln_prev) {
5290Sstevel@tonic-gate 				status = (*func)(NODE_TO_ELEM(lp, np), private);
5300Sstevel@tonic-gate 			}
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 	}
5330Sstevel@tonic-gate 	if (status >= 0)
5340Sstevel@tonic-gate 		return (0);
5350Sstevel@tonic-gate 	uu_set_error(UU_ERROR_CALLBACK_FAILED);
5360Sstevel@tonic-gate 	return (-1);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate void
uu_list_remove(uu_list_t * lp,void * elem)5400Sstevel@tonic-gate uu_list_remove(uu_list_t *lp, void *elem)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
5430Sstevel@tonic-gate 	uu_list_walk_t *wp;
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (lp->ul_debug) {
5460Sstevel@tonic-gate 		if (np->uln_prev == NULL)
5470Sstevel@tonic-gate 			uu_panic("uu_list_remove(%p, %p): elem not on list\n",
5487240Srh87107 			    (void *)lp, elem);
5490Sstevel@tonic-gate 		/*
5500Sstevel@tonic-gate 		 * invalidate outstanding uu_list_index_ts.
5510Sstevel@tonic-gate 		 */
5520Sstevel@tonic-gate 		lp->ul_index = INDEX_NEXT(lp->ul_index);
5530Sstevel@tonic-gate 	}
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 	/*
5560Sstevel@tonic-gate 	 * robust walkers must be advanced.  In debug mode, non-robust
5570Sstevel@tonic-gate 	 * walkers are also on the list.  If there are any, it's an error.
5580Sstevel@tonic-gate 	 */
5590Sstevel@tonic-gate 	for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
5600Sstevel@tonic-gate 	    wp = wp->ulw_next) {
5610Sstevel@tonic-gate 		if (wp->ulw_robust) {
5620Sstevel@tonic-gate 			if (np == wp->ulw_next_result)
5630Sstevel@tonic-gate 				(void) list_walk_advance(wp, lp);
5640Sstevel@tonic-gate 		} else if (wp->ulw_next_result != NULL) {
5650Sstevel@tonic-gate 			uu_panic("uu_list_remove(%p, %p): active non-robust "
5667240Srh87107 			    "walker\n", (void *)lp, elem);
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	np->uln_next->uln_prev = np->uln_prev;
5710Sstevel@tonic-gate 	np->uln_prev->uln_next = np->uln_next;
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	lp->ul_numnodes--;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	np->uln_next = POOL_TO_MARKER(lp->ul_pool);
5760Sstevel@tonic-gate 	np->uln_prev = NULL;
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate void *
uu_list_teardown(uu_list_t * lp,void ** cookie)5800Sstevel@tonic-gate uu_list_teardown(uu_list_t *lp, void **cookie)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	void *ep;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	/*
5850Sstevel@tonic-gate 	 * XXX: disable list modification until list is empty
5860Sstevel@tonic-gate 	 */
5870Sstevel@tonic-gate 	if (lp->ul_debug && *cookie != NULL)
5887240Srh87107 		uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
5897240Srh87107 		    (void *)lp, (void *)cookie);
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	ep = uu_list_first(lp);
5920Sstevel@tonic-gate 	if (ep)
5930Sstevel@tonic-gate 		uu_list_remove(lp, ep);
5940Sstevel@tonic-gate 	return (ep);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate int
uu_list_insert_before(uu_list_t * lp,void * target,void * elem)5980Sstevel@tonic-gate uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (target == NULL)
6030Sstevel@tonic-gate 		np = &lp->ul_null_node;
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	if (lp->ul_debug) {
6060Sstevel@tonic-gate 		if (np->uln_prev == NULL)
6070Sstevel@tonic-gate 			uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
6080Sstevel@tonic-gate 			    "not currently on a list\n",
6097240Srh87107 			    (void *)lp, target, elem, target);
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 	if (lp->ul_sorted) {
6120Sstevel@tonic-gate 		if (lp->ul_debug)
6130Sstevel@tonic-gate 			uu_panic("uu_list_insert_before(%p, ...): list is "
6147240Srh87107 			    "UU_LIST_SORTED\n", (void *)lp);
6150Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
6160Sstevel@tonic-gate 		return (-1);
6170Sstevel@tonic-gate 	}
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
6200Sstevel@tonic-gate 	return (0);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate int
uu_list_insert_after(uu_list_t * lp,void * target,void * elem)6240Sstevel@tonic-gate uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	if (target == NULL)
6290Sstevel@tonic-gate 		np = &lp->ul_null_node;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	if (lp->ul_debug) {
6320Sstevel@tonic-gate 		if (np->uln_prev == NULL)
6330Sstevel@tonic-gate 			uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
6340Sstevel@tonic-gate 			    "not currently on a list\n",
6357240Srh87107 			    (void *)lp, target, elem, target);
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 	if (lp->ul_sorted) {
6380Sstevel@tonic-gate 		if (lp->ul_debug)
6390Sstevel@tonic-gate 			uu_panic("uu_list_insert_after(%p, ...): list is "
6407240Srh87107 			    "UU_LIST_SORTED\n", (void *)lp);
6410Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
6420Sstevel@tonic-gate 		return (-1);
6430Sstevel@tonic-gate 	}
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
6460Sstevel@tonic-gate 	return (0);
6470Sstevel@tonic-gate }
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate size_t
uu_list_numnodes(uu_list_t * lp)6500Sstevel@tonic-gate uu_list_numnodes(uu_list_t *lp)
6510Sstevel@tonic-gate {
6520Sstevel@tonic-gate 	return (lp->ul_numnodes);
6530Sstevel@tonic-gate }
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate void *
uu_list_first(uu_list_t * lp)6560Sstevel@tonic-gate uu_list_first(uu_list_t *lp)
6570Sstevel@tonic-gate {
6580Sstevel@tonic-gate 	uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
6590Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6600Sstevel@tonic-gate 		return (NULL);
6610Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate void *
uu_list_last(uu_list_t * lp)6650Sstevel@tonic-gate uu_list_last(uu_list_t *lp)
6660Sstevel@tonic-gate {
6670Sstevel@tonic-gate 	uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
6680Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6690Sstevel@tonic-gate 		return (NULL);
6700Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate 
6730Sstevel@tonic-gate void *
uu_list_next(uu_list_t * lp,void * elem)6740Sstevel@tonic-gate uu_list_next(uu_list_t *lp, void *elem)
6750Sstevel@tonic-gate {
6760Sstevel@tonic-gate 	uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	n = n->uln_next;
6790Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6800Sstevel@tonic-gate 		return (NULL);
6810Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6820Sstevel@tonic-gate }
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate void *
uu_list_prev(uu_list_t * lp,void * elem)6850Sstevel@tonic-gate uu_list_prev(uu_list_t *lp, void *elem)
6860Sstevel@tonic-gate {
6870Sstevel@tonic-gate 	uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	n = n->uln_prev;
6900Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6910Sstevel@tonic-gate 		return (NULL);
6920Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6930Sstevel@tonic-gate }
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate /*
6960Sstevel@tonic-gate  * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
6970Sstevel@tonic-gate  */
6980Sstevel@tonic-gate void
uu_list_lockup(void)6990Sstevel@tonic-gate uu_list_lockup(void)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	uu_list_pool_t *pp;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
7040Sstevel@tonic-gate 	for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
7050Sstevel@tonic-gate 	    pp = pp->ulp_next)
7060Sstevel@tonic-gate 		(void) pthread_mutex_lock(&pp->ulp_lock);
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate void
uu_list_release(void)7100Sstevel@tonic-gate uu_list_release(void)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate 	uu_list_pool_t *pp;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 	for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
7150Sstevel@tonic-gate 	    pp = pp->ulp_next)
7160Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pp->ulp_lock);
7170Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
7180Sstevel@tonic-gate }
719