1c18a5ab7SFrançois Tigeot /*-
2c18a5ab7SFrançois Tigeot * Copyright (c) 2004 Poul-Henning Kamp
3c18a5ab7SFrançois Tigeot * All rights reserved.
4c18a5ab7SFrançois Tigeot *
5c18a5ab7SFrançois Tigeot * Redistribution and use in source and binary forms, with or without
6c18a5ab7SFrançois Tigeot * modification, are permitted provided that the following conditions
7c18a5ab7SFrançois Tigeot * are met:
8c18a5ab7SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
9c18a5ab7SFrançois Tigeot * notice, this list of conditions and the following disclaimer.
10c18a5ab7SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
11c18a5ab7SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
12c18a5ab7SFrançois Tigeot * documentation and/or other materials provided with the distribution.
13c18a5ab7SFrançois Tigeot *
14c18a5ab7SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c18a5ab7SFrançois Tigeot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c18a5ab7SFrançois Tigeot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c18a5ab7SFrançois Tigeot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c18a5ab7SFrançois Tigeot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c18a5ab7SFrançois Tigeot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c18a5ab7SFrançois Tigeot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c18a5ab7SFrançois Tigeot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c18a5ab7SFrançois Tigeot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c18a5ab7SFrançois Tigeot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c18a5ab7SFrançois Tigeot * SUCH DAMAGE.
25c18a5ab7SFrançois Tigeot *
26c18a5ab7SFrançois Tigeot * $FreeBSD: src/sys/kern/subr_unit.c,v 1.7 2005/03/14 06:51:29 phk Exp $
27c18a5ab7SFrançois Tigeot *
28c18a5ab7SFrançois Tigeot *
29c18a5ab7SFrançois Tigeot * Unit number allocation functions.
30c18a5ab7SFrançois Tigeot *
31c18a5ab7SFrançois Tigeot * These functions implement a mixed run-length/bitmap management of unit
32c18a5ab7SFrançois Tigeot * number spaces in a very memory efficient manner.
33c18a5ab7SFrançois Tigeot *
34c18a5ab7SFrançois Tigeot * Allocation policy is always lowest free number first.
35c18a5ab7SFrançois Tigeot *
36c18a5ab7SFrançois Tigeot * A return value of -1 signals that no more unit numbers are available.
37c18a5ab7SFrançois Tigeot *
38c18a5ab7SFrançois Tigeot * There is no cost associated with the range of unitnumbers, so unless
39c18a5ab7SFrançois Tigeot * the resource really is finite, specify INT_MAX to new_unrhdr() and
40c18a5ab7SFrançois Tigeot * forget about checking the return value.
41c18a5ab7SFrançois Tigeot *
42c18a5ab7SFrançois Tigeot * If a mutex is not provided when the unit number space is created, a
43c18a5ab7SFrançois Tigeot * default global mutex is used. The advantage to passing a mutex in, is
44c18a5ab7SFrançois Tigeot * that the the alloc_unrl() function can be called with the mutex already
45c18a5ab7SFrançois Tigeot * held (it will not be released by alloc_unrl()).
46c18a5ab7SFrançois Tigeot *
47c18a5ab7SFrançois Tigeot * The allocation function alloc_unr{l}() never sleeps (but it may block on
48c18a5ab7SFrançois Tigeot * the mutex of course).
49c18a5ab7SFrançois Tigeot *
50c18a5ab7SFrançois Tigeot * Freeing a unit number may require allocating memory, and can therefore
51c18a5ab7SFrançois Tigeot * sleep so the free_unr() function does not come in a pre-locked variant.
52c18a5ab7SFrançois Tigeot *
53c18a5ab7SFrançois Tigeot * A userland test program is included.
54c18a5ab7SFrançois Tigeot *
55c18a5ab7SFrançois Tigeot * Memory usage is a very complex function of the the exact allocation
56c18a5ab7SFrançois Tigeot * pattern, but always very compact:
57c18a5ab7SFrançois Tigeot * * For the very typical case where a single unbroken run of unit
58*0a80a445Szrj * numbers are allocated 44 bytes are used on x86.
59c18a5ab7SFrançois Tigeot * * For a unit number space of 1000 units and the random pattern
60c18a5ab7SFrançois Tigeot * in the usermode test program included, the worst case usage
61*0a80a445Szrj * was 252 bytes on x86 for 500 allocated and 500 free units.
62c18a5ab7SFrançois Tigeot * * For a unit number space of 10000 units and the random pattern
63c18a5ab7SFrançois Tigeot * in the usermode test program included, the worst case usage
64*0a80a445Szrj * was 798 bytes on x86 for 5000 allocated and 5000 free units.
65c18a5ab7SFrançois Tigeot * * The worst case is where every other unit number is allocated and
66c18a5ab7SFrançois Tigeot * the the rest are free. In that case 44 + N/4 bytes are used where
67c18a5ab7SFrançois Tigeot * N is the number of the highest unit allocated.
68c18a5ab7SFrançois Tigeot */
69c18a5ab7SFrançois Tigeot
70c18a5ab7SFrançois Tigeot #include <sys/types.h>
71c18a5ab7SFrançois Tigeot #include <sys/queue.h>
7284bfc1a1SSascha Wildner #include <sys/bitstring.h>
73c18a5ab7SFrançois Tigeot
74c18a5ab7SFrançois Tigeot #ifdef _KERNEL
75c18a5ab7SFrançois Tigeot
76c18a5ab7SFrançois Tigeot #include <sys/param.h>
77c18a5ab7SFrançois Tigeot #include <sys/malloc.h>
78c18a5ab7SFrançois Tigeot #include <sys/kernel.h>
79c18a5ab7SFrançois Tigeot #include <sys/systm.h>
80c18a5ab7SFrançois Tigeot #include <sys/limits.h>
81c18a5ab7SFrançois Tigeot #include <sys/lock.h>
82c18a5ab7SFrançois Tigeot #include <sys/proc.h>
83c18a5ab7SFrançois Tigeot
84c18a5ab7SFrançois Tigeot /*
85c18a5ab7SFrançois Tigeot * In theory it would be smarter to allocate the individual blocks
86c18a5ab7SFrançois Tigeot * with the zone allocator, but at this time the expectation is that
87c18a5ab7SFrançois Tigeot * there will typically not even be enough allocations to fill a single
88c18a5ab7SFrançois Tigeot * page, so we stick with malloc for now.
89c18a5ab7SFrançois Tigeot */
90c18a5ab7SFrançois Tigeot static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation");
91c18a5ab7SFrançois Tigeot
92c18a5ab7SFrançois Tigeot #define Malloc(foo) kmalloc(foo, M_UNIT, M_WAITOK | M_ZERO)
93c18a5ab7SFrançois Tigeot #define Free(foo) kfree(foo, M_UNIT)
94c18a5ab7SFrançois Tigeot
95c18a5ab7SFrançois Tigeot static struct lock unit_lock;
96c18a5ab7SFrançois Tigeot
97c18a5ab7SFrançois Tigeot LOCK_SYSINIT(unit, &unit_lock, "unit# allocation", LK_CANRECURSE);
98c18a5ab7SFrançois Tigeot
99c18a5ab7SFrançois Tigeot #else /* ...USERLAND */
100c18a5ab7SFrançois Tigeot
101c18a5ab7SFrançois Tigeot /* No unit allocation on DragonFly's userland */
102c18a5ab7SFrançois Tigeot
103c18a5ab7SFrançois Tigeot #endif /* USERLAND */
104c18a5ab7SFrançois Tigeot
105c18a5ab7SFrançois Tigeot /*
106c18a5ab7SFrançois Tigeot * This is our basic building block.
107c18a5ab7SFrançois Tigeot *
108c18a5ab7SFrançois Tigeot * It can be used in three different ways depending on the value of the ptr
109c18a5ab7SFrançois Tigeot * element:
110c18a5ab7SFrançois Tigeot * If ptr is NULL, it represents a run of free items.
111c18a5ab7SFrançois Tigeot * If ptr points to the unrhdr it represents a run of allocated items.
112c18a5ab7SFrançois Tigeot * Otherwise it points to an bitstring of allocated items.
113c18a5ab7SFrançois Tigeot *
114c18a5ab7SFrançois Tigeot * For runs the len field is the length of the run.
115c18a5ab7SFrançois Tigeot * For bitmaps the len field represents the number of allocated items.
116c18a5ab7SFrançois Tigeot *
117c18a5ab7SFrançois Tigeot * The bitmap is the same size as struct unr to optimize memory management.
118c18a5ab7SFrançois Tigeot */
119c18a5ab7SFrançois Tigeot struct unr {
120c18a5ab7SFrançois Tigeot TAILQ_ENTRY(unr) list;
121c18a5ab7SFrançois Tigeot u_int len;
122c18a5ab7SFrançois Tigeot void *ptr;
123c18a5ab7SFrançois Tigeot };
124c18a5ab7SFrançois Tigeot
125c18a5ab7SFrançois Tigeot struct unrb {
126c18a5ab7SFrançois Tigeot u_char busy;
127c18a5ab7SFrançois Tigeot bitstr_t map[sizeof(struct unr) - 1];
128c18a5ab7SFrançois Tigeot };
129c18a5ab7SFrançois Tigeot
130c18a5ab7SFrançois Tigeot CTASSERT(sizeof(struct unr) == sizeof(struct unrb));
131c18a5ab7SFrançois Tigeot
132c18a5ab7SFrançois Tigeot /* Number of bits in the bitmap */
133c18a5ab7SFrançois Tigeot #define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8)
134c18a5ab7SFrançois Tigeot
135c18a5ab7SFrançois Tigeot /* Header element for a unr number space. */
136c18a5ab7SFrançois Tigeot
137c18a5ab7SFrançois Tigeot struct unrhdr {
138c18a5ab7SFrançois Tigeot TAILQ_HEAD(unrhd,unr) head;
139c18a5ab7SFrançois Tigeot u_int low; /* Lowest item */
140c18a5ab7SFrançois Tigeot u_int high; /* Highest item */
141c18a5ab7SFrançois Tigeot u_int busy; /* Count of allocated items */
142c18a5ab7SFrançois Tigeot u_int alloc; /* Count of memory allocations */
143c18a5ab7SFrançois Tigeot u_int first; /* items in allocated from start */
144c18a5ab7SFrançois Tigeot u_int last; /* items free at end */
145c18a5ab7SFrançois Tigeot struct lock *lock;
146c18a5ab7SFrançois Tigeot };
147c18a5ab7SFrançois Tigeot
148c18a5ab7SFrançois Tigeot
149c18a5ab7SFrançois Tigeot #if defined(DIAGNOSTIC) || !defined(_KERNEL)
150c18a5ab7SFrançois Tigeot /*
151c18a5ab7SFrançois Tigeot * Consistency check function.
152c18a5ab7SFrançois Tigeot *
153c18a5ab7SFrançois Tigeot * Checks the internal consistency as well as we can.
154c18a5ab7SFrançois Tigeot *
155c18a5ab7SFrançois Tigeot * Called at all boundaries of this API.
156c18a5ab7SFrançois Tigeot */
157c18a5ab7SFrançois Tigeot static void
check_unrhdr(struct unrhdr * uh,int line)158c18a5ab7SFrançois Tigeot check_unrhdr(struct unrhdr *uh, int line)
159c18a5ab7SFrançois Tigeot {
160c18a5ab7SFrançois Tigeot struct unr *up;
161c18a5ab7SFrançois Tigeot struct unrb *ub;
162c18a5ab7SFrançois Tigeot u_int x, y, z, w;
163c18a5ab7SFrançois Tigeot
164c18a5ab7SFrançois Tigeot y = uh->first;
165c18a5ab7SFrançois Tigeot z = 0;
166c18a5ab7SFrançois Tigeot TAILQ_FOREACH(up, &uh->head, list) {
167c18a5ab7SFrançois Tigeot z++;
168c18a5ab7SFrançois Tigeot if (up->ptr != uh && up->ptr != NULL) {
169c18a5ab7SFrançois Tigeot ub = up->ptr;
170c18a5ab7SFrançois Tigeot KASSERT (up->len <= NBITS,
171c18a5ab7SFrançois Tigeot ("UNR inconsistency: len %u max %d (line %d)\n",
172c18a5ab7SFrançois Tigeot up->len, NBITS, line));
173c18a5ab7SFrançois Tigeot z++;
174c18a5ab7SFrançois Tigeot w = 0;
175c18a5ab7SFrançois Tigeot for (x = 0; x < up->len; x++)
176c18a5ab7SFrançois Tigeot if (bit_test(ub->map, x))
177c18a5ab7SFrançois Tigeot w++;
178c18a5ab7SFrançois Tigeot KASSERT (w == ub->busy,
179c18a5ab7SFrançois Tigeot ("UNR inconsistency: busy %u found %u (line %d)\n",
180c18a5ab7SFrançois Tigeot ub->busy, w, line));
181c18a5ab7SFrançois Tigeot y += w;
182c18a5ab7SFrançois Tigeot } else if (up->ptr != NULL)
183c18a5ab7SFrançois Tigeot y += up->len;
184c18a5ab7SFrançois Tigeot }
185c18a5ab7SFrançois Tigeot KASSERT (y == uh->busy,
186c18a5ab7SFrançois Tigeot ("UNR inconsistency: items %u found %u (line %d)\n",
187c18a5ab7SFrançois Tigeot uh->busy, y, line));
188c18a5ab7SFrançois Tigeot KASSERT (z == uh->alloc,
189c18a5ab7SFrançois Tigeot ("UNR inconsistency: chunks %u found %u (line %d)\n",
190c18a5ab7SFrançois Tigeot uh->alloc, z, line));
191c18a5ab7SFrançois Tigeot }
192c18a5ab7SFrançois Tigeot
193c18a5ab7SFrançois Tigeot #else
194c18a5ab7SFrançois Tigeot
195c18a5ab7SFrançois Tigeot static __inline void
check_unrhdr(struct unrhdr * uh,int line)196c18a5ab7SFrançois Tigeot check_unrhdr(struct unrhdr *uh, int line)
197c18a5ab7SFrançois Tigeot {
198c18a5ab7SFrançois Tigeot
199c18a5ab7SFrançois Tigeot }
200c18a5ab7SFrançois Tigeot
201c18a5ab7SFrançois Tigeot #endif
202c18a5ab7SFrançois Tigeot
203c18a5ab7SFrançois Tigeot
204c18a5ab7SFrançois Tigeot /*
205c18a5ab7SFrançois Tigeot * Userland memory management. Just use calloc and keep track of how
206c18a5ab7SFrançois Tigeot * many elements we have allocated for check_unrhdr().
207c18a5ab7SFrançois Tigeot */
208c18a5ab7SFrançois Tigeot
209c18a5ab7SFrançois Tigeot static __inline void *
new_unr(struct unrhdr * uh,void ** p1,void ** p2)210c18a5ab7SFrançois Tigeot new_unr(struct unrhdr *uh, void **p1, void **p2)
211c18a5ab7SFrançois Tigeot {
212c18a5ab7SFrançois Tigeot void *p;
213c18a5ab7SFrançois Tigeot
214c18a5ab7SFrançois Tigeot uh->alloc++;
215c18a5ab7SFrançois Tigeot KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory"));
216c18a5ab7SFrançois Tigeot if (*p1 != NULL) {
217c18a5ab7SFrançois Tigeot p = *p1;
218c18a5ab7SFrançois Tigeot *p1 = NULL;
219c18a5ab7SFrançois Tigeot return (p);
220c18a5ab7SFrançois Tigeot } else {
221c18a5ab7SFrançois Tigeot p = *p2;
222c18a5ab7SFrançois Tigeot *p2 = NULL;
223c18a5ab7SFrançois Tigeot return (p);
224c18a5ab7SFrançois Tigeot }
225c18a5ab7SFrançois Tigeot }
226c18a5ab7SFrançois Tigeot
227c18a5ab7SFrançois Tigeot static __inline void
delete_unr(struct unrhdr * uh,void * ptr)228c18a5ab7SFrançois Tigeot delete_unr(struct unrhdr *uh, void *ptr)
229c18a5ab7SFrançois Tigeot {
230c18a5ab7SFrançois Tigeot
231c18a5ab7SFrançois Tigeot uh->alloc--;
232c18a5ab7SFrançois Tigeot Free(ptr);
233c18a5ab7SFrançois Tigeot }
234c18a5ab7SFrançois Tigeot
235c18a5ab7SFrançois Tigeot /*
236c18a5ab7SFrançois Tigeot * Allocate a new unrheader set.
237c18a5ab7SFrançois Tigeot *
238c18a5ab7SFrançois Tigeot * Highest and lowest valid values given as paramters.
239c18a5ab7SFrançois Tigeot */
240c18a5ab7SFrançois Tigeot
241c18a5ab7SFrançois Tigeot struct unrhdr *
new_unrhdr(int low,int high,struct lock * lock)242c18a5ab7SFrançois Tigeot new_unrhdr(int low, int high, struct lock *lock)
243c18a5ab7SFrançois Tigeot {
244c18a5ab7SFrançois Tigeot struct unrhdr *uh;
245c18a5ab7SFrançois Tigeot
246c18a5ab7SFrançois Tigeot KASSERT(low <= high,
247c18a5ab7SFrançois Tigeot ("UNR: use error: new_unrhdr(%u, %u)", low, high));
248c18a5ab7SFrançois Tigeot uh = Malloc(sizeof *uh);
249c18a5ab7SFrançois Tigeot if (lock != NULL)
250c18a5ab7SFrançois Tigeot uh->lock = lock;
251c18a5ab7SFrançois Tigeot else
252c18a5ab7SFrançois Tigeot uh->lock = &unit_lock;
253c18a5ab7SFrançois Tigeot TAILQ_INIT(&uh->head);
254c18a5ab7SFrançois Tigeot uh->low = low;
255c18a5ab7SFrançois Tigeot uh->high = high;
256c18a5ab7SFrançois Tigeot uh->first = 0;
257c18a5ab7SFrançois Tigeot uh->last = 1 + (high - low);
258c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
259c18a5ab7SFrançois Tigeot return (uh);
260c18a5ab7SFrançois Tigeot }
261c18a5ab7SFrançois Tigeot
262c18a5ab7SFrançois Tigeot void
delete_unrhdr(struct unrhdr * uh)263c18a5ab7SFrançois Tigeot delete_unrhdr(struct unrhdr *uh)
264c18a5ab7SFrançois Tigeot {
265c18a5ab7SFrançois Tigeot
266c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
267c18a5ab7SFrançois Tigeot KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy));
268c18a5ab7SFrançois Tigeot KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr"));
269c18a5ab7SFrançois Tigeot Free(uh);
270c18a5ab7SFrançois Tigeot }
271c18a5ab7SFrançois Tigeot
272c18a5ab7SFrançois Tigeot static __inline int
is_bitmap(struct unrhdr * uh,struct unr * up)273c18a5ab7SFrançois Tigeot is_bitmap(struct unrhdr *uh, struct unr *up)
274c18a5ab7SFrançois Tigeot {
275c18a5ab7SFrançois Tigeot return (up->ptr != uh && up->ptr != NULL);
276c18a5ab7SFrançois Tigeot }
277c18a5ab7SFrançois Tigeot
278c18a5ab7SFrançois Tigeot /*
279c18a5ab7SFrançois Tigeot * Look for sequence of items which can be combined into a bitmap, if
280c18a5ab7SFrançois Tigeot * multiple are present, take the one which saves most memory.
281c18a5ab7SFrançois Tigeot *
282c18a5ab7SFrançois Tigeot * Return (1) if a sequence was found to indicate that another call
283c18a5ab7SFrançois Tigeot * might be able to do more. Return (0) if we found no suitable sequence.
284c18a5ab7SFrançois Tigeot *
285c18a5ab7SFrançois Tigeot * NB: called from alloc_unr(), no new memory allocation allowed.
286c18a5ab7SFrançois Tigeot */
287c18a5ab7SFrançois Tigeot static int
optimize_unr(struct unrhdr * uh)288c18a5ab7SFrançois Tigeot optimize_unr(struct unrhdr *uh)
289c18a5ab7SFrançois Tigeot {
290c18a5ab7SFrançois Tigeot struct unr *up, *uf, *us;
291c18a5ab7SFrançois Tigeot struct unrb *ub, *ubf;
292c18a5ab7SFrançois Tigeot u_int a, l, ba;
293c18a5ab7SFrançois Tigeot
294c18a5ab7SFrançois Tigeot /*
295c18a5ab7SFrançois Tigeot * Look for the run of items (if any) which when collapsed into
296c18a5ab7SFrançois Tigeot * a bitmap would save most memory.
297c18a5ab7SFrançois Tigeot */
298c18a5ab7SFrançois Tigeot us = NULL;
299c18a5ab7SFrançois Tigeot ba = 0;
300c18a5ab7SFrançois Tigeot TAILQ_FOREACH(uf, &uh->head, list) {
301c18a5ab7SFrançois Tigeot if (uf->len >= NBITS)
302c18a5ab7SFrançois Tigeot continue;
303c18a5ab7SFrançois Tigeot a = 1;
304c18a5ab7SFrançois Tigeot if (is_bitmap(uh, uf))
305c18a5ab7SFrançois Tigeot a++;
306c18a5ab7SFrançois Tigeot l = uf->len;
307c18a5ab7SFrançois Tigeot up = uf;
308c18a5ab7SFrançois Tigeot while (1) {
309c18a5ab7SFrançois Tigeot up = TAILQ_NEXT(up, list);
310c18a5ab7SFrançois Tigeot if (up == NULL)
311c18a5ab7SFrançois Tigeot break;
312c18a5ab7SFrançois Tigeot if ((up->len + l) > NBITS)
313c18a5ab7SFrançois Tigeot break;
314c18a5ab7SFrançois Tigeot a++;
315c18a5ab7SFrançois Tigeot if (is_bitmap(uh, up))
316c18a5ab7SFrançois Tigeot a++;
317c18a5ab7SFrançois Tigeot l += up->len;
318c18a5ab7SFrançois Tigeot }
319c18a5ab7SFrançois Tigeot if (a > ba) {
320c18a5ab7SFrançois Tigeot ba = a;
321c18a5ab7SFrançois Tigeot us = uf;
322c18a5ab7SFrançois Tigeot }
323c18a5ab7SFrançois Tigeot }
324c18a5ab7SFrançois Tigeot if (ba < 3)
325c18a5ab7SFrançois Tigeot return (0);
326c18a5ab7SFrançois Tigeot
327c18a5ab7SFrançois Tigeot /*
328c18a5ab7SFrançois Tigeot * If the first element is not a bitmap, make it one.
329c18a5ab7SFrançois Tigeot * Trying to do so without allocating more memory complicates things
330c18a5ab7SFrançois Tigeot * a bit
331c18a5ab7SFrançois Tigeot */
332c18a5ab7SFrançois Tigeot if (!is_bitmap(uh, us)) {
333c18a5ab7SFrançois Tigeot uf = TAILQ_NEXT(us, list);
334c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, us, list);
335c18a5ab7SFrançois Tigeot a = us->len;
336c18a5ab7SFrançois Tigeot l = us->ptr == uh ? 1 : 0;
337c18a5ab7SFrançois Tigeot ub = (void *)us;
338c18a5ab7SFrançois Tigeot ub->busy = 0;
339c18a5ab7SFrançois Tigeot if (l) {
340c18a5ab7SFrançois Tigeot bit_nset(ub->map, 0, a);
341c18a5ab7SFrançois Tigeot ub->busy += a;
342c18a5ab7SFrançois Tigeot } else {
343c18a5ab7SFrançois Tigeot bit_nclear(ub->map, 0, a);
344c18a5ab7SFrançois Tigeot }
345c18a5ab7SFrançois Tigeot if (!is_bitmap(uh, uf)) {
346c18a5ab7SFrançois Tigeot if (uf->ptr == NULL) {
347c18a5ab7SFrançois Tigeot bit_nclear(ub->map, a, a + uf->len - 1);
348c18a5ab7SFrançois Tigeot } else {
349c18a5ab7SFrançois Tigeot bit_nset(ub->map, a, a + uf->len - 1);
350c18a5ab7SFrançois Tigeot ub->busy += uf->len;
351c18a5ab7SFrançois Tigeot }
352c18a5ab7SFrançois Tigeot uf->ptr = ub;
353c18a5ab7SFrançois Tigeot uf->len += a;
354c18a5ab7SFrançois Tigeot us = uf;
355c18a5ab7SFrançois Tigeot } else {
356c18a5ab7SFrançois Tigeot ubf = uf->ptr;
357c18a5ab7SFrançois Tigeot for (l = 0; l < uf->len; l++, a++) {
358c18a5ab7SFrançois Tigeot if (bit_test(ubf->map, l)) {
359c18a5ab7SFrançois Tigeot bit_set(ub->map, a);
360c18a5ab7SFrançois Tigeot ub->busy++;
361c18a5ab7SFrançois Tigeot } else {
362c18a5ab7SFrançois Tigeot bit_clear(ub->map, a);
363c18a5ab7SFrançois Tigeot }
364c18a5ab7SFrançois Tigeot }
365c18a5ab7SFrançois Tigeot uf->len = a;
366c18a5ab7SFrançois Tigeot delete_unr(uh, uf->ptr);
367c18a5ab7SFrançois Tigeot uf->ptr = ub;
368c18a5ab7SFrançois Tigeot us = uf;
369c18a5ab7SFrançois Tigeot }
370c18a5ab7SFrançois Tigeot }
371c18a5ab7SFrançois Tigeot ub = us->ptr;
372c18a5ab7SFrançois Tigeot while (1) {
373c18a5ab7SFrançois Tigeot uf = TAILQ_NEXT(us, list);
374c18a5ab7SFrançois Tigeot if (uf == NULL)
375c18a5ab7SFrançois Tigeot return (1);
376c18a5ab7SFrançois Tigeot if (uf->len + us->len > NBITS)
377c18a5ab7SFrançois Tigeot return (1);
378c18a5ab7SFrançois Tigeot if (uf->ptr == NULL) {
379c18a5ab7SFrançois Tigeot bit_nclear(ub->map, us->len, us->len + uf->len - 1);
380c18a5ab7SFrançois Tigeot us->len += uf->len;
381c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, uf, list);
382c18a5ab7SFrançois Tigeot delete_unr(uh, uf);
383c18a5ab7SFrançois Tigeot } else if (uf->ptr == uh) {
384c18a5ab7SFrançois Tigeot bit_nset(ub->map, us->len, us->len + uf->len - 1);
385c18a5ab7SFrançois Tigeot ub->busy += uf->len;
386c18a5ab7SFrançois Tigeot us->len += uf->len;
387c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, uf, list);
388c18a5ab7SFrançois Tigeot delete_unr(uh, uf);
389c18a5ab7SFrançois Tigeot } else {
390c18a5ab7SFrançois Tigeot ubf = uf->ptr;
391c18a5ab7SFrançois Tigeot for (l = 0; l < uf->len; l++, us->len++) {
392c18a5ab7SFrançois Tigeot if (bit_test(ubf->map, l)) {
393c18a5ab7SFrançois Tigeot bit_set(ub->map, us->len);
394c18a5ab7SFrançois Tigeot ub->busy++;
395c18a5ab7SFrançois Tigeot } else {
396c18a5ab7SFrançois Tigeot bit_clear(ub->map, us->len);
397c18a5ab7SFrançois Tigeot }
398c18a5ab7SFrançois Tigeot }
399c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, uf, list);
400c18a5ab7SFrançois Tigeot delete_unr(uh, ubf);
401c18a5ab7SFrançois Tigeot delete_unr(uh, uf);
402c18a5ab7SFrançois Tigeot }
403c18a5ab7SFrançois Tigeot }
404c18a5ab7SFrançois Tigeot }
405c18a5ab7SFrançois Tigeot
406c18a5ab7SFrançois Tigeot /*
407c18a5ab7SFrançois Tigeot * See if a given unr should be collapsed with a neighbor.
408c18a5ab7SFrançois Tigeot *
409c18a5ab7SFrançois Tigeot * NB: called from alloc_unr(), no new memory allocation allowed.
410c18a5ab7SFrançois Tigeot */
411c18a5ab7SFrançois Tigeot static void
collapse_unr(struct unrhdr * uh,struct unr * up)412c18a5ab7SFrançois Tigeot collapse_unr(struct unrhdr *uh, struct unr *up)
413c18a5ab7SFrançois Tigeot {
414c18a5ab7SFrançois Tigeot struct unr *upp;
415c18a5ab7SFrançois Tigeot struct unrb *ub;
416c18a5ab7SFrançois Tigeot
417c18a5ab7SFrançois Tigeot /* If bitmap is all set or clear, change it to runlength */
418c18a5ab7SFrançois Tigeot if (is_bitmap(uh, up)) {
419c18a5ab7SFrançois Tigeot ub = up->ptr;
420c18a5ab7SFrançois Tigeot if (ub->busy == up->len) {
421c18a5ab7SFrançois Tigeot delete_unr(uh, up->ptr);
422c18a5ab7SFrançois Tigeot up->ptr = uh;
423c18a5ab7SFrançois Tigeot } else if (ub->busy == 0) {
424c18a5ab7SFrançois Tigeot delete_unr(uh, up->ptr);
425c18a5ab7SFrançois Tigeot up->ptr = NULL;
426c18a5ab7SFrançois Tigeot }
427c18a5ab7SFrançois Tigeot }
428c18a5ab7SFrançois Tigeot
429c18a5ab7SFrançois Tigeot /* If nothing left in runlength, delete it */
430c18a5ab7SFrançois Tigeot if (up->len == 0) {
431c18a5ab7SFrançois Tigeot upp = TAILQ_PREV(up, unrhd, list);
432c18a5ab7SFrançois Tigeot if (upp == NULL)
433c18a5ab7SFrançois Tigeot upp = TAILQ_NEXT(up, list);
434c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, up, list);
435c18a5ab7SFrançois Tigeot delete_unr(uh, up);
436c18a5ab7SFrançois Tigeot up = upp;
437c18a5ab7SFrançois Tigeot }
438c18a5ab7SFrançois Tigeot
439c18a5ab7SFrançois Tigeot /* If we have "hot-spot" still, merge with neighbor if possible */
440c18a5ab7SFrançois Tigeot if (up != NULL) {
441c18a5ab7SFrançois Tigeot upp = TAILQ_PREV(up, unrhd, list);
442c18a5ab7SFrançois Tigeot if (upp != NULL && up->ptr == upp->ptr) {
443c18a5ab7SFrançois Tigeot up->len += upp->len;
444c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, upp, list);
445c18a5ab7SFrançois Tigeot delete_unr(uh, upp);
446c18a5ab7SFrançois Tigeot }
447c18a5ab7SFrançois Tigeot upp = TAILQ_NEXT(up, list);
448c18a5ab7SFrançois Tigeot if (upp != NULL && up->ptr == upp->ptr) {
449c18a5ab7SFrançois Tigeot up->len += upp->len;
450c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, upp, list);
451c18a5ab7SFrançois Tigeot delete_unr(uh, upp);
452c18a5ab7SFrançois Tigeot }
453c18a5ab7SFrançois Tigeot }
454c18a5ab7SFrançois Tigeot
455c18a5ab7SFrançois Tigeot /* Merge into ->first if possible */
456c18a5ab7SFrançois Tigeot upp = TAILQ_FIRST(&uh->head);
457c18a5ab7SFrançois Tigeot if (upp != NULL && upp->ptr == uh) {
458c18a5ab7SFrançois Tigeot uh->first += upp->len;
459c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, upp, list);
460c18a5ab7SFrançois Tigeot delete_unr(uh, upp);
461c18a5ab7SFrançois Tigeot if (up == upp)
462c18a5ab7SFrançois Tigeot up = NULL;
463c18a5ab7SFrançois Tigeot }
464c18a5ab7SFrançois Tigeot
465c18a5ab7SFrançois Tigeot /* Merge into ->last if possible */
466c18a5ab7SFrançois Tigeot upp = TAILQ_LAST(&uh->head, unrhd);
467c18a5ab7SFrançois Tigeot if (upp != NULL && upp->ptr == NULL) {
468c18a5ab7SFrançois Tigeot uh->last += upp->len;
469c18a5ab7SFrançois Tigeot TAILQ_REMOVE(&uh->head, upp, list);
470c18a5ab7SFrançois Tigeot delete_unr(uh, upp);
471c18a5ab7SFrançois Tigeot if (up == upp)
472c18a5ab7SFrançois Tigeot up = NULL;
473c18a5ab7SFrançois Tigeot }
474c18a5ab7SFrançois Tigeot
475c18a5ab7SFrançois Tigeot /* Try to make bitmaps */
476c18a5ab7SFrançois Tigeot while (optimize_unr(uh))
477c18a5ab7SFrançois Tigeot continue;
478c18a5ab7SFrançois Tigeot }
479c18a5ab7SFrançois Tigeot
480c18a5ab7SFrançois Tigeot /*
481c18a5ab7SFrançois Tigeot * Allocate a free unr.
482c18a5ab7SFrançois Tigeot */
483c18a5ab7SFrançois Tigeot int
alloc_unrl(struct unrhdr * uh)484c18a5ab7SFrançois Tigeot alloc_unrl(struct unrhdr *uh)
485c18a5ab7SFrançois Tigeot {
486c18a5ab7SFrançois Tigeot struct unr *up;
487c18a5ab7SFrançois Tigeot struct unrb *ub;
488c18a5ab7SFrançois Tigeot u_int x;
489c18a5ab7SFrançois Tigeot int y;
490a25c5a19SSascha Wildner struct lock *ml __debugvar = uh->lock;
491a25c5a19SSascha Wildner struct thread *td __debugvar = curthread;
492c18a5ab7SFrançois Tigeot
493c18a5ab7SFrançois Tigeot KKASSERT(lockstatus(ml, td) != 0);
494c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
495c18a5ab7SFrançois Tigeot x = uh->low + uh->first;
496c18a5ab7SFrançois Tigeot
497c18a5ab7SFrançois Tigeot up = TAILQ_FIRST(&uh->head);
498c18a5ab7SFrançois Tigeot
499c18a5ab7SFrançois Tigeot /*
500c18a5ab7SFrançois Tigeot * If we have an ideal split, just adjust the first+last
501c18a5ab7SFrançois Tigeot */
502c18a5ab7SFrançois Tigeot if (up == NULL && uh->last > 0) {
503c18a5ab7SFrançois Tigeot uh->first++;
504c18a5ab7SFrançois Tigeot uh->last--;
505c18a5ab7SFrançois Tigeot uh->busy++;
506c18a5ab7SFrançois Tigeot return (x);
507c18a5ab7SFrançois Tigeot }
508c18a5ab7SFrançois Tigeot
509c18a5ab7SFrançois Tigeot /*
510c18a5ab7SFrançois Tigeot * We can always allocate from the first list element, so if we have
511c18a5ab7SFrançois Tigeot * nothing on the list, we must have run out of unit numbers.
512c18a5ab7SFrançois Tigeot */
513c18a5ab7SFrançois Tigeot if (up == NULL)
514c18a5ab7SFrançois Tigeot return (-1);
515c18a5ab7SFrançois Tigeot
516c18a5ab7SFrançois Tigeot KASSERT(up->ptr != uh, ("UNR first element is allocated"));
517c18a5ab7SFrançois Tigeot
518c18a5ab7SFrançois Tigeot if (up->ptr == NULL) { /* free run */
519c18a5ab7SFrançois Tigeot uh->first++;
520c18a5ab7SFrançois Tigeot up->len--;
521c18a5ab7SFrançois Tigeot } else { /* bitmap */
522c18a5ab7SFrançois Tigeot ub = up->ptr;
523c18a5ab7SFrançois Tigeot KASSERT(ub->busy < up->len, ("UNR bitmap confusion"));
524c18a5ab7SFrançois Tigeot bit_ffc(ub->map, up->len, &y);
525c18a5ab7SFrançois Tigeot KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap."));
526c18a5ab7SFrançois Tigeot bit_set(ub->map, y);
527c18a5ab7SFrançois Tigeot ub->busy++;
528c18a5ab7SFrançois Tigeot x += y;
529c18a5ab7SFrançois Tigeot }
530c18a5ab7SFrançois Tigeot uh->busy++;
531c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
532c18a5ab7SFrançois Tigeot return (x);
533c18a5ab7SFrançois Tigeot }
534c18a5ab7SFrançois Tigeot
535c18a5ab7SFrançois Tigeot int
alloc_unr(struct unrhdr * uh)536c18a5ab7SFrançois Tigeot alloc_unr(struct unrhdr *uh)
537c18a5ab7SFrançois Tigeot {
538c18a5ab7SFrançois Tigeot int i;
539c18a5ab7SFrançois Tigeot
540c18a5ab7SFrançois Tigeot lockmgr(uh->lock, LK_EXCLUSIVE);
541c18a5ab7SFrançois Tigeot i = alloc_unrl(uh);
542c18a5ab7SFrançois Tigeot lockmgr(uh->lock, LK_RELEASE);
543c18a5ab7SFrançois Tigeot return (i);
544c18a5ab7SFrançois Tigeot }
545c18a5ab7SFrançois Tigeot
546c18a5ab7SFrançois Tigeot /*
547c18a5ab7SFrançois Tigeot * Free a unr.
548c18a5ab7SFrançois Tigeot *
549c18a5ab7SFrançois Tigeot * If we can save unrs by using a bitmap, do so.
550c18a5ab7SFrançois Tigeot */
551c18a5ab7SFrançois Tigeot static void
free_unrl(struct unrhdr * uh,u_int item,void ** p1,void ** p2)552c18a5ab7SFrançois Tigeot free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2)
553c18a5ab7SFrançois Tigeot {
554c18a5ab7SFrançois Tigeot struct unr *up, *upp, *upn;
555c18a5ab7SFrançois Tigeot struct unrb *ub;
556c18a5ab7SFrançois Tigeot u_int pl;
557c18a5ab7SFrançois Tigeot
558c18a5ab7SFrançois Tigeot KASSERT(item >= uh->low && item <= uh->high,
559c18a5ab7SFrançois Tigeot ("UNR: free_unr(%u) out of range [%u...%u]",
560c18a5ab7SFrançois Tigeot item, uh->low, uh->high));
561c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
562c18a5ab7SFrançois Tigeot item -= uh->low;
563c18a5ab7SFrançois Tigeot upp = TAILQ_FIRST(&uh->head);
564c18a5ab7SFrançois Tigeot /*
565c18a5ab7SFrançois Tigeot * Freeing in the ideal split case
566c18a5ab7SFrançois Tigeot */
567c18a5ab7SFrançois Tigeot if (item + 1 == uh->first && upp == NULL) {
568c18a5ab7SFrançois Tigeot uh->last++;
569c18a5ab7SFrançois Tigeot uh->first--;
570c18a5ab7SFrançois Tigeot uh->busy--;
571c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
572c18a5ab7SFrançois Tigeot return;
573c18a5ab7SFrançois Tigeot }
574c18a5ab7SFrançois Tigeot /*
575c18a5ab7SFrançois Tigeot * Freeing in the ->first section. Create a run starting at the
576c18a5ab7SFrançois Tigeot * freed item. The code below will subdivide it.
577c18a5ab7SFrançois Tigeot */
578c18a5ab7SFrançois Tigeot if (item < uh->first) {
579c18a5ab7SFrançois Tigeot up = new_unr(uh, p1, p2);
580c18a5ab7SFrançois Tigeot up->ptr = uh;
581c18a5ab7SFrançois Tigeot up->len = uh->first - item;
582c18a5ab7SFrançois Tigeot TAILQ_INSERT_HEAD(&uh->head, up, list);
583c18a5ab7SFrançois Tigeot uh->first -= up->len;
584c18a5ab7SFrançois Tigeot }
585c18a5ab7SFrançois Tigeot
586c18a5ab7SFrançois Tigeot item -= uh->first;
587c18a5ab7SFrançois Tigeot
588c18a5ab7SFrançois Tigeot /* Find the item which contains the unit we want to free */
589c18a5ab7SFrançois Tigeot TAILQ_FOREACH(up, &uh->head, list) {
590c18a5ab7SFrançois Tigeot if (up->len > item)
591c18a5ab7SFrançois Tigeot break;
592c18a5ab7SFrançois Tigeot item -= up->len;
593c18a5ab7SFrançois Tigeot }
594c18a5ab7SFrançois Tigeot
595c18a5ab7SFrançois Tigeot /* Handle bitmap items */
596c18a5ab7SFrançois Tigeot if (is_bitmap(uh, up)) {
597c18a5ab7SFrançois Tigeot ub = up->ptr;
598c18a5ab7SFrançois Tigeot
599c18a5ab7SFrançois Tigeot KASSERT(bit_test(ub->map, item) != 0,
600c18a5ab7SFrançois Tigeot ("UNR: Freeing free item %d (bitmap)\n", item));
601c18a5ab7SFrançois Tigeot bit_clear(ub->map, item);
602c18a5ab7SFrançois Tigeot uh->busy--;
603c18a5ab7SFrançois Tigeot ub->busy--;
604c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
605c18a5ab7SFrançois Tigeot return;
606c18a5ab7SFrançois Tigeot }
607c18a5ab7SFrançois Tigeot
608c18a5ab7SFrançois Tigeot KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item));
609c18a5ab7SFrançois Tigeot
610c18a5ab7SFrançois Tigeot /* Just this one left, reap it */
611c18a5ab7SFrançois Tigeot if (up->len == 1) {
612c18a5ab7SFrançois Tigeot up->ptr = NULL;
613c18a5ab7SFrançois Tigeot uh->busy--;
614c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
615c18a5ab7SFrançois Tigeot return;
616c18a5ab7SFrançois Tigeot }
617c18a5ab7SFrançois Tigeot
618c18a5ab7SFrançois Tigeot /* Check if we can shift the item into the previous 'free' run */
619c18a5ab7SFrançois Tigeot upp = TAILQ_PREV(up, unrhd, list);
620c18a5ab7SFrançois Tigeot if (item == 0 && upp != NULL && upp->ptr == NULL) {
621c18a5ab7SFrançois Tigeot upp->len++;
622c18a5ab7SFrançois Tigeot up->len--;
623c18a5ab7SFrançois Tigeot uh->busy--;
624c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
625c18a5ab7SFrançois Tigeot return;
626c18a5ab7SFrançois Tigeot }
627c18a5ab7SFrançois Tigeot
628c18a5ab7SFrançois Tigeot /* Check if we can shift the item to the next 'free' run */
629c18a5ab7SFrançois Tigeot upn = TAILQ_NEXT(up, list);
630c18a5ab7SFrançois Tigeot if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) {
631c18a5ab7SFrançois Tigeot upn->len++;
632c18a5ab7SFrançois Tigeot up->len--;
633c18a5ab7SFrançois Tigeot uh->busy--;
634c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
635c18a5ab7SFrançois Tigeot return;
636c18a5ab7SFrançois Tigeot }
637c18a5ab7SFrançois Tigeot
638c18a5ab7SFrançois Tigeot /* Split off the tail end, if any. */
639c18a5ab7SFrançois Tigeot pl = up->len - (1 + item);
640c18a5ab7SFrançois Tigeot if (pl > 0) {
641c18a5ab7SFrançois Tigeot upp = new_unr(uh, p1, p2);
642c18a5ab7SFrançois Tigeot upp->ptr = uh;
643c18a5ab7SFrançois Tigeot upp->len = pl;
644c18a5ab7SFrançois Tigeot TAILQ_INSERT_AFTER(&uh->head, up, upp, list);
645c18a5ab7SFrançois Tigeot }
646c18a5ab7SFrançois Tigeot
647c18a5ab7SFrançois Tigeot /* Split off head end, if any */
648c18a5ab7SFrançois Tigeot if (item > 0) {
649c18a5ab7SFrançois Tigeot upp = new_unr(uh, p1, p2);
650c18a5ab7SFrançois Tigeot upp->len = item;
651c18a5ab7SFrançois Tigeot upp->ptr = uh;
652c18a5ab7SFrançois Tigeot TAILQ_INSERT_BEFORE(up, upp, list);
653c18a5ab7SFrançois Tigeot }
654c18a5ab7SFrançois Tigeot up->len = 1;
655c18a5ab7SFrançois Tigeot up->ptr = NULL;
656c18a5ab7SFrançois Tigeot uh->busy--;
657c18a5ab7SFrançois Tigeot collapse_unr(uh, up);
658c18a5ab7SFrançois Tigeot }
659c18a5ab7SFrançois Tigeot
660c18a5ab7SFrançois Tigeot void
free_unr(struct unrhdr * uh,u_int item)661c18a5ab7SFrançois Tigeot free_unr(struct unrhdr *uh, u_int item)
662c18a5ab7SFrançois Tigeot {
663c18a5ab7SFrançois Tigeot void *p1, *p2;
664c18a5ab7SFrançois Tigeot
665c18a5ab7SFrançois Tigeot p1 = Malloc(sizeof(struct unr));
666c18a5ab7SFrançois Tigeot p2 = Malloc(sizeof(struct unr));
667c18a5ab7SFrançois Tigeot lockmgr(uh->lock, LK_EXCLUSIVE);
668c18a5ab7SFrançois Tigeot free_unrl(uh, item, &p1, &p2);
669c18a5ab7SFrançois Tigeot lockmgr(uh->lock, LK_RELEASE);
670c18a5ab7SFrançois Tigeot if (p1 != NULL)
671c18a5ab7SFrançois Tigeot Free(p1);
672c18a5ab7SFrançois Tigeot if (p2 != NULL)
673c18a5ab7SFrançois Tigeot Free(p2);
674c18a5ab7SFrançois Tigeot }
675c18a5ab7SFrançois Tigeot
676c18a5ab7SFrançois Tigeot #ifndef _KERNEL /* USERLAND test driver */
677c18a5ab7SFrançois Tigeot
678c18a5ab7SFrançois Tigeot /*
679c18a5ab7SFrançois Tigeot * Simple stochastic test driver for the above functions
680c18a5ab7SFrançois Tigeot */
681c18a5ab7SFrançois Tigeot
682c18a5ab7SFrançois Tigeot static void
print_unr(struct unrhdr * uh,struct unr * up)683c18a5ab7SFrançois Tigeot print_unr(struct unrhdr *uh, struct unr *up)
684c18a5ab7SFrançois Tigeot {
685c18a5ab7SFrançois Tigeot u_int x;
686c18a5ab7SFrançois Tigeot struct unrb *ub;
687c18a5ab7SFrançois Tigeot
688c18a5ab7SFrançois Tigeot printf(" %p len = %5u ", up, up->len);
689c18a5ab7SFrançois Tigeot if (up->ptr == NULL)
690c18a5ab7SFrançois Tigeot printf("free\n");
691c18a5ab7SFrançois Tigeot else if (up->ptr == uh)
692c18a5ab7SFrançois Tigeot printf("alloc\n");
693c18a5ab7SFrançois Tigeot else {
694c18a5ab7SFrançois Tigeot ub = up->ptr;
695c18a5ab7SFrançois Tigeot printf("bitmap(%d) [", ub->busy);
696c18a5ab7SFrançois Tigeot for (x = 0; x < up->len; x++) {
697c18a5ab7SFrançois Tigeot if (bit_test(ub->map, x))
698c18a5ab7SFrançois Tigeot printf("#");
699c18a5ab7SFrançois Tigeot else
700c18a5ab7SFrançois Tigeot printf(" ");
701c18a5ab7SFrançois Tigeot }
702c18a5ab7SFrançois Tigeot printf("]\n");
703c18a5ab7SFrançois Tigeot }
704c18a5ab7SFrançois Tigeot }
705c18a5ab7SFrançois Tigeot
706c18a5ab7SFrançois Tigeot static void
print_unrhdr(struct unrhdr * uh)707c18a5ab7SFrançois Tigeot print_unrhdr(struct unrhdr *uh)
708c18a5ab7SFrançois Tigeot {
709c18a5ab7SFrançois Tigeot struct unr *up;
710c18a5ab7SFrançois Tigeot u_int x;
711c18a5ab7SFrançois Tigeot
712c18a5ab7SFrançois Tigeot printf(
713c18a5ab7SFrançois Tigeot "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n",
714c18a5ab7SFrançois Tigeot uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc);
715c18a5ab7SFrançois Tigeot x = uh->low + uh->first;
716c18a5ab7SFrançois Tigeot TAILQ_FOREACH(up, &uh->head, list) {
717c18a5ab7SFrançois Tigeot printf(" from = %5u", x);
718c18a5ab7SFrançois Tigeot print_unr(uh, up);
719c18a5ab7SFrançois Tigeot if (up->ptr == NULL || up->ptr == uh)
720c18a5ab7SFrançois Tigeot x += up->len;
721c18a5ab7SFrançois Tigeot else
722c18a5ab7SFrançois Tigeot x += NBITS;
723c18a5ab7SFrançois Tigeot }
724c18a5ab7SFrançois Tigeot }
725c18a5ab7SFrançois Tigeot
726c18a5ab7SFrançois Tigeot /* Number of unrs to test */
727c18a5ab7SFrançois Tigeot #define NN 10000
728c18a5ab7SFrançois Tigeot
729c18a5ab7SFrançois Tigeot int
main(int argc __unused,const char ** argv __unused)730c18a5ab7SFrançois Tigeot main(int argc __unused, const char **argv __unused)
731c18a5ab7SFrançois Tigeot {
732c18a5ab7SFrançois Tigeot struct unrhdr *uh;
733c18a5ab7SFrançois Tigeot u_int i, x, m, j;
734c18a5ab7SFrançois Tigeot char a[NN];
735c18a5ab7SFrançois Tigeot
736c18a5ab7SFrançois Tigeot setbuf(stdout, NULL);
737c18a5ab7SFrançois Tigeot uh = new_unrhdr(0, NN - 1, NULL);
738c18a5ab7SFrançois Tigeot print_unrhdr(uh);
739c18a5ab7SFrançois Tigeot
740c18a5ab7SFrançois Tigeot memset(a, 0, sizeof a);
741c18a5ab7SFrançois Tigeot
742c18a5ab7SFrançois Tigeot fprintf(stderr, "sizeof(struct unr) %d\n", sizeof (struct unr));
743c18a5ab7SFrançois Tigeot fprintf(stderr, "sizeof(struct unrb) %d\n", sizeof (struct unrb));
744c18a5ab7SFrançois Tigeot fprintf(stderr, "sizeof(struct unrhdr) %d\n", sizeof (struct unrhdr));
745c18a5ab7SFrançois Tigeot fprintf(stderr, "NBITS %d\n", NBITS);
746c18a5ab7SFrançois Tigeot x = 1;
747c18a5ab7SFrançois Tigeot for (m = 0; m < NN * 100; m++) {
748c18a5ab7SFrançois Tigeot j = random();
749c18a5ab7SFrançois Tigeot i = (j >> 1) % NN;
750c18a5ab7SFrançois Tigeot #if 0
751c18a5ab7SFrançois Tigeot if (a[i] && (j & 1))
752c18a5ab7SFrançois Tigeot continue;
753c18a5ab7SFrançois Tigeot #endif
754c18a5ab7SFrançois Tigeot if (a[i]) {
755c18a5ab7SFrançois Tigeot printf("F %u\n", i);
756c18a5ab7SFrançois Tigeot free_unr(uh, i);
757c18a5ab7SFrançois Tigeot a[i] = 0;
758c18a5ab7SFrançois Tigeot } else {
759c18a5ab7SFrançois Tigeot no_alloc = 1;
760c18a5ab7SFrançois Tigeot i = alloc_unr(uh);
761c18a5ab7SFrançois Tigeot if (i != -1) {
762c18a5ab7SFrançois Tigeot a[i] = 1;
763c18a5ab7SFrançois Tigeot printf("A %u\n", i);
764c18a5ab7SFrançois Tigeot }
765c18a5ab7SFrançois Tigeot no_alloc = 0;
766c18a5ab7SFrançois Tigeot }
767c18a5ab7SFrançois Tigeot if (1) /* XXX: change this for detailed debug printout */
768c18a5ab7SFrançois Tigeot print_unrhdr(uh);
769c18a5ab7SFrançois Tigeot check_unrhdr(uh, __LINE__);
770c18a5ab7SFrançois Tigeot }
771c18a5ab7SFrançois Tigeot for (i = 0; i < NN; i++) {
772c18a5ab7SFrançois Tigeot if (a[i]) {
773c18a5ab7SFrançois Tigeot printf("C %u\n", i);
774c18a5ab7SFrançois Tigeot free_unr(uh, i);
775c18a5ab7SFrançois Tigeot print_unrhdr(uh);
776c18a5ab7SFrançois Tigeot }
777c18a5ab7SFrançois Tigeot }
778c18a5ab7SFrançois Tigeot print_unrhdr(uh);
779c18a5ab7SFrançois Tigeot delete_unrhdr(uh);
780c18a5ab7SFrançois Tigeot return (0);
781c18a5ab7SFrançois Tigeot }
782c18a5ab7SFrançois Tigeot #endif
783