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