17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5903a11ebSrh  * Common Development and Distribution License (the "License").
6903a11ebSrh  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*4c178533SJason King 
227c478bd9Sstevel@tonic-gate /*
23903a11ebSrh  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*4c178533SJason King  *
26*4c178533SJason King  * Copyright 2011 Jason King.  All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include "libuutil_common.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <string.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <sys/time.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #define	ELEM_TO_NODE(lp, e) \
377c478bd9Sstevel@tonic-gate 	((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #define	NODE_TO_ELEM(lp, n) \
407c478bd9Sstevel@tonic-gate 	((void *)((uintptr_t)(n) - (lp)->ul_offset))
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * uu_list_index_ts define a location for insertion.  They are simply a
447c478bd9Sstevel@tonic-gate  * pointer to the object after the insertion point.  We store a mark
457c478bd9Sstevel@tonic-gate  * in the low-bits of the index, to help prevent mistakes.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * When debugging, the index mark changes on every insert and delete, to
487c478bd9Sstevel@tonic-gate  * catch stale references.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate #define	INDEX_MAX		(sizeof (uintptr_t) - 1)
517c478bd9Sstevel@tonic-gate #define	INDEX_NEXT(m)		(((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #define	INDEX_TO_NODE(i)	((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
547c478bd9Sstevel@tonic-gate #define	NODE_TO_INDEX(p, n)	(((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
557c478bd9Sstevel@tonic-gate #define	INDEX_VALID(p, i)	(((i) & INDEX_MAX) == (p)->ul_index)
567c478bd9Sstevel@tonic-gate #define	INDEX_CHECK(i)		(((i) & INDEX_MAX) != 0)
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate #define	POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate static uu_list_pool_t	uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
617c478bd9Sstevel@tonic-gate static pthread_mutex_t	uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@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)647c478bd9Sstevel@tonic-gate uu_list_pool_create(const char *name, size_t objsize,
657c478bd9Sstevel@tonic-gate     size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	uu_list_pool_t *pp, *next, *prev;
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	if (name == NULL ||
707c478bd9Sstevel@tonic-gate 	    uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
717c478bd9Sstevel@tonic-gate 	    nodeoffset + sizeof (uu_list_node_t) > objsize) {
727c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_INVALID_ARGUMENT);
737c478bd9Sstevel@tonic-gate 		return (NULL);
747c478bd9Sstevel@tonic-gate 	}
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	if (flags & ~UU_LIST_POOL_DEBUG) {
777c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
787c478bd9Sstevel@tonic-gate 		return (NULL);
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	pp = uu_zalloc(sizeof (uu_list_pool_t));
827c478bd9Sstevel@tonic-gate 	if (pp == NULL) {
837c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
847c478bd9Sstevel@tonic-gate 		return (NULL);
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	(void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
887c478bd9Sstevel@tonic-gate 	pp->ulp_nodeoffset = nodeoffset;
897c478bd9Sstevel@tonic-gate 	pp->ulp_objsize = objsize;
907c478bd9Sstevel@tonic-gate 	pp->ulp_cmp = compare_func;
917c478bd9Sstevel@tonic-gate 	if (flags & UU_LIST_POOL_DEBUG)
927c478bd9Sstevel@tonic-gate 		pp->ulp_debug = 1;
937c478bd9Sstevel@tonic-gate 	pp->ulp_last_index = 0;
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_init(&pp->ulp_lock, NULL);
967c478bd9Sstevel@tonic-gate 
978918dff3Sjwadams 	pp->ulp_null_list.ul_next_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
988918dff3Sjwadams 	pp->ulp_null_list.ul_prev_enc = UU_PTR_ENCODE(&pp->ulp_null_list);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
1017c478bd9Sstevel@tonic-gate 	pp->ulp_next = next = &uu_null_lpool;
1027c478bd9Sstevel@tonic-gate 	pp->ulp_prev = prev = next->ulp_prev;
1037c478bd9Sstevel@tonic-gate 	next->ulp_prev = pp;
1047c478bd9Sstevel@tonic-gate 	prev->ulp_next = pp;
1057c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	return (pp);
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate void
uu_list_pool_destroy(uu_list_pool_t * pp)1117c478bd9Sstevel@tonic-gate uu_list_pool_destroy(uu_list_pool_t *pp)
1127c478bd9Sstevel@tonic-gate {
1137c478bd9Sstevel@tonic-gate 	if (pp->ulp_debug) {
1148918dff3Sjwadams 		if (pp->ulp_null_list.ul_next_enc !=
1158918dff3Sjwadams 		    UU_PTR_ENCODE(&pp->ulp_null_list) ||
1168918dff3Sjwadams 		    pp->ulp_null_list.ul_prev_enc !=
1178918dff3Sjwadams 		    UU_PTR_ENCODE(&pp->ulp_null_list)) {
1187c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
1197c478bd9Sstevel@tonic-gate 			    "outstanding lists, or is corrupt.\n",
120903a11ebSrh 			    (int)sizeof (pp->ulp_name), pp->ulp_name,
121903a11ebSrh 			    (void *)pp);
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
1257c478bd9Sstevel@tonic-gate 	pp->ulp_next->ulp_prev = pp->ulp_prev;
1267c478bd9Sstevel@tonic-gate 	pp->ulp_prev->ulp_next = pp->ulp_next;
1277c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
1287c478bd9Sstevel@tonic-gate 	pp->ulp_prev = NULL;
1297c478bd9Sstevel@tonic-gate 	pp->ulp_next = NULL;
1307c478bd9Sstevel@tonic-gate 	uu_free(pp);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate void
uu_list_node_init(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)1347c478bd9Sstevel@tonic-gate uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (pp->ulp_debug) {
1397c478bd9Sstevel@tonic-gate 		uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
1407c478bd9Sstevel@tonic-gate 		if (offset + sizeof (*np) > pp->ulp_objsize) {
1417c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
1427c478bd9Sstevel@tonic-gate 			    "offset %ld doesn't fit in object (size %ld)\n",
143903a11ebSrh 			    base, (void *)np, (void *)pp, pp->ulp_name,
144903a11ebSrh 			    (long)offset, (long)pp->ulp_objsize);
1457c478bd9Sstevel@tonic-gate 		}
1467c478bd9Sstevel@tonic-gate 		if (offset != pp->ulp_nodeoffset) {
1477c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
1487c478bd9Sstevel@tonic-gate 			    "offset %ld doesn't match pool's offset (%ld)\n",
149903a11ebSrh 			    base, (void *)np, (void *)pp, pp->ulp_name,
150903a11ebSrh 			    (long)offset, (long)pp->ulp_objsize);
1517c478bd9Sstevel@tonic-gate 		}
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 	np->uln_next = POOL_TO_MARKER(pp);
1547c478bd9Sstevel@tonic-gate 	np->uln_prev = NULL;
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate void
uu_list_node_fini(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)1587c478bd9Sstevel@tonic-gate uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	if (pp->ulp_debug) {
1637c478bd9Sstevel@tonic-gate 		if (np->uln_next == NULL &&
1647c478bd9Sstevel@tonic-gate 		    np->uln_prev == NULL) {
1657c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
1667c478bd9Sstevel@tonic-gate 			    "node already finied\n",
167903a11ebSrh 			    base, (void *)np_arg, (void *)pp, pp->ulp_name);
1687c478bd9Sstevel@tonic-gate 		}
1697c478bd9Sstevel@tonic-gate 		if (np->uln_next != POOL_TO_MARKER(pp) ||
1707c478bd9Sstevel@tonic-gate 		    np->uln_prev != NULL) {
1717c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
1727c478bd9Sstevel@tonic-gate 			    "node corrupt or on list\n",
173903a11ebSrh 			    base, (void *)np_arg, (void *)pp, pp->ulp_name);
1747c478bd9Sstevel@tonic-gate 		}
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 	np->uln_next = NULL;
1777c478bd9Sstevel@tonic-gate 	np->uln_prev = NULL;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate uu_list_t *
uu_list_create(uu_list_pool_t * pp,void * parent,uint32_t flags)1817c478bd9Sstevel@tonic-gate uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
1827c478bd9Sstevel@tonic-gate {
1837c478bd9Sstevel@tonic-gate 	uu_list_t *lp, *next, *prev;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
1867c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
1877c478bd9Sstevel@tonic-gate 		return (NULL);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
1917c478bd9Sstevel@tonic-gate 		if (pp->ulp_debug)
1927c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_create(%p, ...): requested "
1937c478bd9Sstevel@tonic-gate 			    "UU_LIST_SORTED, but pool has no comparison func\n",
194903a11ebSrh 			    (void *)pp);
1957c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
1967c478bd9Sstevel@tonic-gate 		return (NULL);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	lp = uu_zalloc(sizeof (*lp));
2007c478bd9Sstevel@tonic-gate 	if (lp == NULL) {
2017c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
2027c478bd9Sstevel@tonic-gate 		return (NULL);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	lp->ul_pool = pp;
2068918dff3Sjwadams 	lp->ul_parent_enc = UU_PTR_ENCODE(parent);
2077c478bd9Sstevel@tonic-gate 	lp->ul_offset = pp->ulp_nodeoffset;
2087c478bd9Sstevel@tonic-gate 	lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
2097c478bd9Sstevel@tonic-gate 	lp->ul_sorted = (flags & UU_LIST_SORTED);
2107c478bd9Sstevel@tonic-gate 	lp->ul_numnodes = 0;
2117c478bd9Sstevel@tonic-gate 	lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	lp->ul_null_node.uln_next = &lp->ul_null_node;
2147c478bd9Sstevel@tonic-gate 	lp->ul_null_node.uln_prev = &lp->ul_null_node;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
2177c478bd9Sstevel@tonic-gate 	lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pp->ulp_lock);
2208918dff3Sjwadams 	next = &pp->ulp_null_list;
2218918dff3Sjwadams 	prev = UU_PTR_DECODE(next->ul_prev_enc);
2228918dff3Sjwadams 	lp->ul_next_enc = UU_PTR_ENCODE(next);
2238918dff3Sjwadams 	lp->ul_prev_enc = UU_PTR_ENCODE(prev);
2248918dff3Sjwadams 	next->ul_prev_enc = UU_PTR_ENCODE(lp);
2258918dff3Sjwadams 	prev->ul_next_enc = UU_PTR_ENCODE(lp);
2267c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pp->ulp_lock);
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	return (lp);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate void
uu_list_destroy(uu_list_t * lp)2327c478bd9Sstevel@tonic-gate uu_list_destroy(uu_list_t *lp)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	uu_list_pool_t *pp = lp->ul_pool;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
2377c478bd9Sstevel@tonic-gate 		if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
2387c478bd9Sstevel@tonic-gate 		    lp->ul_null_node.uln_prev != &lp->ul_null_node) {
2397c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  list not empty\n",
240903a11ebSrh 			    (void *)lp);
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 		if (lp->ul_numnodes != 0) {
2437c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  numnodes is nonzero, "
244903a11ebSrh 			    "but list is empty\n", (void *)lp);
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
2477c478bd9Sstevel@tonic-gate 		    lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
2487c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_destroy(%p):  outstanding walkers\n",
249903a11ebSrh 			    (void *)lp);
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&pp->ulp_lock);
2548918dff3Sjwadams 	UU_LIST_PTR(lp->ul_next_enc)->ul_prev_enc = lp->ul_prev_enc;
2558918dff3Sjwadams 	UU_LIST_PTR(lp->ul_prev_enc)->ul_next_enc = lp->ul_next_enc;
2567c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&pp->ulp_lock);
2578918dff3Sjwadams 	lp->ul_prev_enc = UU_PTR_ENCODE(NULL);
2588918dff3Sjwadams 	lp->ul_next_enc = UU_PTR_ENCODE(NULL);
2597c478bd9Sstevel@tonic-gate 	lp->ul_pool = NULL;
2607c478bd9Sstevel@tonic-gate 	uu_free(lp);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@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)2647c478bd9Sstevel@tonic-gate list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
2657c478bd9Sstevel@tonic-gate     uu_list_node_impl_t *next)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
2687c478bd9Sstevel@tonic-gate 		if (next->uln_prev != prev || prev->uln_next != next)
2697c478bd9Sstevel@tonic-gate 			uu_panic("insert(%p): internal error: %p and %p not "
270903a11ebSrh 			    "neighbors\n", (void *)lp, (void *)next,
271903a11ebSrh 			    (void *)prev);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 		if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
2747c478bd9Sstevel@tonic-gate 		    np->uln_prev != NULL) {
2757c478bd9Sstevel@tonic-gate 			uu_panic("insert(%p): elem %p node %p corrupt, "
2767c478bd9Sstevel@tonic-gate 			    "not initialized, or already in a list.\n",
277903a11ebSrh 			    (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 		/*
2807c478bd9Sstevel@tonic-gate 		 * invalidate outstanding uu_list_index_ts.
2817c478bd9Sstevel@tonic-gate 		 */
2827c478bd9Sstevel@tonic-gate 		lp->ul_index = INDEX_NEXT(lp->ul_index);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	np->uln_next = next;
2857c478bd9Sstevel@tonic-gate 	np->uln_prev = prev;
2867c478bd9Sstevel@tonic-gate 	next->uln_prev = np;
2877c478bd9Sstevel@tonic-gate 	prev->uln_next = np;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	lp->ul_numnodes++;
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate void
uu_list_insert(uu_list_t * lp,void * elem,uu_list_index_t idx)2937c478bd9Sstevel@tonic-gate uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
2947c478bd9Sstevel@tonic-gate {
2957c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	np = INDEX_TO_NODE(idx);
2987c478bd9Sstevel@tonic-gate 	if (np == NULL)
2997c478bd9Sstevel@tonic-gate 		np = &lp->ul_null_node;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
3027c478bd9Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3037c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert(%p, %p, %p): %s\n",
304903a11ebSrh 			    (void *)lp, elem, (void *)idx,
3057c478bd9Sstevel@tonic-gate 			    INDEX_CHECK(idx)? "outdated index" :
3067c478bd9Sstevel@tonic-gate 			    "invalid index");
3077c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3087c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
309903a11ebSrh 			    "index\n", (void *)lp, elem, (void *)idx);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate void *
uu_list_find(uu_list_t * lp,void * elem,void * private,uu_list_index_t * out)3167c478bd9Sstevel@tonic-gate uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
3177c478bd9Sstevel@tonic-gate {
3187c478bd9Sstevel@tonic-gate 	int sorted = lp->ul_sorted;
3197c478bd9Sstevel@tonic-gate 	uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
3207c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np;
3217c478bd9Sstevel@tonic-gate 
322*4c178533SJason King 	uu_set_error(UU_ERROR_NONE);
323*4c178533SJason King 
3247c478bd9Sstevel@tonic-gate 	if (func == NULL) {
3257c478bd9Sstevel@tonic-gate 		if (out != NULL)
3267c478bd9Sstevel@tonic-gate 			*out = 0;
3277c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
3287c478bd9Sstevel@tonic-gate 		return (NULL);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 	for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
3317c478bd9Sstevel@tonic-gate 	    np = np->uln_next) {
3327c478bd9Sstevel@tonic-gate 		void *ep = NODE_TO_ELEM(lp, np);
3337c478bd9Sstevel@tonic-gate 		int cmp = func(ep, elem, private);
3347c478bd9Sstevel@tonic-gate 		if (cmp == 0) {
3357c478bd9Sstevel@tonic-gate 			if (out != NULL)
3367c478bd9Sstevel@tonic-gate 				*out = NODE_TO_INDEX(lp, np);
3377c478bd9Sstevel@tonic-gate 			return (ep);
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 		if (sorted && cmp > 0) {
3407c478bd9Sstevel@tonic-gate 			if (out != NULL)
3417c478bd9Sstevel@tonic-gate 				*out = NODE_TO_INDEX(lp, np);
3427c478bd9Sstevel@tonic-gate 			return (NULL);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 	if (out != NULL)
3467c478bd9Sstevel@tonic-gate 		*out = NODE_TO_INDEX(lp, 0);
3477c478bd9Sstevel@tonic-gate 	return (NULL);
3487c478bd9Sstevel@tonic-gate }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate void *
uu_list_nearest_next(uu_list_t * lp,uu_list_index_t idx)3517c478bd9Sstevel@tonic-gate uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
3527c478bd9Sstevel@tonic-gate {
3537c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (np == NULL)
3567c478bd9Sstevel@tonic-gate 		np = &lp->ul_null_node;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
3597c478bd9Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3607c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_nearest_next(%p, %p): %s\n",
361903a11ebSrh 			    (void *)lp, (void *)idx,
362903a11ebSrh 			    INDEX_CHECK(idx)? "outdated index" :
3637c478bd9Sstevel@tonic-gate 			    "invalid index");
3647c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3657c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
366903a11ebSrh 			    "index\n", (void *)lp, (void *)idx);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (np == &lp->ul_null_node)
3707c478bd9Sstevel@tonic-gate 		return (NULL);
3717c478bd9Sstevel@tonic-gate 	else
3727c478bd9Sstevel@tonic-gate 		return (NODE_TO_ELEM(lp, np));
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate void *
uu_list_nearest_prev(uu_list_t * lp,uu_list_index_t idx)3767c478bd9Sstevel@tonic-gate uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	if (np == NULL)
3817c478bd9Sstevel@tonic-gate 		np = &lp->ul_null_node;
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
3847c478bd9Sstevel@tonic-gate 		if (!INDEX_VALID(lp, idx))
3857c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
386903a11ebSrh 			    (void *)lp, (void *)idx, INDEX_CHECK(idx)?
387903a11ebSrh 			    "outdated index" : "invalid index");
3887c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
3897c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
390903a11ebSrh 			    "index\n", (void *)lp, (void *)idx);
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	if ((np = np->uln_prev) == &lp->ul_null_node)
3947c478bd9Sstevel@tonic-gate 		return (NULL);
3957c478bd9Sstevel@tonic-gate 	else
3967c478bd9Sstevel@tonic-gate 		return (NODE_TO_ELEM(lp, np));
3977c478bd9Sstevel@tonic-gate }
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate static void
list_walk_init(uu_list_walk_t * wp,uu_list_t * lp,uint32_t flags)4007c478bd9Sstevel@tonic-gate list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
4017c478bd9Sstevel@tonic-gate {
4027c478bd9Sstevel@tonic-gate 	uu_list_walk_t *next, *prev;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	int robust = (flags & UU_WALK_ROBUST);
4057c478bd9Sstevel@tonic-gate 	int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	(void) memset(wp, 0, sizeof (*wp));
4087c478bd9Sstevel@tonic-gate 	wp->ulw_list = lp;
4097c478bd9Sstevel@tonic-gate 	wp->ulw_robust = robust;
4107c478bd9Sstevel@tonic-gate 	wp->ulw_dir = direction;
4117c478bd9Sstevel@tonic-gate 	if (direction > 0)
4127c478bd9Sstevel@tonic-gate 		wp->ulw_next_result = lp->ul_null_node.uln_next;
4137c478bd9Sstevel@tonic-gate 	else
4147c478bd9Sstevel@tonic-gate 		wp->ulw_next_result = lp->ul_null_node.uln_prev;
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	if (lp->ul_debug || robust) {
4176643e1ffSbustos 		/*
4186643e1ffSbustos 		 * Add this walker to the list's list of walkers so
4196643e1ffSbustos 		 * uu_list_remove() can advance us if somebody tries to
4206643e1ffSbustos 		 * remove ulw_next_result.
4216643e1ffSbustos 		 */
4227c478bd9Sstevel@tonic-gate 		wp->ulw_next = next = &lp->ul_null_walk;
4237c478bd9Sstevel@tonic-gate 		wp->ulw_prev = prev = next->ulw_prev;
4247c478bd9Sstevel@tonic-gate 		next->ulw_prev = wp;
4257c478bd9Sstevel@tonic-gate 		prev->ulw_next = wp;
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate static uu_list_node_impl_t *
list_walk_advance(uu_list_walk_t * wp,uu_list_t * lp)4307c478bd9Sstevel@tonic-gate list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = wp->ulw_next_result;
4337c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *next;
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	if (np == &lp->ul_null_node)
4367c478bd9Sstevel@tonic-gate 		return (NULL);
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	wp->ulw_next_result = next;
4417c478bd9Sstevel@tonic-gate 	return (np);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate static void
list_walk_fini(uu_list_walk_t * wp)4457c478bd9Sstevel@tonic-gate list_walk_fini(uu_list_walk_t *wp)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	/* GLXXX debugging? */
4487c478bd9Sstevel@tonic-gate 	if (wp->ulw_next != NULL) {
4497c478bd9Sstevel@tonic-gate 		wp->ulw_next->ulw_prev = wp->ulw_prev;
4507c478bd9Sstevel@tonic-gate 		wp->ulw_prev->ulw_next = wp->ulw_next;
4517c478bd9Sstevel@tonic-gate 		wp->ulw_next = NULL;
4527c478bd9Sstevel@tonic-gate 		wp->ulw_prev = NULL;
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 	wp->ulw_list = NULL;
4557c478bd9Sstevel@tonic-gate 	wp->ulw_next_result = NULL;
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate uu_list_walk_t *
uu_list_walk_start(uu_list_t * lp,uint32_t flags)4597c478bd9Sstevel@tonic-gate uu_list_walk_start(uu_list_t *lp, uint32_t flags)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	uu_list_walk_t *wp;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
4647c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
4657c478bd9Sstevel@tonic-gate 		return (NULL);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	wp = uu_zalloc(sizeof (*wp));
4697c478bd9Sstevel@tonic-gate 	if (wp == NULL) {
4707c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NO_MEMORY);
4717c478bd9Sstevel@tonic-gate 		return (NULL);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	list_walk_init(wp, lp, flags);
4757c478bd9Sstevel@tonic-gate 	return (wp);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate void *
uu_list_walk_next(uu_list_walk_t * wp)4797c478bd9Sstevel@tonic-gate uu_list_walk_next(uu_list_walk_t *wp)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	uu_list_t *lp = wp->ulw_list;
4827c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = list_walk_advance(wp, lp);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (np == NULL)
4857c478bd9Sstevel@tonic-gate 		return (NULL);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, np));
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate void
uu_list_walk_end(uu_list_walk_t * wp)4917c478bd9Sstevel@tonic-gate uu_list_walk_end(uu_list_walk_t *wp)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate 	list_walk_fini(wp);
4947c478bd9Sstevel@tonic-gate 	uu_free(wp);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate int
uu_list_walk(uu_list_t * lp,uu_walk_fn_t * func,void * private,uint32_t flags)4987c478bd9Sstevel@tonic-gate uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
4997c478bd9Sstevel@tonic-gate {
5007c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	int status = UU_WALK_NEXT;
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	int robust = (flags & UU_WALK_ROBUST);
5057c478bd9Sstevel@tonic-gate 	int reverse = (flags & UU_WALK_REVERSE);
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
5087c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_UNKNOWN_FLAG);
5097c478bd9Sstevel@tonic-gate 		return (-1);
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (lp->ul_debug || robust) {
5137c478bd9Sstevel@tonic-gate 		uu_list_walk_t my_walk;
5147c478bd9Sstevel@tonic-gate 		void *e;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		list_walk_init(&my_walk, lp, flags);
5177c478bd9Sstevel@tonic-gate 		while (status == UU_WALK_NEXT &&
5187c478bd9Sstevel@tonic-gate 		    (e = uu_list_walk_next(&my_walk)) != NULL)
5197c478bd9Sstevel@tonic-gate 			status = (*func)(e, private);
5207c478bd9Sstevel@tonic-gate 		list_walk_fini(&my_walk);
5217c478bd9Sstevel@tonic-gate 	} else {
5227c478bd9Sstevel@tonic-gate 		if (!reverse) {
5237c478bd9Sstevel@tonic-gate 			for (np = lp->ul_null_node.uln_next;
5247c478bd9Sstevel@tonic-gate 			    status == UU_WALK_NEXT && np != &lp->ul_null_node;
5257c478bd9Sstevel@tonic-gate 			    np = np->uln_next) {
5267c478bd9Sstevel@tonic-gate 				status = (*func)(NODE_TO_ELEM(lp, np), private);
5277c478bd9Sstevel@tonic-gate 			}
5287c478bd9Sstevel@tonic-gate 		} else {
5297c478bd9Sstevel@tonic-gate 			for (np = lp->ul_null_node.uln_prev;
5307c478bd9Sstevel@tonic-gate 			    status == UU_WALK_NEXT && np != &lp->ul_null_node;
5317c478bd9Sstevel@tonic-gate 			    np = np->uln_prev) {
5327c478bd9Sstevel@tonic-gate 				status = (*func)(NODE_TO_ELEM(lp, np), private);
5337c478bd9Sstevel@tonic-gate 			}
5347c478bd9Sstevel@tonic-gate 		}
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 	if (status >= 0)
5377c478bd9Sstevel@tonic-gate 		return (0);
5387c478bd9Sstevel@tonic-gate 	uu_set_error(UU_ERROR_CALLBACK_FAILED);
5397c478bd9Sstevel@tonic-gate 	return (-1);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate void
uu_list_remove(uu_list_t * lp,void * elem)5437c478bd9Sstevel@tonic-gate uu_list_remove(uu_list_t *lp, void *elem)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
5467c478bd9Sstevel@tonic-gate 	uu_list_walk_t *wp;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
5497c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
5507c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_remove(%p, %p): elem not on list\n",
551903a11ebSrh 			    (void *)lp, elem);
5527c478bd9Sstevel@tonic-gate 		/*
5537c478bd9Sstevel@tonic-gate 		 * invalidate outstanding uu_list_index_ts.
5547c478bd9Sstevel@tonic-gate 		 */
5557c478bd9Sstevel@tonic-gate 		lp->ul_index = INDEX_NEXT(lp->ul_index);
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	/*
5597c478bd9Sstevel@tonic-gate 	 * robust walkers must be advanced.  In debug mode, non-robust
5607c478bd9Sstevel@tonic-gate 	 * walkers are also on the list.  If there are any, it's an error.
5617c478bd9Sstevel@tonic-gate 	 */
5627c478bd9Sstevel@tonic-gate 	for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
5637c478bd9Sstevel@tonic-gate 	    wp = wp->ulw_next) {
5647c478bd9Sstevel@tonic-gate 		if (wp->ulw_robust) {
5657c478bd9Sstevel@tonic-gate 			if (np == wp->ulw_next_result)
5667c478bd9Sstevel@tonic-gate 				(void) list_walk_advance(wp, lp);
5677c478bd9Sstevel@tonic-gate 		} else if (wp->ulw_next_result != NULL) {
5687c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_remove(%p, %p): active non-robust "
569903a11ebSrh 			    "walker\n", (void *)lp, elem);
5707c478bd9Sstevel@tonic-gate 		}
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	np->uln_next->uln_prev = np->uln_prev;
5747c478bd9Sstevel@tonic-gate 	np->uln_prev->uln_next = np->uln_next;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	lp->ul_numnodes--;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	np->uln_next = POOL_TO_MARKER(lp->ul_pool);
5797c478bd9Sstevel@tonic-gate 	np->uln_prev = NULL;
5807c478bd9Sstevel@tonic-gate }
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate void *
uu_list_teardown(uu_list_t * lp,void ** cookie)5837c478bd9Sstevel@tonic-gate uu_list_teardown(uu_list_t *lp, void **cookie)
5847c478bd9Sstevel@tonic-gate {
5857c478bd9Sstevel@tonic-gate 	void *ep;
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * XXX: disable list modification until list is empty
5897c478bd9Sstevel@tonic-gate 	 */
5907c478bd9Sstevel@tonic-gate 	if (lp->ul_debug && *cookie != NULL)
591903a11ebSrh 		uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
592903a11ebSrh 		    (void *)lp, (void *)cookie);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	ep = uu_list_first(lp);
5957c478bd9Sstevel@tonic-gate 	if (ep)
5967c478bd9Sstevel@tonic-gate 		uu_list_remove(lp, ep);
5977c478bd9Sstevel@tonic-gate 	return (ep);
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate int
uu_list_insert_before(uu_list_t * lp,void * target,void * elem)6017c478bd9Sstevel@tonic-gate uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (target == NULL)
6067c478bd9Sstevel@tonic-gate 		np = &lp->ul_null_node;
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
6097c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
6107c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
6117c478bd9Sstevel@tonic-gate 			    "not currently on a list\n",
612903a11ebSrh 			    (void *)lp, target, elem, target);
6137c478bd9Sstevel@tonic-gate 	}
6147c478bd9Sstevel@tonic-gate 	if (lp->ul_sorted) {
6157c478bd9Sstevel@tonic-gate 		if (lp->ul_debug)
6167c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert_before(%p, ...): list is "
617903a11ebSrh 			    "UU_LIST_SORTED\n", (void *)lp);
6187c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
6197c478bd9Sstevel@tonic-gate 		return (-1);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
6237c478bd9Sstevel@tonic-gate 	return (0);
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate int
uu_list_insert_after(uu_list_t * lp,void * target,void * elem)6277c478bd9Sstevel@tonic-gate uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	if (target == NULL)
6327c478bd9Sstevel@tonic-gate 		np = &lp->ul_null_node;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (lp->ul_debug) {
6357c478bd9Sstevel@tonic-gate 		if (np->uln_prev == NULL)
6367c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
6377c478bd9Sstevel@tonic-gate 			    "not currently on a list\n",
638903a11ebSrh 			    (void *)lp, target, elem, target);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 	if (lp->ul_sorted) {
6417c478bd9Sstevel@tonic-gate 		if (lp->ul_debug)
6427c478bd9Sstevel@tonic-gate 			uu_panic("uu_list_insert_after(%p, ...): list is "
643903a11ebSrh 			    "UU_LIST_SORTED\n", (void *)lp);
6447c478bd9Sstevel@tonic-gate 		uu_set_error(UU_ERROR_NOT_SUPPORTED);
6457c478bd9Sstevel@tonic-gate 		return (-1);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
6497c478bd9Sstevel@tonic-gate 	return (0);
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate size_t
uu_list_numnodes(uu_list_t * lp)6537c478bd9Sstevel@tonic-gate uu_list_numnodes(uu_list_t *lp)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	return (lp->ul_numnodes);
6567c478bd9Sstevel@tonic-gate }
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate void *
uu_list_first(uu_list_t * lp)6597c478bd9Sstevel@tonic-gate uu_list_first(uu_list_t *lp)
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
6627c478bd9Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6637c478bd9Sstevel@tonic-gate 		return (NULL);
6647c478bd9Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate void *
uu_list_last(uu_list_t * lp)6687c478bd9Sstevel@tonic-gate uu_list_last(uu_list_t *lp)
6697c478bd9Sstevel@tonic-gate {
6707c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
6717c478bd9Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6727c478bd9Sstevel@tonic-gate 		return (NULL);
6737c478bd9Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate void *
uu_list_next(uu_list_t * lp,void * elem)6777c478bd9Sstevel@tonic-gate uu_list_next(uu_list_t *lp, void *elem)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	n = n->uln_next;
6827c478bd9Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6837c478bd9Sstevel@tonic-gate 		return (NULL);
6847c478bd9Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6857c478bd9Sstevel@tonic-gate }
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate void *
uu_list_prev(uu_list_t * lp,void * elem)6887c478bd9Sstevel@tonic-gate uu_list_prev(uu_list_t *lp, void *elem)
6897c478bd9Sstevel@tonic-gate {
6907c478bd9Sstevel@tonic-gate 	uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	n = n->uln_prev;
6937c478bd9Sstevel@tonic-gate 	if (n == &lp->ul_null_node)
6947c478bd9Sstevel@tonic-gate 		return (NULL);
6957c478bd9Sstevel@tonic-gate 	return (NODE_TO_ELEM(lp, n));
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate /*
6997c478bd9Sstevel@tonic-gate  * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
7007c478bd9Sstevel@tonic-gate  */
7017c478bd9Sstevel@tonic-gate void
uu_list_lockup(void)7027c478bd9Sstevel@tonic-gate uu_list_lockup(void)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	uu_list_pool_t *pp;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&uu_lpool_list_lock);
7077c478bd9Sstevel@tonic-gate 	for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
7087c478bd9Sstevel@tonic-gate 	    pp = pp->ulp_next)
7097c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&pp->ulp_lock);
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate void
uu_list_release(void)7137c478bd9Sstevel@tonic-gate uu_list_release(void)
7147c478bd9Sstevel@tonic-gate {
7157c478bd9Sstevel@tonic-gate 	uu_list_pool_t *pp;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
7187c478bd9Sstevel@tonic-gate 	    pp = pp->ulp_next)
7197c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&pp->ulp_lock);
7207c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&uu_lpool_list_lock);
7217c478bd9Sstevel@tonic-gate }
722