1eda14cbcSMatt Macy /*
2eda14cbcSMatt Macy * CDDL HEADER START
3eda14cbcSMatt Macy *
4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the
5eda14cbcSMatt Macy * Common Development and Distribution License (the "License").
6eda14cbcSMatt Macy * You may not use this file except in compliance with the License.
7eda14cbcSMatt Macy *
8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0.
10eda14cbcSMatt Macy * See the License for the specific language governing permissions
11eda14cbcSMatt Macy * and limitations under the License.
12eda14cbcSMatt Macy *
13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each
14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the
16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying
17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner]
18eda14cbcSMatt Macy *
19eda14cbcSMatt Macy * CDDL HEADER END
20eda14cbcSMatt Macy */
21eda14cbcSMatt Macy /*
22eda14cbcSMatt Macy * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23eda14cbcSMatt Macy * Use is subject to license terms.
24eda14cbcSMatt Macy */
25eda14cbcSMatt Macy
26eda14cbcSMatt Macy
27eda14cbcSMatt Macy
28eda14cbcSMatt Macy #include "libuutil_common.h"
29eda14cbcSMatt Macy
30eda14cbcSMatt Macy #include <stdlib.h>
31eda14cbcSMatt Macy #include <string.h>
32eda14cbcSMatt Macy #include <unistd.h>
33eda14cbcSMatt Macy #include <sys/time.h>
34eda14cbcSMatt Macy
35eda14cbcSMatt Macy #define ELEM_TO_NODE(lp, e) \
36eda14cbcSMatt Macy ((uu_list_node_impl_t *)((uintptr_t)(e) + (lp)->ul_offset))
37eda14cbcSMatt Macy
38eda14cbcSMatt Macy #define NODE_TO_ELEM(lp, n) \
39eda14cbcSMatt Macy ((void *)((uintptr_t)(n) - (lp)->ul_offset))
40eda14cbcSMatt Macy
41eda14cbcSMatt Macy /*
42eda14cbcSMatt Macy * uu_list_index_ts define a location for insertion. They are simply a
43eda14cbcSMatt Macy * pointer to the object after the insertion point. We store a mark
44eda14cbcSMatt Macy * in the low-bits of the index, to help prevent mistakes.
45eda14cbcSMatt Macy *
46eda14cbcSMatt Macy * When debugging, the index mark changes on every insert and delete, to
47eda14cbcSMatt Macy * catch stale references.
48eda14cbcSMatt Macy */
49eda14cbcSMatt Macy #define INDEX_MAX (sizeof (uintptr_t) - 1)
50eda14cbcSMatt Macy #define INDEX_NEXT(m) (((m) == INDEX_MAX)? 1 : ((m) + 1) & INDEX_MAX)
51eda14cbcSMatt Macy
52eda14cbcSMatt Macy #define INDEX_TO_NODE(i) ((uu_list_node_impl_t *)((i) & ~INDEX_MAX))
53eda14cbcSMatt Macy #define NODE_TO_INDEX(p, n) (((uintptr_t)(n) & ~INDEX_MAX) | (p)->ul_index)
54eda14cbcSMatt Macy #define INDEX_VALID(p, i) (((i) & INDEX_MAX) == (p)->ul_index)
55eda14cbcSMatt Macy #define INDEX_CHECK(i) (((i) & INDEX_MAX) != 0)
56eda14cbcSMatt Macy
57eda14cbcSMatt Macy #define POOL_TO_MARKER(pp) ((void *)((uintptr_t)(pp) | 1))
58eda14cbcSMatt Macy
59eda14cbcSMatt Macy static uu_list_pool_t uu_null_lpool = { &uu_null_lpool, &uu_null_lpool };
60eda14cbcSMatt Macy static pthread_mutex_t uu_lpool_list_lock = PTHREAD_MUTEX_INITIALIZER;
61eda14cbcSMatt Macy
62eda14cbcSMatt Macy 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)63eda14cbcSMatt Macy uu_list_pool_create(const char *name, size_t objsize,
64eda14cbcSMatt Macy size_t nodeoffset, uu_compare_fn_t *compare_func, uint32_t flags)
65eda14cbcSMatt Macy {
66eda14cbcSMatt Macy uu_list_pool_t *pp, *next, *prev;
67eda14cbcSMatt Macy
68eda14cbcSMatt Macy if (name == NULL ||
69eda14cbcSMatt Macy uu_check_name(name, UU_NAME_DOMAIN) == -1 ||
70eda14cbcSMatt Macy nodeoffset + sizeof (uu_list_node_t) > objsize) {
71eda14cbcSMatt Macy uu_set_error(UU_ERROR_INVALID_ARGUMENT);
72eda14cbcSMatt Macy return (NULL);
73eda14cbcSMatt Macy }
74eda14cbcSMatt Macy
75eda14cbcSMatt Macy if (flags & ~UU_LIST_POOL_DEBUG) {
76eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG);
77eda14cbcSMatt Macy return (NULL);
78eda14cbcSMatt Macy }
79eda14cbcSMatt Macy
80eda14cbcSMatt Macy pp = uu_zalloc(sizeof (uu_list_pool_t));
81eda14cbcSMatt Macy if (pp == NULL) {
82eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY);
83eda14cbcSMatt Macy return (NULL);
84eda14cbcSMatt Macy }
85eda14cbcSMatt Macy
86eda14cbcSMatt Macy (void) strlcpy(pp->ulp_name, name, sizeof (pp->ulp_name));
87eda14cbcSMatt Macy pp->ulp_nodeoffset = nodeoffset;
88eda14cbcSMatt Macy pp->ulp_objsize = objsize;
89eda14cbcSMatt Macy pp->ulp_cmp = compare_func;
90eda14cbcSMatt Macy if (flags & UU_LIST_POOL_DEBUG)
91eda14cbcSMatt Macy pp->ulp_debug = 1;
92eda14cbcSMatt Macy pp->ulp_last_index = 0;
93eda14cbcSMatt Macy
94eda14cbcSMatt Macy (void) pthread_mutex_init(&pp->ulp_lock, NULL);
95eda14cbcSMatt Macy
96dbd5678dSMartin Matuska pp->ulp_null_list.ul_next = &pp->ulp_null_list;
97dbd5678dSMartin Matuska pp->ulp_null_list.ul_prev = &pp->ulp_null_list;
98eda14cbcSMatt Macy
99eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_lpool_list_lock);
100eda14cbcSMatt Macy pp->ulp_next = next = &uu_null_lpool;
101eda14cbcSMatt Macy pp->ulp_prev = prev = next->ulp_prev;
102eda14cbcSMatt Macy next->ulp_prev = pp;
103eda14cbcSMatt Macy prev->ulp_next = pp;
104eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_lpool_list_lock);
105eda14cbcSMatt Macy
106eda14cbcSMatt Macy return (pp);
107eda14cbcSMatt Macy }
108eda14cbcSMatt Macy
109eda14cbcSMatt Macy void
uu_list_pool_destroy(uu_list_pool_t * pp)110eda14cbcSMatt Macy uu_list_pool_destroy(uu_list_pool_t *pp)
111eda14cbcSMatt Macy {
112eda14cbcSMatt Macy if (pp->ulp_debug) {
113dbd5678dSMartin Matuska if (pp->ulp_null_list.ul_next != &pp->ulp_null_list ||
114dbd5678dSMartin Matuska pp->ulp_null_list.ul_prev != &pp->ulp_null_list) {
115eda14cbcSMatt Macy uu_panic("uu_list_pool_destroy: Pool \"%.*s\" (%p) has "
116eda14cbcSMatt Macy "outstanding lists, or is corrupt.\n",
117eda14cbcSMatt Macy (int)sizeof (pp->ulp_name), pp->ulp_name,
118eda14cbcSMatt Macy (void *)pp);
119eda14cbcSMatt Macy }
120eda14cbcSMatt Macy }
121eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_lpool_list_lock);
122eda14cbcSMatt Macy pp->ulp_next->ulp_prev = pp->ulp_prev;
123eda14cbcSMatt Macy pp->ulp_prev->ulp_next = pp->ulp_next;
124eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_lpool_list_lock);
125eda14cbcSMatt Macy pp->ulp_prev = NULL;
126eda14cbcSMatt Macy pp->ulp_next = NULL;
127eda14cbcSMatt Macy uu_free(pp);
128eda14cbcSMatt Macy }
129eda14cbcSMatt Macy
130eda14cbcSMatt Macy void
uu_list_node_init(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)131eda14cbcSMatt Macy uu_list_node_init(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
132eda14cbcSMatt Macy {
133eda14cbcSMatt Macy uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
134eda14cbcSMatt Macy
135eda14cbcSMatt Macy if (pp->ulp_debug) {
136eda14cbcSMatt Macy uintptr_t offset = (uintptr_t)np - (uintptr_t)base;
137eda14cbcSMatt Macy if (offset + sizeof (*np) > pp->ulp_objsize) {
138eda14cbcSMatt Macy uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
139eda14cbcSMatt Macy "offset %ld doesn't fit in object (size %ld)\n",
140eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->ulp_name,
141eda14cbcSMatt Macy (long)offset, (long)pp->ulp_objsize);
142eda14cbcSMatt Macy }
143eda14cbcSMatt Macy if (offset != pp->ulp_nodeoffset) {
144eda14cbcSMatt Macy uu_panic("uu_list_node_init(%p, %p, %p (\"%s\")): "
145eda14cbcSMatt Macy "offset %ld doesn't match pool's offset (%ld)\n",
146eda14cbcSMatt Macy base, (void *)np, (void *)pp, pp->ulp_name,
147eda14cbcSMatt Macy (long)offset, (long)pp->ulp_objsize);
148eda14cbcSMatt Macy }
149eda14cbcSMatt Macy }
150eda14cbcSMatt Macy np->uln_next = POOL_TO_MARKER(pp);
151eda14cbcSMatt Macy np->uln_prev = NULL;
152eda14cbcSMatt Macy }
153eda14cbcSMatt Macy
154eda14cbcSMatt Macy void
uu_list_node_fini(void * base,uu_list_node_t * np_arg,uu_list_pool_t * pp)155eda14cbcSMatt Macy uu_list_node_fini(void *base, uu_list_node_t *np_arg, uu_list_pool_t *pp)
156eda14cbcSMatt Macy {
157eda14cbcSMatt Macy uu_list_node_impl_t *np = (uu_list_node_impl_t *)np_arg;
158eda14cbcSMatt Macy
159eda14cbcSMatt Macy if (pp->ulp_debug) {
160eda14cbcSMatt Macy if (np->uln_next == NULL &&
161eda14cbcSMatt Macy np->uln_prev == NULL) {
162eda14cbcSMatt Macy uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
163eda14cbcSMatt Macy "node already finied\n",
164eda14cbcSMatt Macy base, (void *)np_arg, (void *)pp, pp->ulp_name);
165eda14cbcSMatt Macy }
166eda14cbcSMatt Macy if (np->uln_next != POOL_TO_MARKER(pp) ||
167eda14cbcSMatt Macy np->uln_prev != NULL) {
168eda14cbcSMatt Macy uu_panic("uu_list_node_fini(%p, %p, %p (\"%s\")): "
169eda14cbcSMatt Macy "node corrupt or on list\n",
170eda14cbcSMatt Macy base, (void *)np_arg, (void *)pp, pp->ulp_name);
171eda14cbcSMatt Macy }
172eda14cbcSMatt Macy }
173eda14cbcSMatt Macy np->uln_next = NULL;
174eda14cbcSMatt Macy np->uln_prev = NULL;
175eda14cbcSMatt Macy }
176eda14cbcSMatt Macy
177eda14cbcSMatt Macy uu_list_t *
uu_list_create(uu_list_pool_t * pp,void * parent,uint32_t flags)178eda14cbcSMatt Macy uu_list_create(uu_list_pool_t *pp, void *parent, uint32_t flags)
179eda14cbcSMatt Macy {
180eda14cbcSMatt Macy uu_list_t *lp, *next, *prev;
181eda14cbcSMatt Macy
182eda14cbcSMatt Macy if (flags & ~(UU_LIST_DEBUG | UU_LIST_SORTED)) {
183eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG);
184eda14cbcSMatt Macy return (NULL);
185eda14cbcSMatt Macy }
186eda14cbcSMatt Macy
187eda14cbcSMatt Macy if ((flags & UU_LIST_SORTED) && pp->ulp_cmp == NULL) {
188eda14cbcSMatt Macy if (pp->ulp_debug)
189eda14cbcSMatt Macy uu_panic("uu_list_create(%p, ...): requested "
190eda14cbcSMatt Macy "UU_LIST_SORTED, but pool has no comparison func\n",
191eda14cbcSMatt Macy (void *)pp);
192eda14cbcSMatt Macy uu_set_error(UU_ERROR_NOT_SUPPORTED);
193eda14cbcSMatt Macy return (NULL);
194eda14cbcSMatt Macy }
195eda14cbcSMatt Macy
196eda14cbcSMatt Macy lp = uu_zalloc(sizeof (*lp));
197eda14cbcSMatt Macy if (lp == NULL) {
198eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY);
199eda14cbcSMatt Macy return (NULL);
200eda14cbcSMatt Macy }
201eda14cbcSMatt Macy
202eda14cbcSMatt Macy lp->ul_pool = pp;
203dbd5678dSMartin Matuska lp->ul_parent = parent;
204eda14cbcSMatt Macy lp->ul_offset = pp->ulp_nodeoffset;
205eda14cbcSMatt Macy lp->ul_debug = pp->ulp_debug || (flags & UU_LIST_DEBUG);
206eda14cbcSMatt Macy lp->ul_sorted = (flags & UU_LIST_SORTED);
207eda14cbcSMatt Macy lp->ul_numnodes = 0;
208eda14cbcSMatt Macy lp->ul_index = (pp->ulp_last_index = INDEX_NEXT(pp->ulp_last_index));
209eda14cbcSMatt Macy
210eda14cbcSMatt Macy lp->ul_null_node.uln_next = &lp->ul_null_node;
211eda14cbcSMatt Macy lp->ul_null_node.uln_prev = &lp->ul_null_node;
212eda14cbcSMatt Macy
213eda14cbcSMatt Macy lp->ul_null_walk.ulw_next = &lp->ul_null_walk;
214eda14cbcSMatt Macy lp->ul_null_walk.ulw_prev = &lp->ul_null_walk;
215eda14cbcSMatt Macy
216eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->ulp_lock);
217eda14cbcSMatt Macy next = &pp->ulp_null_list;
218dbd5678dSMartin Matuska prev = next->ul_prev;
219dbd5678dSMartin Matuska lp->ul_next = next;
220dbd5678dSMartin Matuska lp->ul_prev = prev;
221dbd5678dSMartin Matuska next->ul_prev = lp;
222dbd5678dSMartin Matuska prev->ul_next = lp;
223eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->ulp_lock);
224eda14cbcSMatt Macy
225eda14cbcSMatt Macy return (lp);
226eda14cbcSMatt Macy }
227eda14cbcSMatt Macy
228eda14cbcSMatt Macy void
uu_list_destroy(uu_list_t * lp)229eda14cbcSMatt Macy uu_list_destroy(uu_list_t *lp)
230eda14cbcSMatt Macy {
231eda14cbcSMatt Macy uu_list_pool_t *pp = lp->ul_pool;
232eda14cbcSMatt Macy
233eda14cbcSMatt Macy if (lp->ul_debug) {
234eda14cbcSMatt Macy if (lp->ul_null_node.uln_next != &lp->ul_null_node ||
235eda14cbcSMatt Macy lp->ul_null_node.uln_prev != &lp->ul_null_node) {
236eda14cbcSMatt Macy uu_panic("uu_list_destroy(%p): list not empty\n",
237eda14cbcSMatt Macy (void *)lp);
238eda14cbcSMatt Macy }
239eda14cbcSMatt Macy if (lp->ul_numnodes != 0) {
240eda14cbcSMatt Macy uu_panic("uu_list_destroy(%p): numnodes is nonzero, "
241eda14cbcSMatt Macy "but list is empty\n", (void *)lp);
242eda14cbcSMatt Macy }
243eda14cbcSMatt Macy if (lp->ul_null_walk.ulw_next != &lp->ul_null_walk ||
244eda14cbcSMatt Macy lp->ul_null_walk.ulw_prev != &lp->ul_null_walk) {
245eda14cbcSMatt Macy uu_panic("uu_list_destroy(%p): outstanding walkers\n",
246eda14cbcSMatt Macy (void *)lp);
247eda14cbcSMatt Macy }
248eda14cbcSMatt Macy }
249eda14cbcSMatt Macy
250eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->ulp_lock);
251dbd5678dSMartin Matuska lp->ul_next->ul_prev = lp->ul_prev;
252dbd5678dSMartin Matuska lp->ul_prev->ul_next = lp->ul_next;
253eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->ulp_lock);
254dbd5678dSMartin Matuska lp->ul_prev = NULL;
255dbd5678dSMartin Matuska lp->ul_next = NULL;
256eda14cbcSMatt Macy lp->ul_pool = NULL;
257eda14cbcSMatt Macy uu_free(lp);
258eda14cbcSMatt Macy }
259eda14cbcSMatt Macy
260eda14cbcSMatt Macy 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)261eda14cbcSMatt Macy list_insert(uu_list_t *lp, uu_list_node_impl_t *np, uu_list_node_impl_t *prev,
262eda14cbcSMatt Macy uu_list_node_impl_t *next)
263eda14cbcSMatt Macy {
264eda14cbcSMatt Macy if (lp->ul_debug) {
265eda14cbcSMatt Macy if (next->uln_prev != prev || prev->uln_next != next)
266eda14cbcSMatt Macy uu_panic("insert(%p): internal error: %p and %p not "
267eda14cbcSMatt Macy "neighbors\n", (void *)lp, (void *)next,
268eda14cbcSMatt Macy (void *)prev);
269eda14cbcSMatt Macy
270eda14cbcSMatt Macy if (np->uln_next != POOL_TO_MARKER(lp->ul_pool) ||
271eda14cbcSMatt Macy np->uln_prev != NULL) {
272eda14cbcSMatt Macy uu_panic("insert(%p): elem %p node %p corrupt, "
273eda14cbcSMatt Macy "not initialized, or already in a list.\n",
274eda14cbcSMatt Macy (void *)lp, NODE_TO_ELEM(lp, np), (void *)np);
275eda14cbcSMatt Macy }
276eda14cbcSMatt Macy /*
277eda14cbcSMatt Macy * invalidate outstanding uu_list_index_ts.
278eda14cbcSMatt Macy */
279eda14cbcSMatt Macy lp->ul_index = INDEX_NEXT(lp->ul_index);
280eda14cbcSMatt Macy }
281eda14cbcSMatt Macy np->uln_next = next;
282eda14cbcSMatt Macy np->uln_prev = prev;
283eda14cbcSMatt Macy next->uln_prev = np;
284eda14cbcSMatt Macy prev->uln_next = np;
285eda14cbcSMatt Macy
286eda14cbcSMatt Macy lp->ul_numnodes++;
287eda14cbcSMatt Macy }
288eda14cbcSMatt Macy
289eda14cbcSMatt Macy void
uu_list_insert(uu_list_t * lp,void * elem,uu_list_index_t idx)290eda14cbcSMatt Macy uu_list_insert(uu_list_t *lp, void *elem, uu_list_index_t idx)
291eda14cbcSMatt Macy {
292eda14cbcSMatt Macy uu_list_node_impl_t *np;
293eda14cbcSMatt Macy
294eda14cbcSMatt Macy np = INDEX_TO_NODE(idx);
295eda14cbcSMatt Macy if (np == NULL)
296eda14cbcSMatt Macy np = &lp->ul_null_node;
297eda14cbcSMatt Macy
298eda14cbcSMatt Macy if (lp->ul_debug) {
299eda14cbcSMatt Macy if (!INDEX_VALID(lp, idx))
300eda14cbcSMatt Macy uu_panic("uu_list_insert(%p, %p, %p): %s\n",
301eda14cbcSMatt Macy (void *)lp, elem, (void *)idx,
302eda14cbcSMatt Macy INDEX_CHECK(idx)? "outdated index" :
303eda14cbcSMatt Macy "invalid index");
304eda14cbcSMatt Macy if (np->uln_prev == NULL)
305eda14cbcSMatt Macy uu_panic("uu_list_insert(%p, %p, %p): out-of-date "
306eda14cbcSMatt Macy "index\n", (void *)lp, elem, (void *)idx);
307eda14cbcSMatt Macy }
308eda14cbcSMatt Macy
309eda14cbcSMatt Macy list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
310eda14cbcSMatt Macy }
311eda14cbcSMatt Macy
312eda14cbcSMatt Macy void *
uu_list_find(uu_list_t * lp,void * elem,void * private,uu_list_index_t * out)313eda14cbcSMatt Macy uu_list_find(uu_list_t *lp, void *elem, void *private, uu_list_index_t *out)
314eda14cbcSMatt Macy {
315eda14cbcSMatt Macy int sorted = lp->ul_sorted;
316eda14cbcSMatt Macy uu_compare_fn_t *func = lp->ul_pool->ulp_cmp;
317eda14cbcSMatt Macy uu_list_node_impl_t *np;
318eda14cbcSMatt Macy
319eda14cbcSMatt Macy if (func == NULL) {
320eda14cbcSMatt Macy if (out != NULL)
321eda14cbcSMatt Macy *out = 0;
322eda14cbcSMatt Macy uu_set_error(UU_ERROR_NOT_SUPPORTED);
323eda14cbcSMatt Macy return (NULL);
324eda14cbcSMatt Macy }
325eda14cbcSMatt Macy for (np = lp->ul_null_node.uln_next; np != &lp->ul_null_node;
326eda14cbcSMatt Macy np = np->uln_next) {
327eda14cbcSMatt Macy void *ep = NODE_TO_ELEM(lp, np);
328eda14cbcSMatt Macy int cmp = func(ep, elem, private);
329eda14cbcSMatt Macy if (cmp == 0) {
330eda14cbcSMatt Macy if (out != NULL)
331eda14cbcSMatt Macy *out = NODE_TO_INDEX(lp, np);
332eda14cbcSMatt Macy return (ep);
333eda14cbcSMatt Macy }
334eda14cbcSMatt Macy if (sorted && cmp > 0) {
335eda14cbcSMatt Macy if (out != NULL)
336eda14cbcSMatt Macy *out = NODE_TO_INDEX(lp, np);
337eda14cbcSMatt Macy return (NULL);
338eda14cbcSMatt Macy }
339eda14cbcSMatt Macy }
340eda14cbcSMatt Macy if (out != NULL)
341eda14cbcSMatt Macy *out = NODE_TO_INDEX(lp, 0);
342eda14cbcSMatt Macy return (NULL);
343eda14cbcSMatt Macy }
344eda14cbcSMatt Macy
345eda14cbcSMatt Macy void *
uu_list_nearest_next(uu_list_t * lp,uu_list_index_t idx)346eda14cbcSMatt Macy uu_list_nearest_next(uu_list_t *lp, uu_list_index_t idx)
347eda14cbcSMatt Macy {
348eda14cbcSMatt Macy uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
349eda14cbcSMatt Macy
350eda14cbcSMatt Macy if (np == NULL)
351eda14cbcSMatt Macy np = &lp->ul_null_node;
352eda14cbcSMatt Macy
353eda14cbcSMatt Macy if (lp->ul_debug) {
354eda14cbcSMatt Macy if (!INDEX_VALID(lp, idx))
355eda14cbcSMatt Macy uu_panic("uu_list_nearest_next(%p, %p): %s\n",
356eda14cbcSMatt Macy (void *)lp, (void *)idx,
357eda14cbcSMatt Macy INDEX_CHECK(idx)? "outdated index" :
358eda14cbcSMatt Macy "invalid index");
359eda14cbcSMatt Macy if (np->uln_prev == NULL)
360eda14cbcSMatt Macy uu_panic("uu_list_nearest_next(%p, %p): out-of-date "
361eda14cbcSMatt Macy "index\n", (void *)lp, (void *)idx);
362eda14cbcSMatt Macy }
363eda14cbcSMatt Macy
364eda14cbcSMatt Macy if (np == &lp->ul_null_node)
365eda14cbcSMatt Macy return (NULL);
366eda14cbcSMatt Macy else
367eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, np));
368eda14cbcSMatt Macy }
369eda14cbcSMatt Macy
370eda14cbcSMatt Macy void *
uu_list_nearest_prev(uu_list_t * lp,uu_list_index_t idx)371eda14cbcSMatt Macy uu_list_nearest_prev(uu_list_t *lp, uu_list_index_t idx)
372eda14cbcSMatt Macy {
373eda14cbcSMatt Macy uu_list_node_impl_t *np = INDEX_TO_NODE(idx);
374eda14cbcSMatt Macy
375eda14cbcSMatt Macy if (np == NULL)
376eda14cbcSMatt Macy np = &lp->ul_null_node;
377eda14cbcSMatt Macy
378eda14cbcSMatt Macy if (lp->ul_debug) {
379eda14cbcSMatt Macy if (!INDEX_VALID(lp, idx))
380eda14cbcSMatt Macy uu_panic("uu_list_nearest_prev(%p, %p): %s\n",
381eda14cbcSMatt Macy (void *)lp, (void *)idx, INDEX_CHECK(idx)?
382eda14cbcSMatt Macy "outdated index" : "invalid index");
383eda14cbcSMatt Macy if (np->uln_prev == NULL)
384eda14cbcSMatt Macy uu_panic("uu_list_nearest_prev(%p, %p): out-of-date "
385eda14cbcSMatt Macy "index\n", (void *)lp, (void *)idx);
386eda14cbcSMatt Macy }
387eda14cbcSMatt Macy
388eda14cbcSMatt Macy if ((np = np->uln_prev) == &lp->ul_null_node)
389eda14cbcSMatt Macy return (NULL);
390eda14cbcSMatt Macy else
391eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, np));
392eda14cbcSMatt Macy }
393eda14cbcSMatt Macy
394eda14cbcSMatt Macy static void
list_walk_init(uu_list_walk_t * wp,uu_list_t * lp,uint32_t flags)395eda14cbcSMatt Macy list_walk_init(uu_list_walk_t *wp, uu_list_t *lp, uint32_t flags)
396eda14cbcSMatt Macy {
397eda14cbcSMatt Macy uu_list_walk_t *next, *prev;
398eda14cbcSMatt Macy
399eda14cbcSMatt Macy int robust = (flags & UU_WALK_ROBUST);
400eda14cbcSMatt Macy int direction = (flags & UU_WALK_REVERSE)? -1 : 1;
401eda14cbcSMatt Macy
402eda14cbcSMatt Macy (void) memset(wp, 0, sizeof (*wp));
403eda14cbcSMatt Macy wp->ulw_list = lp;
404eda14cbcSMatt Macy wp->ulw_robust = robust;
405eda14cbcSMatt Macy wp->ulw_dir = direction;
406eda14cbcSMatt Macy if (direction > 0)
407eda14cbcSMatt Macy wp->ulw_next_result = lp->ul_null_node.uln_next;
408eda14cbcSMatt Macy else
409eda14cbcSMatt Macy wp->ulw_next_result = lp->ul_null_node.uln_prev;
410eda14cbcSMatt Macy
411eda14cbcSMatt Macy if (lp->ul_debug || robust) {
412eda14cbcSMatt Macy /*
413eda14cbcSMatt Macy * Add this walker to the list's list of walkers so
414eda14cbcSMatt Macy * uu_list_remove() can advance us if somebody tries to
415eda14cbcSMatt Macy * remove ulw_next_result.
416eda14cbcSMatt Macy */
417eda14cbcSMatt Macy wp->ulw_next = next = &lp->ul_null_walk;
418eda14cbcSMatt Macy wp->ulw_prev = prev = next->ulw_prev;
419eda14cbcSMatt Macy next->ulw_prev = wp;
420eda14cbcSMatt Macy prev->ulw_next = wp;
421eda14cbcSMatt Macy }
422eda14cbcSMatt Macy }
423eda14cbcSMatt Macy
424eda14cbcSMatt Macy static uu_list_node_impl_t *
list_walk_advance(uu_list_walk_t * wp,uu_list_t * lp)425eda14cbcSMatt Macy list_walk_advance(uu_list_walk_t *wp, uu_list_t *lp)
426eda14cbcSMatt Macy {
427eda14cbcSMatt Macy uu_list_node_impl_t *np = wp->ulw_next_result;
428eda14cbcSMatt Macy uu_list_node_impl_t *next;
429eda14cbcSMatt Macy
430eda14cbcSMatt Macy if (np == &lp->ul_null_node)
431eda14cbcSMatt Macy return (NULL);
432eda14cbcSMatt Macy
433eda14cbcSMatt Macy next = (wp->ulw_dir > 0)? np->uln_next : np->uln_prev;
434eda14cbcSMatt Macy
435eda14cbcSMatt Macy wp->ulw_next_result = next;
436eda14cbcSMatt Macy return (np);
437eda14cbcSMatt Macy }
438eda14cbcSMatt Macy
439eda14cbcSMatt Macy static void
list_walk_fini(uu_list_walk_t * wp)440eda14cbcSMatt Macy list_walk_fini(uu_list_walk_t *wp)
441eda14cbcSMatt Macy {
442eda14cbcSMatt Macy /* GLXXX debugging? */
443eda14cbcSMatt Macy if (wp->ulw_next != NULL) {
444eda14cbcSMatt Macy wp->ulw_next->ulw_prev = wp->ulw_prev;
445eda14cbcSMatt Macy wp->ulw_prev->ulw_next = wp->ulw_next;
446eda14cbcSMatt Macy wp->ulw_next = NULL;
447eda14cbcSMatt Macy wp->ulw_prev = NULL;
448eda14cbcSMatt Macy }
449eda14cbcSMatt Macy wp->ulw_list = NULL;
450eda14cbcSMatt Macy wp->ulw_next_result = NULL;
451eda14cbcSMatt Macy }
452eda14cbcSMatt Macy
453eda14cbcSMatt Macy uu_list_walk_t *
uu_list_walk_start(uu_list_t * lp,uint32_t flags)454eda14cbcSMatt Macy uu_list_walk_start(uu_list_t *lp, uint32_t flags)
455eda14cbcSMatt Macy {
456eda14cbcSMatt Macy uu_list_walk_t *wp;
457eda14cbcSMatt Macy
458eda14cbcSMatt Macy if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
459eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG);
460eda14cbcSMatt Macy return (NULL);
461eda14cbcSMatt Macy }
462eda14cbcSMatt Macy
463eda14cbcSMatt Macy wp = uu_zalloc(sizeof (*wp));
464eda14cbcSMatt Macy if (wp == NULL) {
465eda14cbcSMatt Macy uu_set_error(UU_ERROR_NO_MEMORY);
466eda14cbcSMatt Macy return (NULL);
467eda14cbcSMatt Macy }
468eda14cbcSMatt Macy
469eda14cbcSMatt Macy list_walk_init(wp, lp, flags);
470eda14cbcSMatt Macy return (wp);
471eda14cbcSMatt Macy }
472eda14cbcSMatt Macy
473eda14cbcSMatt Macy void *
uu_list_walk_next(uu_list_walk_t * wp)474eda14cbcSMatt Macy uu_list_walk_next(uu_list_walk_t *wp)
475eda14cbcSMatt Macy {
476eda14cbcSMatt Macy uu_list_t *lp = wp->ulw_list;
477eda14cbcSMatt Macy uu_list_node_impl_t *np = list_walk_advance(wp, lp);
478eda14cbcSMatt Macy
479eda14cbcSMatt Macy if (np == NULL)
480eda14cbcSMatt Macy return (NULL);
481eda14cbcSMatt Macy
482eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, np));
483eda14cbcSMatt Macy }
484eda14cbcSMatt Macy
485eda14cbcSMatt Macy void
uu_list_walk_end(uu_list_walk_t * wp)486eda14cbcSMatt Macy uu_list_walk_end(uu_list_walk_t *wp)
487eda14cbcSMatt Macy {
488eda14cbcSMatt Macy list_walk_fini(wp);
489eda14cbcSMatt Macy uu_free(wp);
490eda14cbcSMatt Macy }
491eda14cbcSMatt Macy
492eda14cbcSMatt Macy int
uu_list_walk(uu_list_t * lp,uu_walk_fn_t * func,void * private,uint32_t flags)493eda14cbcSMatt Macy uu_list_walk(uu_list_t *lp, uu_walk_fn_t *func, void *private, uint32_t flags)
494eda14cbcSMatt Macy {
495eda14cbcSMatt Macy uu_list_node_impl_t *np;
496eda14cbcSMatt Macy
497eda14cbcSMatt Macy int status = UU_WALK_NEXT;
498eda14cbcSMatt Macy
499eda14cbcSMatt Macy int robust = (flags & UU_WALK_ROBUST);
500eda14cbcSMatt Macy int reverse = (flags & UU_WALK_REVERSE);
501eda14cbcSMatt Macy
502eda14cbcSMatt Macy if (flags & ~(UU_WALK_ROBUST | UU_WALK_REVERSE)) {
503eda14cbcSMatt Macy uu_set_error(UU_ERROR_UNKNOWN_FLAG);
504eda14cbcSMatt Macy return (-1);
505eda14cbcSMatt Macy }
506eda14cbcSMatt Macy
507eda14cbcSMatt Macy if (lp->ul_debug || robust) {
508*b985c9caSMartin Matuska uu_list_walk_t *my_walk;
509eda14cbcSMatt Macy void *e;
510eda14cbcSMatt Macy
511*b985c9caSMartin Matuska my_walk = uu_zalloc(sizeof (*my_walk));
512*b985c9caSMartin Matuska if (my_walk == NULL)
513*b985c9caSMartin Matuska return (-1);
514*b985c9caSMartin Matuska
515*b985c9caSMartin Matuska list_walk_init(my_walk, lp, flags);
516eda14cbcSMatt Macy while (status == UU_WALK_NEXT &&
517*b985c9caSMartin Matuska (e = uu_list_walk_next(my_walk)) != NULL)
518eda14cbcSMatt Macy status = (*func)(e, private);
519*b985c9caSMartin Matuska list_walk_fini(my_walk);
520*b985c9caSMartin Matuska
521*b985c9caSMartin Matuska uu_free(my_walk);
522eda14cbcSMatt Macy } else {
523eda14cbcSMatt Macy if (!reverse) {
524eda14cbcSMatt Macy for (np = lp->ul_null_node.uln_next;
525eda14cbcSMatt Macy status == UU_WALK_NEXT && np != &lp->ul_null_node;
526eda14cbcSMatt Macy np = np->uln_next) {
527eda14cbcSMatt Macy status = (*func)(NODE_TO_ELEM(lp, np), private);
528eda14cbcSMatt Macy }
529eda14cbcSMatt Macy } else {
530eda14cbcSMatt Macy for (np = lp->ul_null_node.uln_prev;
531eda14cbcSMatt Macy status == UU_WALK_NEXT && np != &lp->ul_null_node;
532eda14cbcSMatt Macy np = np->uln_prev) {
533eda14cbcSMatt Macy status = (*func)(NODE_TO_ELEM(lp, np), private);
534eda14cbcSMatt Macy }
535eda14cbcSMatt Macy }
536eda14cbcSMatt Macy }
537eda14cbcSMatt Macy if (status >= 0)
538eda14cbcSMatt Macy return (0);
539eda14cbcSMatt Macy uu_set_error(UU_ERROR_CALLBACK_FAILED);
540eda14cbcSMatt Macy return (-1);
541eda14cbcSMatt Macy }
542eda14cbcSMatt Macy
543eda14cbcSMatt Macy void
uu_list_remove(uu_list_t * lp,void * elem)544eda14cbcSMatt Macy uu_list_remove(uu_list_t *lp, void *elem)
545eda14cbcSMatt Macy {
546eda14cbcSMatt Macy uu_list_node_impl_t *np = ELEM_TO_NODE(lp, elem);
547eda14cbcSMatt Macy uu_list_walk_t *wp;
548eda14cbcSMatt Macy
549eda14cbcSMatt Macy if (lp->ul_debug) {
550eda14cbcSMatt Macy if (np->uln_prev == NULL)
551eda14cbcSMatt Macy uu_panic("uu_list_remove(%p, %p): elem not on list\n",
552eda14cbcSMatt Macy (void *)lp, elem);
553eda14cbcSMatt Macy /*
554eda14cbcSMatt Macy * invalidate outstanding uu_list_index_ts.
555eda14cbcSMatt Macy */
556eda14cbcSMatt Macy lp->ul_index = INDEX_NEXT(lp->ul_index);
557eda14cbcSMatt Macy }
558eda14cbcSMatt Macy
559eda14cbcSMatt Macy /*
560eda14cbcSMatt Macy * robust walkers must be advanced. In debug mode, non-robust
561eda14cbcSMatt Macy * walkers are also on the list. If there are any, it's an error.
562eda14cbcSMatt Macy */
563eda14cbcSMatt Macy for (wp = lp->ul_null_walk.ulw_next; wp != &lp->ul_null_walk;
564eda14cbcSMatt Macy wp = wp->ulw_next) {
565eda14cbcSMatt Macy if (wp->ulw_robust) {
566eda14cbcSMatt Macy if (np == wp->ulw_next_result)
567eda14cbcSMatt Macy (void) list_walk_advance(wp, lp);
568eda14cbcSMatt Macy } else if (wp->ulw_next_result != NULL) {
569eda14cbcSMatt Macy uu_panic("uu_list_remove(%p, %p): active non-robust "
570eda14cbcSMatt Macy "walker\n", (void *)lp, elem);
571eda14cbcSMatt Macy }
572eda14cbcSMatt Macy }
573eda14cbcSMatt Macy
574eda14cbcSMatt Macy np->uln_next->uln_prev = np->uln_prev;
575eda14cbcSMatt Macy np->uln_prev->uln_next = np->uln_next;
576eda14cbcSMatt Macy
577eda14cbcSMatt Macy lp->ul_numnodes--;
578eda14cbcSMatt Macy
579eda14cbcSMatt Macy np->uln_next = POOL_TO_MARKER(lp->ul_pool);
580eda14cbcSMatt Macy np->uln_prev = NULL;
581eda14cbcSMatt Macy }
582eda14cbcSMatt Macy
583eda14cbcSMatt Macy void *
uu_list_teardown(uu_list_t * lp,void ** cookie)584eda14cbcSMatt Macy uu_list_teardown(uu_list_t *lp, void **cookie)
585eda14cbcSMatt Macy {
586eda14cbcSMatt Macy void *ep;
587eda14cbcSMatt Macy
588eda14cbcSMatt Macy /*
589eda14cbcSMatt Macy * XXX: disable list modification until list is empty
590eda14cbcSMatt Macy */
591eda14cbcSMatt Macy if (lp->ul_debug && *cookie != NULL)
592eda14cbcSMatt Macy uu_panic("uu_list_teardown(%p, %p): unexpected cookie\n",
593eda14cbcSMatt Macy (void *)lp, (void *)cookie);
594eda14cbcSMatt Macy
595eda14cbcSMatt Macy ep = uu_list_first(lp);
596eda14cbcSMatt Macy if (ep)
597eda14cbcSMatt Macy uu_list_remove(lp, ep);
598eda14cbcSMatt Macy return (ep);
599eda14cbcSMatt Macy }
600eda14cbcSMatt Macy
601eda14cbcSMatt Macy int
uu_list_insert_before(uu_list_t * lp,void * target,void * elem)602eda14cbcSMatt Macy uu_list_insert_before(uu_list_t *lp, void *target, void *elem)
603eda14cbcSMatt Macy {
604eda14cbcSMatt Macy uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
605eda14cbcSMatt Macy
606eda14cbcSMatt Macy if (target == NULL)
607eda14cbcSMatt Macy np = &lp->ul_null_node;
608eda14cbcSMatt Macy
609eda14cbcSMatt Macy if (lp->ul_debug) {
610eda14cbcSMatt Macy if (np->uln_prev == NULL)
611eda14cbcSMatt Macy uu_panic("uu_list_insert_before(%p, %p, %p): %p is "
612eda14cbcSMatt Macy "not currently on a list\n",
613eda14cbcSMatt Macy (void *)lp, target, elem, target);
614eda14cbcSMatt Macy }
615eda14cbcSMatt Macy if (lp->ul_sorted) {
616eda14cbcSMatt Macy if (lp->ul_debug)
617eda14cbcSMatt Macy uu_panic("uu_list_insert_before(%p, ...): list is "
618eda14cbcSMatt Macy "UU_LIST_SORTED\n", (void *)lp);
619eda14cbcSMatt Macy uu_set_error(UU_ERROR_NOT_SUPPORTED);
620eda14cbcSMatt Macy return (-1);
621eda14cbcSMatt Macy }
622eda14cbcSMatt Macy
623eda14cbcSMatt Macy list_insert(lp, ELEM_TO_NODE(lp, elem), np->uln_prev, np);
624eda14cbcSMatt Macy return (0);
625eda14cbcSMatt Macy }
626eda14cbcSMatt Macy
627eda14cbcSMatt Macy int
uu_list_insert_after(uu_list_t * lp,void * target,void * elem)628eda14cbcSMatt Macy uu_list_insert_after(uu_list_t *lp, void *target, void *elem)
629eda14cbcSMatt Macy {
630eda14cbcSMatt Macy uu_list_node_impl_t *np = ELEM_TO_NODE(lp, target);
631eda14cbcSMatt Macy
632eda14cbcSMatt Macy if (target == NULL)
633eda14cbcSMatt Macy np = &lp->ul_null_node;
634eda14cbcSMatt Macy
635eda14cbcSMatt Macy if (lp->ul_debug) {
636eda14cbcSMatt Macy if (np->uln_prev == NULL)
637eda14cbcSMatt Macy uu_panic("uu_list_insert_after(%p, %p, %p): %p is "
638eda14cbcSMatt Macy "not currently on a list\n",
639eda14cbcSMatt Macy (void *)lp, target, elem, target);
640eda14cbcSMatt Macy }
641eda14cbcSMatt Macy if (lp->ul_sorted) {
642eda14cbcSMatt Macy if (lp->ul_debug)
643eda14cbcSMatt Macy uu_panic("uu_list_insert_after(%p, ...): list is "
644eda14cbcSMatt Macy "UU_LIST_SORTED\n", (void *)lp);
645eda14cbcSMatt Macy uu_set_error(UU_ERROR_NOT_SUPPORTED);
646eda14cbcSMatt Macy return (-1);
647eda14cbcSMatt Macy }
648eda14cbcSMatt Macy
649eda14cbcSMatt Macy list_insert(lp, ELEM_TO_NODE(lp, elem), np, np->uln_next);
650eda14cbcSMatt Macy return (0);
651eda14cbcSMatt Macy }
652eda14cbcSMatt Macy
653eda14cbcSMatt Macy size_t
uu_list_numnodes(uu_list_t * lp)654eda14cbcSMatt Macy uu_list_numnodes(uu_list_t *lp)
655eda14cbcSMatt Macy {
656eda14cbcSMatt Macy return (lp->ul_numnodes);
657eda14cbcSMatt Macy }
658eda14cbcSMatt Macy
659eda14cbcSMatt Macy void *
uu_list_first(uu_list_t * lp)660eda14cbcSMatt Macy uu_list_first(uu_list_t *lp)
661eda14cbcSMatt Macy {
662eda14cbcSMatt Macy uu_list_node_impl_t *n = lp->ul_null_node.uln_next;
663eda14cbcSMatt Macy if (n == &lp->ul_null_node)
664eda14cbcSMatt Macy return (NULL);
665eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, n));
666eda14cbcSMatt Macy }
667eda14cbcSMatt Macy
668eda14cbcSMatt Macy void *
uu_list_last(uu_list_t * lp)669eda14cbcSMatt Macy uu_list_last(uu_list_t *lp)
670eda14cbcSMatt Macy {
671eda14cbcSMatt Macy uu_list_node_impl_t *n = lp->ul_null_node.uln_prev;
672eda14cbcSMatt Macy if (n == &lp->ul_null_node)
673eda14cbcSMatt Macy return (NULL);
674eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, n));
675eda14cbcSMatt Macy }
676eda14cbcSMatt Macy
677eda14cbcSMatt Macy void *
uu_list_next(uu_list_t * lp,void * elem)678eda14cbcSMatt Macy uu_list_next(uu_list_t *lp, void *elem)
679eda14cbcSMatt Macy {
680eda14cbcSMatt Macy uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
681eda14cbcSMatt Macy
682eda14cbcSMatt Macy n = n->uln_next;
683eda14cbcSMatt Macy if (n == &lp->ul_null_node)
684eda14cbcSMatt Macy return (NULL);
685eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, n));
686eda14cbcSMatt Macy }
687eda14cbcSMatt Macy
688eda14cbcSMatt Macy void *
uu_list_prev(uu_list_t * lp,void * elem)689eda14cbcSMatt Macy uu_list_prev(uu_list_t *lp, void *elem)
690eda14cbcSMatt Macy {
691eda14cbcSMatt Macy uu_list_node_impl_t *n = ELEM_TO_NODE(lp, elem);
692eda14cbcSMatt Macy
693eda14cbcSMatt Macy n = n->uln_prev;
694eda14cbcSMatt Macy if (n == &lp->ul_null_node)
695eda14cbcSMatt Macy return (NULL);
696eda14cbcSMatt Macy return (NODE_TO_ELEM(lp, n));
697eda14cbcSMatt Macy }
698eda14cbcSMatt Macy
699eda14cbcSMatt Macy /*
700eda14cbcSMatt Macy * called from uu_lockup() and uu_release(), as part of our fork1()-safety.
701eda14cbcSMatt Macy */
702eda14cbcSMatt Macy void
uu_list_lockup(void)703eda14cbcSMatt Macy uu_list_lockup(void)
704eda14cbcSMatt Macy {
705eda14cbcSMatt Macy uu_list_pool_t *pp;
706eda14cbcSMatt Macy
707eda14cbcSMatt Macy (void) pthread_mutex_lock(&uu_lpool_list_lock);
708eda14cbcSMatt Macy for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
709eda14cbcSMatt Macy pp = pp->ulp_next)
710eda14cbcSMatt Macy (void) pthread_mutex_lock(&pp->ulp_lock);
711eda14cbcSMatt Macy }
712eda14cbcSMatt Macy
713eda14cbcSMatt Macy void
uu_list_release(void)714eda14cbcSMatt Macy uu_list_release(void)
715eda14cbcSMatt Macy {
716eda14cbcSMatt Macy uu_list_pool_t *pp;
717eda14cbcSMatt Macy
718eda14cbcSMatt Macy for (pp = uu_null_lpool.ulp_next; pp != &uu_null_lpool;
719eda14cbcSMatt Macy pp = pp->ulp_next)
720eda14cbcSMatt Macy (void) pthread_mutex_unlock(&pp->ulp_lock);
721eda14cbcSMatt Macy (void) pthread_mutex_unlock(&uu_lpool_list_lock);
722eda14cbcSMatt Macy }
723