1f6bde1fdSPoul-Henning Kamp /*- 28a36da99SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 38a36da99SPedro F. Giffuni * 4f6bde1fdSPoul-Henning Kamp * Copyright (c) 2004 Poul-Henning Kamp 5f6bde1fdSPoul-Henning Kamp * All rights reserved. 6f6bde1fdSPoul-Henning Kamp * 7f6bde1fdSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 8f6bde1fdSPoul-Henning Kamp * modification, are permitted provided that the following conditions 9f6bde1fdSPoul-Henning Kamp * are met: 10f6bde1fdSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 11f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 12f6bde1fdSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 13f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 14f6bde1fdSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 15f6bde1fdSPoul-Henning Kamp * 16f6bde1fdSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17f6bde1fdSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18f6bde1fdSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19f6bde1fdSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20f6bde1fdSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21f6bde1fdSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22f6bde1fdSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23f6bde1fdSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24f6bde1fdSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25f6bde1fdSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26f6bde1fdSPoul-Henning Kamp * SUCH DAMAGE. 27f6bde1fdSPoul-Henning Kamp * 28f6bde1fdSPoul-Henning Kamp * $FreeBSD$ 29d9a54d5cSPoul-Henning Kamp * 30d9a54d5cSPoul-Henning Kamp * 31d9a54d5cSPoul-Henning Kamp * Unit number allocation functions. 32f6bde1fdSPoul-Henning Kamp * 33f6bde1fdSPoul-Henning Kamp * These functions implement a mixed run-length/bitmap management of unit 34d9a54d5cSPoul-Henning Kamp * number spaces in a very memory efficient manner. 35f6bde1fdSPoul-Henning Kamp * 36d9a54d5cSPoul-Henning Kamp * Allocation policy is always lowest free number first. 37f6bde1fdSPoul-Henning Kamp * 38d9a54d5cSPoul-Henning Kamp * A return value of -1 signals that no more unit numbers are available. 39f6bde1fdSPoul-Henning Kamp * 40d9a54d5cSPoul-Henning Kamp * There is no cost associated with the range of unitnumbers, so unless 41d9a54d5cSPoul-Henning Kamp * the resource really is finite, specify INT_MAX to new_unrhdr() and 42d9a54d5cSPoul-Henning Kamp * forget about checking the return value. 43f6bde1fdSPoul-Henning Kamp * 44d9a54d5cSPoul-Henning Kamp * If a mutex is not provided when the unit number space is created, a 45d9a54d5cSPoul-Henning Kamp * default global mutex is used. The advantage to passing a mutex in, is 466bccea7cSRebecca Cran * that the alloc_unrl() function can be called with the mutex already 47d9a54d5cSPoul-Henning Kamp * held (it will not be released by alloc_unrl()). 48d9a54d5cSPoul-Henning Kamp * 49d9a54d5cSPoul-Henning Kamp * The allocation function alloc_unr{l}() never sleeps (but it may block on 50d9a54d5cSPoul-Henning Kamp * the mutex of course). 51d9a54d5cSPoul-Henning Kamp * 52d9a54d5cSPoul-Henning Kamp * Freeing a unit number may require allocating memory, and can therefore 53d9a54d5cSPoul-Henning Kamp * sleep so the free_unr() function does not come in a pre-locked variant. 54f6bde1fdSPoul-Henning Kamp * 55f6bde1fdSPoul-Henning Kamp * A userland test program is included. 56f6bde1fdSPoul-Henning Kamp * 576bccea7cSRebecca Cran * Memory usage is a very complex function of the exact allocation 58d9a54d5cSPoul-Henning Kamp * pattern, but always very compact: 59d9a54d5cSPoul-Henning Kamp * * For the very typical case where a single unbroken run of unit 60d9a54d5cSPoul-Henning Kamp * numbers are allocated 44 bytes are used on i386. 61d9a54d5cSPoul-Henning Kamp * * For a unit number space of 1000 units and the random pattern 62d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 63d9a54d5cSPoul-Henning Kamp * was 252 bytes on i386 for 500 allocated and 500 free units. 64d9a54d5cSPoul-Henning Kamp * * For a unit number space of 10000 units and the random pattern 65d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 66d9a54d5cSPoul-Henning Kamp * was 798 bytes on i386 for 5000 allocated and 5000 free units. 67d9a54d5cSPoul-Henning Kamp * * The worst case is where every other unit number is allocated and 6896240c89SEitan Adler * the rest are free. In that case 44 + N/4 bytes are used where 69d9a54d5cSPoul-Henning Kamp * N is the number of the highest unit allocated. 70f6bde1fdSPoul-Henning Kamp */ 71f6bde1fdSPoul-Henning Kamp 728907f744SAlan Somers #include <sys/param.h> 73f6bde1fdSPoul-Henning Kamp #include <sys/types.h> 74dc872d46SKonstantin Belousov #include <sys/_unrhdr.h> 75f6bde1fdSPoul-Henning Kamp 76f6bde1fdSPoul-Henning Kamp #ifdef _KERNEL 77f6bde1fdSPoul-Henning Kamp 78794277daSAlan Somers #include <sys/bitstring.h> 79f6bde1fdSPoul-Henning Kamp #include <sys/malloc.h> 80f6bde1fdSPoul-Henning Kamp #include <sys/kernel.h> 81f6bde1fdSPoul-Henning Kamp #include <sys/systm.h> 82d9a54d5cSPoul-Henning Kamp #include <sys/limits.h> 83d9a54d5cSPoul-Henning Kamp #include <sys/lock.h> 84d9a54d5cSPoul-Henning Kamp #include <sys/mutex.h> 85f6bde1fdSPoul-Henning Kamp 86f6bde1fdSPoul-Henning Kamp /* 87f6bde1fdSPoul-Henning Kamp * In theory it would be smarter to allocate the individual blocks 88f6bde1fdSPoul-Henning Kamp * with the zone allocator, but at this time the expectation is that 89f6bde1fdSPoul-Henning Kamp * there will typically not even be enough allocations to fill a single 90f6bde1fdSPoul-Henning Kamp * page, so we stick with malloc for now. 91f6bde1fdSPoul-Henning Kamp */ 92f6bde1fdSPoul-Henning Kamp static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation"); 93f6bde1fdSPoul-Henning Kamp 94f6bde1fdSPoul-Henning Kamp #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO) 95f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo, M_UNIT) 96f6bde1fdSPoul-Henning Kamp 97d9a54d5cSPoul-Henning Kamp static struct mtx unitmtx; 98d9a54d5cSPoul-Henning Kamp 99d9a54d5cSPoul-Henning Kamp MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF); 100d9a54d5cSPoul-Henning Kamp 101435bef7aSMateusz Guzik #ifdef UNR64_LOCKED 102435bef7aSMateusz Guzik uint64_t 103435bef7aSMateusz Guzik alloc_unr64(struct unrhdr64 *unr64) 104435bef7aSMateusz Guzik { 105435bef7aSMateusz Guzik uint64_t item; 106435bef7aSMateusz Guzik 107435bef7aSMateusz Guzik mtx_lock(&unitmtx); 108435bef7aSMateusz Guzik item = unr64->counter++; 109435bef7aSMateusz Guzik mtx_unlock(&unitmtx); 110435bef7aSMateusz Guzik return (item); 111435bef7aSMateusz Guzik } 112435bef7aSMateusz Guzik #endif 113435bef7aSMateusz Guzik 114f6bde1fdSPoul-Henning Kamp #else /* ...USERLAND */ 115f6bde1fdSPoul-Henning Kamp 116794277daSAlan Somers #include <bitstring.h> 117794277daSAlan Somers #include <err.h> 118794277daSAlan Somers #include <errno.h> 119794277daSAlan Somers #include <getopt.h> 120794277daSAlan Somers #include <stdbool.h> 121f6bde1fdSPoul-Henning Kamp #include <stdio.h> 122f6bde1fdSPoul-Henning Kamp #include <stdlib.h> 123d9a54d5cSPoul-Henning Kamp #include <string.h> 124f6bde1fdSPoul-Henning Kamp 125f6bde1fdSPoul-Henning Kamp #define KASSERT(cond, arg) \ 126f6bde1fdSPoul-Henning Kamp do { \ 127f6bde1fdSPoul-Henning Kamp if (!(cond)) { \ 128f6bde1fdSPoul-Henning Kamp printf arg; \ 129d9a54d5cSPoul-Henning Kamp abort(); \ 130f6bde1fdSPoul-Henning Kamp } \ 131f6bde1fdSPoul-Henning Kamp } while (0) 132f6bde1fdSPoul-Henning Kamp 133d9a54d5cSPoul-Henning Kamp static int no_alloc; 134d9a54d5cSPoul-Henning Kamp #define Malloc(foo) _Malloc(foo, __LINE__) 135d9a54d5cSPoul-Henning Kamp static void * 136d9a54d5cSPoul-Henning Kamp _Malloc(size_t foo, int line) 137d9a54d5cSPoul-Henning Kamp { 138d9a54d5cSPoul-Henning Kamp 139d9a54d5cSPoul-Henning Kamp KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line)); 140d9a54d5cSPoul-Henning Kamp return (calloc(foo, 1)); 141d9a54d5cSPoul-Henning Kamp } 142f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo) 143f6bde1fdSPoul-Henning Kamp 144d9a54d5cSPoul-Henning Kamp struct unrhdr; 145d9a54d5cSPoul-Henning Kamp 146*6fe78ad4SKonstantin Belousov #define UNR_NO_MTX ((void *)(uintptr_t)-1) 147*6fe78ad4SKonstantin Belousov 148d9a54d5cSPoul-Henning Kamp struct mtx { 149d9a54d5cSPoul-Henning Kamp int state; 150d9a54d5cSPoul-Henning Kamp } unitmtx; 151d9a54d5cSPoul-Henning Kamp 152d9a54d5cSPoul-Henning Kamp static void 153d9a54d5cSPoul-Henning Kamp mtx_lock(struct mtx *mp) 154d9a54d5cSPoul-Henning Kamp { 155d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 0, ("mutex already locked")); 156d9a54d5cSPoul-Henning Kamp mp->state = 1; 157d9a54d5cSPoul-Henning Kamp } 158d9a54d5cSPoul-Henning Kamp 159d9a54d5cSPoul-Henning Kamp static void 160d9a54d5cSPoul-Henning Kamp mtx_unlock(struct mtx *mp) 161d9a54d5cSPoul-Henning Kamp { 162d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mutex not locked")); 163d9a54d5cSPoul-Henning Kamp mp->state = 0; 164d9a54d5cSPoul-Henning Kamp } 165d9a54d5cSPoul-Henning Kamp 166d9a54d5cSPoul-Henning Kamp #define MA_OWNED 9 167d9a54d5cSPoul-Henning Kamp 168d9a54d5cSPoul-Henning Kamp static void 169d9a54d5cSPoul-Henning Kamp mtx_assert(struct mtx *mp, int flag) 170d9a54d5cSPoul-Henning Kamp { 171d9a54d5cSPoul-Henning Kamp if (flag == MA_OWNED) { 172d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true")); 173d9a54d5cSPoul-Henning Kamp } 174d9a54d5cSPoul-Henning Kamp } 175d9a54d5cSPoul-Henning Kamp 176d9a54d5cSPoul-Henning Kamp #define CTASSERT(foo) 17724e8eaf1SJaakko Heinonen #define WITNESS_WARN(flags, lock, fmt, ...) (void)0 178d9a54d5cSPoul-Henning Kamp 179d9a54d5cSPoul-Henning Kamp #endif /* USERLAND */ 180f6bde1fdSPoul-Henning Kamp 181f6bde1fdSPoul-Henning Kamp /* 182f6bde1fdSPoul-Henning Kamp * This is our basic building block. 183f6bde1fdSPoul-Henning Kamp * 184f6bde1fdSPoul-Henning Kamp * It can be used in three different ways depending on the value of the ptr 185f6bde1fdSPoul-Henning Kamp * element: 186f6bde1fdSPoul-Henning Kamp * If ptr is NULL, it represents a run of free items. 187f6bde1fdSPoul-Henning Kamp * If ptr points to the unrhdr it represents a run of allocated items. 1888907f744SAlan Somers * Otherwise it points to a bitstring of allocated items. 189f6bde1fdSPoul-Henning Kamp * 190f6bde1fdSPoul-Henning Kamp * For runs the len field is the length of the run. 191f6bde1fdSPoul-Henning Kamp * For bitmaps the len field represents the number of allocated items. 192f6bde1fdSPoul-Henning Kamp * 193f6bde1fdSPoul-Henning Kamp * The bitmap is the same size as struct unr to optimize memory management. 194f6bde1fdSPoul-Henning Kamp */ 195f6bde1fdSPoul-Henning Kamp struct unr { 196f6bde1fdSPoul-Henning Kamp TAILQ_ENTRY(unr) list; 197f6bde1fdSPoul-Henning Kamp u_int len; 198f6bde1fdSPoul-Henning Kamp void *ptr; 199f6bde1fdSPoul-Henning Kamp }; 200f6bde1fdSPoul-Henning Kamp 201d9a54d5cSPoul-Henning Kamp struct unrb { 2028907f744SAlan Somers bitstr_t map[sizeof(struct unr) / sizeof(bitstr_t)]; 203d9a54d5cSPoul-Henning Kamp }; 204d9a54d5cSPoul-Henning Kamp 2058907f744SAlan Somers CTASSERT((sizeof(struct unr) % sizeof(bitstr_t)) == 0); 206d9a54d5cSPoul-Henning Kamp 2078907f744SAlan Somers /* Number of bits we can store in the bitmap */ 2088907f744SAlan Somers #define NBITS (8 * sizeof(((struct unrb*)NULL)->map)) 2098907f744SAlan Somers 2108907f744SAlan Somers /* Is the unrb empty in at least the first len bits? */ 2118907f744SAlan Somers static inline bool 2128907f744SAlan Somers ub_empty(struct unrb *ub, int len) { 2138907f744SAlan Somers int first_set; 2148907f744SAlan Somers 2158907f744SAlan Somers bit_ffs(ub->map, len, &first_set); 2168907f744SAlan Somers return (first_set == -1); 2178907f744SAlan Somers } 2188907f744SAlan Somers 2198907f744SAlan Somers /* Is the unrb full? That is, is the number of set elements equal to len? */ 2208907f744SAlan Somers static inline bool 2218907f744SAlan Somers ub_full(struct unrb *ub, int len) 2228907f744SAlan Somers { 2238907f744SAlan Somers int first_clear; 2248907f744SAlan Somers 2258907f744SAlan Somers bit_ffc(ub->map, len, &first_clear); 2268907f744SAlan Somers return (first_clear == -1); 2278907f744SAlan Somers } 2288907f744SAlan Somers 229f6bde1fdSPoul-Henning Kamp #if defined(DIAGNOSTIC) || !defined(_KERNEL) 230f6bde1fdSPoul-Henning Kamp /* 231f6bde1fdSPoul-Henning Kamp * Consistency check function. 232f6bde1fdSPoul-Henning Kamp * 233f6bde1fdSPoul-Henning Kamp * Checks the internal consistency as well as we can. 234f6bde1fdSPoul-Henning Kamp * 235f6bde1fdSPoul-Henning Kamp * Called at all boundaries of this API. 236f6bde1fdSPoul-Henning Kamp */ 237f6bde1fdSPoul-Henning Kamp static void 238f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unrhdr *uh, int line) 239f6bde1fdSPoul-Henning Kamp { 240f6bde1fdSPoul-Henning Kamp struct unr *up; 241d9a54d5cSPoul-Henning Kamp struct unrb *ub; 2421b82e02fSAlan Somers int w; 2431b82e02fSAlan Somers u_int y, z; 244f6bde1fdSPoul-Henning Kamp 245d9a54d5cSPoul-Henning Kamp y = uh->first; 246f6bde1fdSPoul-Henning Kamp z = 0; 247f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 248f6bde1fdSPoul-Henning Kamp z++; 249f6bde1fdSPoul-Henning Kamp if (up->ptr != uh && up->ptr != NULL) { 250d9a54d5cSPoul-Henning Kamp ub = up->ptr; 251d9a54d5cSPoul-Henning Kamp KASSERT (up->len <= NBITS, 2528907f744SAlan Somers ("UNR inconsistency: len %u max %zd (line %d)\n", 253d9a54d5cSPoul-Henning Kamp up->len, NBITS, line)); 254f6bde1fdSPoul-Henning Kamp z++; 255f6bde1fdSPoul-Henning Kamp w = 0; 2561b82e02fSAlan Somers bit_count(ub->map, 0, up->len, &w); 257d9a54d5cSPoul-Henning Kamp y += w; 258d9a54d5cSPoul-Henning Kamp } else if (up->ptr != NULL) 259f6bde1fdSPoul-Henning Kamp y += up->len; 260f6bde1fdSPoul-Henning Kamp } 261f6bde1fdSPoul-Henning Kamp KASSERT (y == uh->busy, 262f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: items %u found %u (line %d)\n", 263f6bde1fdSPoul-Henning Kamp uh->busy, y, line)); 264f6bde1fdSPoul-Henning Kamp KASSERT (z == uh->alloc, 265f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: chunks %u found %u (line %d)\n", 266f6bde1fdSPoul-Henning Kamp uh->alloc, z, line)); 267f6bde1fdSPoul-Henning Kamp } 268f6bde1fdSPoul-Henning Kamp 269f6bde1fdSPoul-Henning Kamp #else 270f6bde1fdSPoul-Henning Kamp 271f6bde1fdSPoul-Henning Kamp static __inline void 2728907f744SAlan Somers check_unrhdr(struct unrhdr *uh __unused, int line __unused) 273f6bde1fdSPoul-Henning Kamp { 274f6bde1fdSPoul-Henning Kamp 275f6bde1fdSPoul-Henning Kamp } 276f6bde1fdSPoul-Henning Kamp 277f6bde1fdSPoul-Henning Kamp #endif 278f6bde1fdSPoul-Henning Kamp 279f6bde1fdSPoul-Henning Kamp /* 280f6bde1fdSPoul-Henning Kamp * Userland memory management. Just use calloc and keep track of how 281f6bde1fdSPoul-Henning Kamp * many elements we have allocated for check_unrhdr(). 282f6bde1fdSPoul-Henning Kamp */ 283f6bde1fdSPoul-Henning Kamp 284f6bde1fdSPoul-Henning Kamp static __inline void * 285d9a54d5cSPoul-Henning Kamp new_unr(struct unrhdr *uh, void **p1, void **p2) 286f6bde1fdSPoul-Henning Kamp { 287d9a54d5cSPoul-Henning Kamp void *p; 288f6bde1fdSPoul-Henning Kamp 289d9a54d5cSPoul-Henning Kamp uh->alloc++; 290d9a54d5cSPoul-Henning Kamp KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory")); 291d9a54d5cSPoul-Henning Kamp if (*p1 != NULL) { 292d9a54d5cSPoul-Henning Kamp p = *p1; 293d9a54d5cSPoul-Henning Kamp *p1 = NULL; 294d9a54d5cSPoul-Henning Kamp return (p); 295d9a54d5cSPoul-Henning Kamp } else { 296d9a54d5cSPoul-Henning Kamp p = *p2; 297d9a54d5cSPoul-Henning Kamp *p2 = NULL; 298d9a54d5cSPoul-Henning Kamp return (p); 299d9a54d5cSPoul-Henning Kamp } 300f6bde1fdSPoul-Henning Kamp } 301f6bde1fdSPoul-Henning Kamp 302f6bde1fdSPoul-Henning Kamp static __inline void 303f6bde1fdSPoul-Henning Kamp delete_unr(struct unrhdr *uh, void *ptr) 304f6bde1fdSPoul-Henning Kamp { 30509828ba9SKonstantin Belousov struct unr *up; 306d9a54d5cSPoul-Henning Kamp 307f6bde1fdSPoul-Henning Kamp uh->alloc--; 30809828ba9SKonstantin Belousov up = ptr; 30909828ba9SKonstantin Belousov TAILQ_INSERT_TAIL(&uh->ppfree, up, list); 31009828ba9SKonstantin Belousov } 31109828ba9SKonstantin Belousov 31209828ba9SKonstantin Belousov void 31309828ba9SKonstantin Belousov clean_unrhdrl(struct unrhdr *uh) 31409828ba9SKonstantin Belousov { 31509828ba9SKonstantin Belousov struct unr *up; 31609828ba9SKonstantin Belousov 317e59b940dSKonstantin Belousov if (uh->mtx != NULL) 31809828ba9SKonstantin Belousov mtx_assert(uh->mtx, MA_OWNED); 31909828ba9SKonstantin Belousov while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) { 32009828ba9SKonstantin Belousov TAILQ_REMOVE(&uh->ppfree, up, list); 321e59b940dSKonstantin Belousov if (uh->mtx != NULL) 32209828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 32309828ba9SKonstantin Belousov Free(up); 324e59b940dSKonstantin Belousov if (uh->mtx != NULL) 32509828ba9SKonstantin Belousov mtx_lock(uh->mtx); 32609828ba9SKonstantin Belousov } 32709828ba9SKonstantin Belousov 32809828ba9SKonstantin Belousov } 32909828ba9SKonstantin Belousov 33009828ba9SKonstantin Belousov void 33109828ba9SKonstantin Belousov clean_unrhdr(struct unrhdr *uh) 33209828ba9SKonstantin Belousov { 33309828ba9SKonstantin Belousov 334e59b940dSKonstantin Belousov if (uh->mtx != NULL) 33509828ba9SKonstantin Belousov mtx_lock(uh->mtx); 33609828ba9SKonstantin Belousov clean_unrhdrl(uh); 337e59b940dSKonstantin Belousov if (uh->mtx != NULL) 33809828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 339f6bde1fdSPoul-Henning Kamp } 340f6bde1fdSPoul-Henning Kamp 341dc872d46SKonstantin Belousov void 342dc872d46SKonstantin Belousov init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex) 343f6bde1fdSPoul-Henning Kamp { 344f6bde1fdSPoul-Henning Kamp 345831aa555SJaakko Heinonen KASSERT(low >= 0 && low <= high, 346501812f2SJaakko Heinonen ("UNR: use error: new_unrhdr(%d, %d)", low, high)); 347e59b940dSKonstantin Belousov if (mutex == UNR_NO_MTX) 348e59b940dSKonstantin Belousov uh->mtx = NULL; 349e59b940dSKonstantin Belousov else if (mutex != NULL) 350d9a54d5cSPoul-Henning Kamp uh->mtx = mutex; 351d9a54d5cSPoul-Henning Kamp else 352d9a54d5cSPoul-Henning Kamp uh->mtx = &unitmtx; 353f6bde1fdSPoul-Henning Kamp TAILQ_INIT(&uh->head); 35409828ba9SKonstantin Belousov TAILQ_INIT(&uh->ppfree); 355f6bde1fdSPoul-Henning Kamp uh->low = low; 356f6bde1fdSPoul-Henning Kamp uh->high = high; 357d9a54d5cSPoul-Henning Kamp uh->first = 0; 358d9a54d5cSPoul-Henning Kamp uh->last = 1 + (high - low); 359c4be460eSKonstantin Belousov uh->busy = 0; 360c4be460eSKonstantin Belousov uh->alloc = 0; 361f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 362dc872d46SKonstantin Belousov } 363dc872d46SKonstantin Belousov 364dc872d46SKonstantin Belousov /* 365dc872d46SKonstantin Belousov * Allocate a new unrheader set. 366dc872d46SKonstantin Belousov * 367dc872d46SKonstantin Belousov * Highest and lowest valid values given as parameters. 368dc872d46SKonstantin Belousov */ 369dc872d46SKonstantin Belousov 370dc872d46SKonstantin Belousov struct unrhdr * 371dc872d46SKonstantin Belousov new_unrhdr(int low, int high, struct mtx *mutex) 372dc872d46SKonstantin Belousov { 373dc872d46SKonstantin Belousov struct unrhdr *uh; 374dc872d46SKonstantin Belousov 375dc872d46SKonstantin Belousov uh = Malloc(sizeof *uh); 376dc872d46SKonstantin Belousov init_unrhdr(uh, low, high, mutex); 377f6bde1fdSPoul-Henning Kamp return (uh); 378f6bde1fdSPoul-Henning Kamp } 379f6bde1fdSPoul-Henning Kamp 380e4fea39eSPoul-Henning Kamp void 381e4fea39eSPoul-Henning Kamp delete_unrhdr(struct unrhdr *uh) 382e4fea39eSPoul-Henning Kamp { 383e4fea39eSPoul-Henning Kamp 384d9a54d5cSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 385e4fea39eSPoul-Henning Kamp KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy)); 386e4fea39eSPoul-Henning Kamp KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr")); 38709828ba9SKonstantin Belousov KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL, 38809828ba9SKonstantin Belousov ("unrhdr has postponed item for free")); 389e4fea39eSPoul-Henning Kamp Free(uh); 390e4fea39eSPoul-Henning Kamp } 391e4fea39eSPoul-Henning Kamp 392333dcaa4SMatt Joras void 393333dcaa4SMatt Joras clear_unrhdr(struct unrhdr *uh) 394333dcaa4SMatt Joras { 395333dcaa4SMatt Joras struct unr *up, *uq; 396333dcaa4SMatt Joras 397333dcaa4SMatt Joras KASSERT(TAILQ_EMPTY(&uh->ppfree), 398333dcaa4SMatt Joras ("unrhdr has postponed item for free")); 3990d8e0405SMatt Joras TAILQ_FOREACH_SAFE(up, &uh->head, list, uq) { 400333dcaa4SMatt Joras if (up->ptr != uh) { 401333dcaa4SMatt Joras Free(up->ptr); 402333dcaa4SMatt Joras } 403333dcaa4SMatt Joras Free(up); 404333dcaa4SMatt Joras } 405333dcaa4SMatt Joras uh->busy = 0; 406333dcaa4SMatt Joras uh->alloc = 0; 4070d8e0405SMatt Joras init_unrhdr(uh, uh->low, uh->high, uh->mtx); 4080d8e0405SMatt Joras 4090d8e0405SMatt Joras check_unrhdr(uh, __LINE__); 410333dcaa4SMatt Joras } 411333dcaa4SMatt Joras 412d9a54d5cSPoul-Henning Kamp static __inline int 413d9a54d5cSPoul-Henning Kamp is_bitmap(struct unrhdr *uh, struct unr *up) 414d9a54d5cSPoul-Henning Kamp { 415d9a54d5cSPoul-Henning Kamp return (up->ptr != uh && up->ptr != NULL); 416d9a54d5cSPoul-Henning Kamp } 417d9a54d5cSPoul-Henning Kamp 418f6bde1fdSPoul-Henning Kamp /* 419d9a54d5cSPoul-Henning Kamp * Look for sequence of items which can be combined into a bitmap, if 420d9a54d5cSPoul-Henning Kamp * multiple are present, take the one which saves most memory. 421d9a54d5cSPoul-Henning Kamp * 422d9a54d5cSPoul-Henning Kamp * Return (1) if a sequence was found to indicate that another call 423d9a54d5cSPoul-Henning Kamp * might be able to do more. Return (0) if we found no suitable sequence. 424d9a54d5cSPoul-Henning Kamp * 425d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 426d9a54d5cSPoul-Henning Kamp */ 427d9a54d5cSPoul-Henning Kamp static int 428d9a54d5cSPoul-Henning Kamp optimize_unr(struct unrhdr *uh) 429d9a54d5cSPoul-Henning Kamp { 430d9a54d5cSPoul-Henning Kamp struct unr *up, *uf, *us; 431d9a54d5cSPoul-Henning Kamp struct unrb *ub, *ubf; 432d9a54d5cSPoul-Henning Kamp u_int a, l, ba; 433d9a54d5cSPoul-Henning Kamp 434d9a54d5cSPoul-Henning Kamp /* 435d9a54d5cSPoul-Henning Kamp * Look for the run of items (if any) which when collapsed into 436d9a54d5cSPoul-Henning Kamp * a bitmap would save most memory. 437d9a54d5cSPoul-Henning Kamp */ 438d9a54d5cSPoul-Henning Kamp us = NULL; 439d9a54d5cSPoul-Henning Kamp ba = 0; 440d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(uf, &uh->head, list) { 441d9a54d5cSPoul-Henning Kamp if (uf->len >= NBITS) 442d9a54d5cSPoul-Henning Kamp continue; 443d9a54d5cSPoul-Henning Kamp a = 1; 444d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, uf)) 445d9a54d5cSPoul-Henning Kamp a++; 446d9a54d5cSPoul-Henning Kamp l = uf->len; 447d9a54d5cSPoul-Henning Kamp up = uf; 448d9a54d5cSPoul-Henning Kamp while (1) { 449d9a54d5cSPoul-Henning Kamp up = TAILQ_NEXT(up, list); 450d9a54d5cSPoul-Henning Kamp if (up == NULL) 451d9a54d5cSPoul-Henning Kamp break; 452d9a54d5cSPoul-Henning Kamp if ((up->len + l) > NBITS) 453d9a54d5cSPoul-Henning Kamp break; 454d9a54d5cSPoul-Henning Kamp a++; 455d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) 456d9a54d5cSPoul-Henning Kamp a++; 457d9a54d5cSPoul-Henning Kamp l += up->len; 458d9a54d5cSPoul-Henning Kamp } 459d9a54d5cSPoul-Henning Kamp if (a > ba) { 460d9a54d5cSPoul-Henning Kamp ba = a; 461d9a54d5cSPoul-Henning Kamp us = uf; 462d9a54d5cSPoul-Henning Kamp } 463d9a54d5cSPoul-Henning Kamp } 464d9a54d5cSPoul-Henning Kamp if (ba < 3) 465d9a54d5cSPoul-Henning Kamp return (0); 466d9a54d5cSPoul-Henning Kamp 467d9a54d5cSPoul-Henning Kamp /* 468d9a54d5cSPoul-Henning Kamp * If the first element is not a bitmap, make it one. 469d9a54d5cSPoul-Henning Kamp * Trying to do so without allocating more memory complicates things 470d9a54d5cSPoul-Henning Kamp * a bit 471d9a54d5cSPoul-Henning Kamp */ 472d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, us)) { 473d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 474d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, us, list); 475d9a54d5cSPoul-Henning Kamp a = us->len; 476d9a54d5cSPoul-Henning Kamp l = us->ptr == uh ? 1 : 0; 477d9a54d5cSPoul-Henning Kamp ub = (void *)us; 4788907f744SAlan Somers bit_nclear(ub->map, 0, NBITS - 1); 4798907f744SAlan Somers if (l) 480d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, 0, a); 481d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, uf)) { 4828907f744SAlan Somers if (uf->ptr == NULL) 483d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, a, a + uf->len - 1); 4848907f744SAlan Somers else 485d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, a, a + uf->len - 1); 486d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 487d9a54d5cSPoul-Henning Kamp uf->len += a; 488d9a54d5cSPoul-Henning Kamp us = uf; 489d9a54d5cSPoul-Henning Kamp } else { 490d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 491d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, a++) { 4928907f744SAlan Somers if (bit_test(ubf->map, l)) 493d9a54d5cSPoul-Henning Kamp bit_set(ub->map, a); 4948907f744SAlan Somers else 495d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, a); 496d9a54d5cSPoul-Henning Kamp } 497d9a54d5cSPoul-Henning Kamp uf->len = a; 498d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf->ptr); 499d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 500d9a54d5cSPoul-Henning Kamp us = uf; 501d9a54d5cSPoul-Henning Kamp } 502d9a54d5cSPoul-Henning Kamp } 503d9a54d5cSPoul-Henning Kamp ub = us->ptr; 504d9a54d5cSPoul-Henning Kamp while (1) { 505d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 506d9a54d5cSPoul-Henning Kamp if (uf == NULL) 507d9a54d5cSPoul-Henning Kamp return (1); 508d9a54d5cSPoul-Henning Kamp if (uf->len + us->len > NBITS) 509d9a54d5cSPoul-Henning Kamp return (1); 510d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 511d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, us->len, us->len + uf->len - 1); 512d9a54d5cSPoul-Henning Kamp us->len += uf->len; 513d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 514d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 515d9a54d5cSPoul-Henning Kamp } else if (uf->ptr == uh) { 516d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, us->len, us->len + uf->len - 1); 517d9a54d5cSPoul-Henning Kamp us->len += uf->len; 518d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 519d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 520d9a54d5cSPoul-Henning Kamp } else { 521d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 522d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, us->len++) { 5238907f744SAlan Somers if (bit_test(ubf->map, l)) 524d9a54d5cSPoul-Henning Kamp bit_set(ub->map, us->len); 5258907f744SAlan Somers else 526d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, us->len); 527d9a54d5cSPoul-Henning Kamp } 528d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 529d9a54d5cSPoul-Henning Kamp delete_unr(uh, ubf); 530d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 531d9a54d5cSPoul-Henning Kamp } 532d9a54d5cSPoul-Henning Kamp } 533d9a54d5cSPoul-Henning Kamp } 534d9a54d5cSPoul-Henning Kamp 535d9a54d5cSPoul-Henning Kamp /* 536d9a54d5cSPoul-Henning Kamp * See if a given unr should be collapsed with a neighbor. 537d9a54d5cSPoul-Henning Kamp * 538d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 539f6bde1fdSPoul-Henning Kamp */ 540f6bde1fdSPoul-Henning Kamp static void 541f6bde1fdSPoul-Henning Kamp collapse_unr(struct unrhdr *uh, struct unr *up) 542f6bde1fdSPoul-Henning Kamp { 543f6bde1fdSPoul-Henning Kamp struct unr *upp; 544d9a54d5cSPoul-Henning Kamp struct unrb *ub; 545f6bde1fdSPoul-Henning Kamp 546d9a54d5cSPoul-Henning Kamp /* If bitmap is all set or clear, change it to runlength */ 547d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 548d9a54d5cSPoul-Henning Kamp ub = up->ptr; 5498907f744SAlan Somers if (ub_full(ub, up->len)) { 550d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 551d9a54d5cSPoul-Henning Kamp up->ptr = uh; 5528907f744SAlan Somers } else if (ub_empty(ub, up->len)) { 553d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 554d9a54d5cSPoul-Henning Kamp up->ptr = NULL; 555d9a54d5cSPoul-Henning Kamp } 556d9a54d5cSPoul-Henning Kamp } 557d9a54d5cSPoul-Henning Kamp 558d9a54d5cSPoul-Henning Kamp /* If nothing left in runlength, delete it */ 559d9a54d5cSPoul-Henning Kamp if (up->len == 0) { 560d9a54d5cSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 561d9a54d5cSPoul-Henning Kamp if (upp == NULL) 562d9a54d5cSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 563d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, up, list); 564d9a54d5cSPoul-Henning Kamp delete_unr(uh, up); 565d9a54d5cSPoul-Henning Kamp up = upp; 566d9a54d5cSPoul-Henning Kamp } 567d9a54d5cSPoul-Henning Kamp 568d9a54d5cSPoul-Henning Kamp /* If we have "hot-spot" still, merge with neighbor if possible */ 569d9a54d5cSPoul-Henning Kamp if (up != NULL) { 570f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 571f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 572f6bde1fdSPoul-Henning Kamp up->len += upp->len; 573f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 574f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 575f6bde1fdSPoul-Henning Kamp } 576f6bde1fdSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 577f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 578f6bde1fdSPoul-Henning Kamp up->len += upp->len; 579f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 580f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 581f6bde1fdSPoul-Henning Kamp } 582f6bde1fdSPoul-Henning Kamp } 583f6bde1fdSPoul-Henning Kamp 584d9a54d5cSPoul-Henning Kamp /* Merge into ->first if possible */ 585d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 586d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == uh) { 587d9a54d5cSPoul-Henning Kamp uh->first += upp->len; 588d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 589d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 590d9a54d5cSPoul-Henning Kamp if (up == upp) 591d9a54d5cSPoul-Henning Kamp up = NULL; 592d9a54d5cSPoul-Henning Kamp } 593d9a54d5cSPoul-Henning Kamp 594d9a54d5cSPoul-Henning Kamp /* Merge into ->last if possible */ 595d9a54d5cSPoul-Henning Kamp upp = TAILQ_LAST(&uh->head, unrhd); 596d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == NULL) { 597d9a54d5cSPoul-Henning Kamp uh->last += upp->len; 598d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 599d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 600d9a54d5cSPoul-Henning Kamp if (up == upp) 601d9a54d5cSPoul-Henning Kamp up = NULL; 602d9a54d5cSPoul-Henning Kamp } 603d9a54d5cSPoul-Henning Kamp 604d9a54d5cSPoul-Henning Kamp /* Try to make bitmaps */ 605d9a54d5cSPoul-Henning Kamp while (optimize_unr(uh)) 606d9a54d5cSPoul-Henning Kamp continue; 607d9a54d5cSPoul-Henning Kamp } 608d9a54d5cSPoul-Henning Kamp 609f6bde1fdSPoul-Henning Kamp /* 610f6bde1fdSPoul-Henning Kamp * Allocate a free unr. 611f6bde1fdSPoul-Henning Kamp */ 612d9a54d5cSPoul-Henning Kamp int 613d9a54d5cSPoul-Henning Kamp alloc_unrl(struct unrhdr *uh) 614f6bde1fdSPoul-Henning Kamp { 615d9a54d5cSPoul-Henning Kamp struct unr *up; 616d9a54d5cSPoul-Henning Kamp struct unrb *ub; 617f6bde1fdSPoul-Henning Kamp u_int x; 618f6bde1fdSPoul-Henning Kamp int y; 619f6bde1fdSPoul-Henning Kamp 620e59b940dSKonstantin Belousov if (uh->mtx != NULL) 621d9a54d5cSPoul-Henning Kamp mtx_assert(uh->mtx, MA_OWNED); 622f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 623d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 624d9a54d5cSPoul-Henning Kamp 625f6bde1fdSPoul-Henning Kamp up = TAILQ_FIRST(&uh->head); 626f6bde1fdSPoul-Henning Kamp 627d9a54d5cSPoul-Henning Kamp /* 628d9a54d5cSPoul-Henning Kamp * If we have an ideal split, just adjust the first+last 629d9a54d5cSPoul-Henning Kamp */ 630d9a54d5cSPoul-Henning Kamp if (up == NULL && uh->last > 0) { 631d9a54d5cSPoul-Henning Kamp uh->first++; 632d9a54d5cSPoul-Henning Kamp uh->last--; 633f6bde1fdSPoul-Henning Kamp uh->busy++; 634f6bde1fdSPoul-Henning Kamp return (x); 635f6bde1fdSPoul-Henning Kamp } 636f6bde1fdSPoul-Henning Kamp 637f6bde1fdSPoul-Henning Kamp /* 638d9a54d5cSPoul-Henning Kamp * We can always allocate from the first list element, so if we have 639d9a54d5cSPoul-Henning Kamp * nothing on the list, we must have run out of unit numbers. 640f6bde1fdSPoul-Henning Kamp */ 64193f6c81eSPoul-Henning Kamp if (up == NULL) 642d9a54d5cSPoul-Henning Kamp return (-1); 643d9a54d5cSPoul-Henning Kamp 644d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr != uh, ("UNR first element is allocated")); 645d9a54d5cSPoul-Henning Kamp 646d9a54d5cSPoul-Henning Kamp if (up->ptr == NULL) { /* free run */ 647d9a54d5cSPoul-Henning Kamp uh->first++; 648f6bde1fdSPoul-Henning Kamp up->len--; 649d9a54d5cSPoul-Henning Kamp } else { /* bitmap */ 650d9a54d5cSPoul-Henning Kamp ub = up->ptr; 651d9a54d5cSPoul-Henning Kamp bit_ffc(ub->map, up->len, &y); 652d9a54d5cSPoul-Henning Kamp KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); 653d9a54d5cSPoul-Henning Kamp bit_set(ub->map, y); 654d9a54d5cSPoul-Henning Kamp x += y; 655d9a54d5cSPoul-Henning Kamp } 656f6bde1fdSPoul-Henning Kamp uh->busy++; 657d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 658f6bde1fdSPoul-Henning Kamp return (x); 659f6bde1fdSPoul-Henning Kamp } 660f6bde1fdSPoul-Henning Kamp 661d9a54d5cSPoul-Henning Kamp int 662d9a54d5cSPoul-Henning Kamp alloc_unr(struct unrhdr *uh) 663d9a54d5cSPoul-Henning Kamp { 664d9a54d5cSPoul-Henning Kamp int i; 665d9a54d5cSPoul-Henning Kamp 666e59b940dSKonstantin Belousov if (uh->mtx != NULL) 667d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 668d9a54d5cSPoul-Henning Kamp i = alloc_unrl(uh); 66909828ba9SKonstantin Belousov clean_unrhdrl(uh); 670e59b940dSKonstantin Belousov if (uh->mtx != NULL) 671d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 672d9a54d5cSPoul-Henning Kamp return (i); 673d9a54d5cSPoul-Henning Kamp } 674d9a54d5cSPoul-Henning Kamp 67513c02cbbSJaakko Heinonen static int 67613c02cbbSJaakko Heinonen alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2) 67713c02cbbSJaakko Heinonen { 67813c02cbbSJaakko Heinonen struct unr *up, *upn; 67913c02cbbSJaakko Heinonen struct unrb *ub; 68013c02cbbSJaakko Heinonen u_int i, last, tl; 68113c02cbbSJaakko Heinonen 682e59b940dSKonstantin Belousov if (uh->mtx != NULL) 68313c02cbbSJaakko Heinonen mtx_assert(uh->mtx, MA_OWNED); 68413c02cbbSJaakko Heinonen 68513c02cbbSJaakko Heinonen if (item < uh->low + uh->first || item > uh->high) 68613c02cbbSJaakko Heinonen return (-1); 68713c02cbbSJaakko Heinonen 68813c02cbbSJaakko Heinonen up = TAILQ_FIRST(&uh->head); 68913c02cbbSJaakko Heinonen /* Ideal split. */ 69013c02cbbSJaakko Heinonen if (up == NULL && item - uh->low == uh->first) { 69113c02cbbSJaakko Heinonen uh->first++; 69213c02cbbSJaakko Heinonen uh->last--; 69313c02cbbSJaakko Heinonen uh->busy++; 69413c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 69513c02cbbSJaakko Heinonen return (item); 69613c02cbbSJaakko Heinonen } 69713c02cbbSJaakko Heinonen 69813c02cbbSJaakko Heinonen i = item - uh->low - uh->first; 69913c02cbbSJaakko Heinonen 70013c02cbbSJaakko Heinonen if (up == NULL) { 70113c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 70213c02cbbSJaakko Heinonen up->ptr = NULL; 70313c02cbbSJaakko Heinonen up->len = i; 70413c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 70513c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 70613c02cbbSJaakko Heinonen up->ptr = uh; 70713c02cbbSJaakko Heinonen up->len = 1; 70813c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 70913c02cbbSJaakko Heinonen uh->last = uh->high - uh->low - i; 71013c02cbbSJaakko Heinonen uh->busy++; 71113c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 71213c02cbbSJaakko Heinonen return (item); 71313c02cbbSJaakko Heinonen } else { 71413c02cbbSJaakko Heinonen /* Find the item which contains the unit we want to allocate. */ 71513c02cbbSJaakko Heinonen TAILQ_FOREACH(up, &uh->head, list) { 71613c02cbbSJaakko Heinonen if (up->len > i) 71713c02cbbSJaakko Heinonen break; 71813c02cbbSJaakko Heinonen i -= up->len; 71913c02cbbSJaakko Heinonen } 72013c02cbbSJaakko Heinonen } 72113c02cbbSJaakko Heinonen 72213c02cbbSJaakko Heinonen if (up == NULL) { 72313c02cbbSJaakko Heinonen if (i > 0) { 72413c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 72513c02cbbSJaakko Heinonen up->ptr = NULL; 72613c02cbbSJaakko Heinonen up->len = i; 72713c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 72813c02cbbSJaakko Heinonen } 72913c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 73013c02cbbSJaakko Heinonen up->ptr = uh; 73113c02cbbSJaakko Heinonen up->len = 1; 73213c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 73313c02cbbSJaakko Heinonen goto done; 73413c02cbbSJaakko Heinonen } 73513c02cbbSJaakko Heinonen 73613c02cbbSJaakko Heinonen if (is_bitmap(uh, up)) { 73713c02cbbSJaakko Heinonen ub = up->ptr; 73813c02cbbSJaakko Heinonen if (bit_test(ub->map, i) == 0) { 73913c02cbbSJaakko Heinonen bit_set(ub->map, i); 74013c02cbbSJaakko Heinonen goto done; 74113c02cbbSJaakko Heinonen } else 74213c02cbbSJaakko Heinonen return (-1); 74313c02cbbSJaakko Heinonen } else if (up->ptr == uh) 74413c02cbbSJaakko Heinonen return (-1); 74513c02cbbSJaakko Heinonen 74613c02cbbSJaakko Heinonen KASSERT(up->ptr == NULL, 74713c02cbbSJaakko Heinonen ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up)); 74813c02cbbSJaakko Heinonen 74913c02cbbSJaakko Heinonen /* Split off the tail end, if any. */ 75013c02cbbSJaakko Heinonen tl = up->len - (1 + i); 75113c02cbbSJaakko Heinonen if (tl > 0) { 75213c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 75313c02cbbSJaakko Heinonen upn->ptr = NULL; 75413c02cbbSJaakko Heinonen upn->len = tl; 75513c02cbbSJaakko Heinonen TAILQ_INSERT_AFTER(&uh->head, up, upn, list); 75613c02cbbSJaakko Heinonen } 75713c02cbbSJaakko Heinonen 75813c02cbbSJaakko Heinonen /* Split off head end, if any */ 75913c02cbbSJaakko Heinonen if (i > 0) { 76013c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 76113c02cbbSJaakko Heinonen upn->len = i; 76213c02cbbSJaakko Heinonen upn->ptr = NULL; 76313c02cbbSJaakko Heinonen TAILQ_INSERT_BEFORE(up, upn, list); 76413c02cbbSJaakko Heinonen } 76513c02cbbSJaakko Heinonen up->len = 1; 76613c02cbbSJaakko Heinonen up->ptr = uh; 76713c02cbbSJaakko Heinonen 76813c02cbbSJaakko Heinonen done: 76913c02cbbSJaakko Heinonen last = uh->high - uh->low - (item - uh->low); 77013c02cbbSJaakko Heinonen if (uh->last > last) 77113c02cbbSJaakko Heinonen uh->last = last; 77213c02cbbSJaakko Heinonen uh->busy++; 77313c02cbbSJaakko Heinonen collapse_unr(uh, up); 77413c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 77513c02cbbSJaakko Heinonen return (item); 77613c02cbbSJaakko Heinonen } 77713c02cbbSJaakko Heinonen 77813c02cbbSJaakko Heinonen int 77913c02cbbSJaakko Heinonen alloc_unr_specific(struct unrhdr *uh, u_int item) 78013c02cbbSJaakko Heinonen { 78113c02cbbSJaakko Heinonen void *p1, *p2; 78213c02cbbSJaakko Heinonen int i; 78313c02cbbSJaakko Heinonen 78413c02cbbSJaakko Heinonen WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific"); 78513c02cbbSJaakko Heinonen 78613c02cbbSJaakko Heinonen p1 = Malloc(sizeof(struct unr)); 78713c02cbbSJaakko Heinonen p2 = Malloc(sizeof(struct unr)); 78813c02cbbSJaakko Heinonen 789e59b940dSKonstantin Belousov if (uh->mtx != NULL) 79013c02cbbSJaakko Heinonen mtx_lock(uh->mtx); 79113c02cbbSJaakko Heinonen i = alloc_unr_specificl(uh, item, &p1, &p2); 792e59b940dSKonstantin Belousov if (uh->mtx != NULL) 79313c02cbbSJaakko Heinonen mtx_unlock(uh->mtx); 79413c02cbbSJaakko Heinonen 79513c02cbbSJaakko Heinonen if (p1 != NULL) 79613c02cbbSJaakko Heinonen Free(p1); 79713c02cbbSJaakko Heinonen if (p2 != NULL) 79813c02cbbSJaakko Heinonen Free(p2); 79913c02cbbSJaakko Heinonen 80013c02cbbSJaakko Heinonen return (i); 80113c02cbbSJaakko Heinonen } 80213c02cbbSJaakko Heinonen 803f6bde1fdSPoul-Henning Kamp /* 804f6bde1fdSPoul-Henning Kamp * Free a unr. 805f6bde1fdSPoul-Henning Kamp * 806f6bde1fdSPoul-Henning Kamp * If we can save unrs by using a bitmap, do so. 807f6bde1fdSPoul-Henning Kamp */ 808d9a54d5cSPoul-Henning Kamp static void 809d9a54d5cSPoul-Henning Kamp free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2) 810f6bde1fdSPoul-Henning Kamp { 811d9a54d5cSPoul-Henning Kamp struct unr *up, *upp, *upn; 812d9a54d5cSPoul-Henning Kamp struct unrb *ub; 813d9a54d5cSPoul-Henning Kamp u_int pl; 814f6bde1fdSPoul-Henning Kamp 815f6bde1fdSPoul-Henning Kamp KASSERT(item >= uh->low && item <= uh->high, 816f6bde1fdSPoul-Henning Kamp ("UNR: free_unr(%u) out of range [%u...%u]", 817f6bde1fdSPoul-Henning Kamp item, uh->low, uh->high)); 818f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 819f6bde1fdSPoul-Henning Kamp item -= uh->low; 820d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 821f6bde1fdSPoul-Henning Kamp /* 822d9a54d5cSPoul-Henning Kamp * Freeing in the ideal split case 823f6bde1fdSPoul-Henning Kamp */ 824d9a54d5cSPoul-Henning Kamp if (item + 1 == uh->first && upp == NULL) { 825d9a54d5cSPoul-Henning Kamp uh->last++; 826d9a54d5cSPoul-Henning Kamp uh->first--; 827d9a54d5cSPoul-Henning Kamp uh->busy--; 828f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 829f6bde1fdSPoul-Henning Kamp return; 830f6bde1fdSPoul-Henning Kamp } 831d9a54d5cSPoul-Henning Kamp /* 832d9a54d5cSPoul-Henning Kamp * Freeing in the ->first section. Create a run starting at the 833d9a54d5cSPoul-Henning Kamp * freed item. The code below will subdivide it. 834d9a54d5cSPoul-Henning Kamp */ 835d9a54d5cSPoul-Henning Kamp if (item < uh->first) { 836d9a54d5cSPoul-Henning Kamp up = new_unr(uh, p1, p2); 837d9a54d5cSPoul-Henning Kamp up->ptr = uh; 838d9a54d5cSPoul-Henning Kamp up->len = uh->first - item; 839d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_HEAD(&uh->head, up, list); 840d9a54d5cSPoul-Henning Kamp uh->first -= up->len; 841f6bde1fdSPoul-Henning Kamp } 842f6bde1fdSPoul-Henning Kamp 843d9a54d5cSPoul-Henning Kamp item -= uh->first; 844d9a54d5cSPoul-Henning Kamp 845d9a54d5cSPoul-Henning Kamp /* Find the item which contains the unit we want to free */ 846d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 847d9a54d5cSPoul-Henning Kamp if (up->len > item) 848d9a54d5cSPoul-Henning Kamp break; 849d9a54d5cSPoul-Henning Kamp item -= up->len; 850d9a54d5cSPoul-Henning Kamp } 851d9a54d5cSPoul-Henning Kamp 852d9a54d5cSPoul-Henning Kamp /* Handle bitmap items */ 853d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 854d9a54d5cSPoul-Henning Kamp ub = up->ptr; 855d9a54d5cSPoul-Henning Kamp 856d9a54d5cSPoul-Henning Kamp KASSERT(bit_test(ub->map, item) != 0, 857d9a54d5cSPoul-Henning Kamp ("UNR: Freeing free item %d (bitmap)\n", item)); 858d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, item); 859d9a54d5cSPoul-Henning Kamp uh->busy--; 860d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 861d9a54d5cSPoul-Henning Kamp return; 862d9a54d5cSPoul-Henning Kamp } 863d9a54d5cSPoul-Henning Kamp 864d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item)); 865f6bde1fdSPoul-Henning Kamp 866f6bde1fdSPoul-Henning Kamp /* Just this one left, reap it */ 867f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 868f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 869f6bde1fdSPoul-Henning Kamp uh->busy--; 870f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 871f6bde1fdSPoul-Henning Kamp return; 872f6bde1fdSPoul-Henning Kamp } 873f6bde1fdSPoul-Henning Kamp 874d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item into the previous 'free' run */ 875f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 876d9a54d5cSPoul-Henning Kamp if (item == 0 && upp != NULL && upp->ptr == NULL) { 877f6bde1fdSPoul-Henning Kamp upp->len++; 878f6bde1fdSPoul-Henning Kamp up->len--; 879f6bde1fdSPoul-Henning Kamp uh->busy--; 880d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 881f6bde1fdSPoul-Henning Kamp return; 882f6bde1fdSPoul-Henning Kamp } 883f6bde1fdSPoul-Henning Kamp 884d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item to the next 'free' run */ 885f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(up, list); 886d9a54d5cSPoul-Henning Kamp if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) { 887f6bde1fdSPoul-Henning Kamp upn->len++; 888f6bde1fdSPoul-Henning Kamp up->len--; 889f6bde1fdSPoul-Henning Kamp uh->busy--; 890d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 891f6bde1fdSPoul-Henning Kamp return; 892f6bde1fdSPoul-Henning Kamp } 893f6bde1fdSPoul-Henning Kamp 894f6bde1fdSPoul-Henning Kamp /* Split off the tail end, if any. */ 895d9a54d5cSPoul-Henning Kamp pl = up->len - (1 + item); 896f6bde1fdSPoul-Henning Kamp if (pl > 0) { 897d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 898f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 899f6bde1fdSPoul-Henning Kamp upp->len = pl; 900f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 901f6bde1fdSPoul-Henning Kamp } 902f6bde1fdSPoul-Henning Kamp 903d9a54d5cSPoul-Henning Kamp /* Split off head end, if any */ 904d9a54d5cSPoul-Henning Kamp if (item > 0) { 905d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 906d9a54d5cSPoul-Henning Kamp upp->len = item; 907d9a54d5cSPoul-Henning Kamp upp->ptr = uh; 908d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_BEFORE(up, upp, list); 909d9a54d5cSPoul-Henning Kamp } 910f6bde1fdSPoul-Henning Kamp up->len = 1; 911f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 912f6bde1fdSPoul-Henning Kamp uh->busy--; 913d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 914f6bde1fdSPoul-Henning Kamp } 915f6bde1fdSPoul-Henning Kamp 916d9a54d5cSPoul-Henning Kamp void 917d9a54d5cSPoul-Henning Kamp free_unr(struct unrhdr *uh, u_int item) 918d9a54d5cSPoul-Henning Kamp { 919d9a54d5cSPoul-Henning Kamp void *p1, *p2; 920f6bde1fdSPoul-Henning Kamp 9217550e3eaSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr"); 922d9a54d5cSPoul-Henning Kamp p1 = Malloc(sizeof(struct unr)); 923d9a54d5cSPoul-Henning Kamp p2 = Malloc(sizeof(struct unr)); 924e59b940dSKonstantin Belousov if (uh->mtx != NULL) 925d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 926d9a54d5cSPoul-Henning Kamp free_unrl(uh, item, &p1, &p2); 92709828ba9SKonstantin Belousov clean_unrhdrl(uh); 928e59b940dSKonstantin Belousov if (uh->mtx != NULL) 929d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 930d9a54d5cSPoul-Henning Kamp if (p1 != NULL) 931d9a54d5cSPoul-Henning Kamp Free(p1); 932d9a54d5cSPoul-Henning Kamp if (p2 != NULL) 933d9a54d5cSPoul-Henning Kamp Free(p2); 934f6bde1fdSPoul-Henning Kamp } 935f6bde1fdSPoul-Henning Kamp 93693f6c81eSPoul-Henning Kamp #ifndef _KERNEL /* USERLAND test driver */ 93793f6c81eSPoul-Henning Kamp 938f6bde1fdSPoul-Henning Kamp /* 939794277daSAlan Somers * Simple stochastic test driver for the above functions. The code resides 940794277daSAlan Somers * here so that it can access static functions and structures. 941f6bde1fdSPoul-Henning Kamp */ 942f6bde1fdSPoul-Henning Kamp 943794277daSAlan Somers static bool verbose; 944794277daSAlan Somers #define VPRINTF(...) {if (verbose) printf(__VA_ARGS__);} 945794277daSAlan Somers 946f6bde1fdSPoul-Henning Kamp static void 947f6bde1fdSPoul-Henning Kamp print_unr(struct unrhdr *uh, struct unr *up) 948f6bde1fdSPoul-Henning Kamp { 949f6bde1fdSPoul-Henning Kamp u_int x; 950d9a54d5cSPoul-Henning Kamp struct unrb *ub; 951f6bde1fdSPoul-Henning Kamp 952f6bde1fdSPoul-Henning Kamp printf(" %p len = %5u ", up, up->len); 953f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL) 954f6bde1fdSPoul-Henning Kamp printf("free\n"); 955f6bde1fdSPoul-Henning Kamp else if (up->ptr == uh) 956f6bde1fdSPoul-Henning Kamp printf("alloc\n"); 957f6bde1fdSPoul-Henning Kamp else { 958d9a54d5cSPoul-Henning Kamp ub = up->ptr; 9598907f744SAlan Somers printf("bitmap ["); 960d9a54d5cSPoul-Henning Kamp for (x = 0; x < up->len; x++) { 961d9a54d5cSPoul-Henning Kamp if (bit_test(ub->map, x)) 962d9a54d5cSPoul-Henning Kamp printf("#"); 963f6bde1fdSPoul-Henning Kamp else 964d9a54d5cSPoul-Henning Kamp printf(" "); 965f6bde1fdSPoul-Henning Kamp } 966f6bde1fdSPoul-Henning Kamp printf("]\n"); 967f6bde1fdSPoul-Henning Kamp } 968f6bde1fdSPoul-Henning Kamp } 969f6bde1fdSPoul-Henning Kamp 970f6bde1fdSPoul-Henning Kamp static void 971f6bde1fdSPoul-Henning Kamp print_unrhdr(struct unrhdr *uh) 972f6bde1fdSPoul-Henning Kamp { 973f6bde1fdSPoul-Henning Kamp struct unr *up; 974f6bde1fdSPoul-Henning Kamp u_int x; 975f6bde1fdSPoul-Henning Kamp 976d9a54d5cSPoul-Henning Kamp printf( 977d9a54d5cSPoul-Henning Kamp "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n", 978d9a54d5cSPoul-Henning Kamp uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc); 979d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 980f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 981f6bde1fdSPoul-Henning Kamp printf(" from = %5u", x); 982f6bde1fdSPoul-Henning Kamp print_unr(uh, up); 983f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL || up->ptr == uh) 984f6bde1fdSPoul-Henning Kamp x += up->len; 985f6bde1fdSPoul-Henning Kamp else 986f6bde1fdSPoul-Henning Kamp x += NBITS; 987f6bde1fdSPoul-Henning Kamp } 988f6bde1fdSPoul-Henning Kamp } 989f6bde1fdSPoul-Henning Kamp 99013c02cbbSJaakko Heinonen static void 99113c02cbbSJaakko Heinonen test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) 99213c02cbbSJaakko Heinonen { 99313c02cbbSJaakko Heinonen int j; 99413c02cbbSJaakko Heinonen 99513c02cbbSJaakko Heinonen if (a[i]) { 996794277daSAlan Somers VPRINTF("F %u\n", i); 99713c02cbbSJaakko Heinonen free_unr(uh, i); 99813c02cbbSJaakko Heinonen a[i] = 0; 99913c02cbbSJaakko Heinonen } else { 100013c02cbbSJaakko Heinonen no_alloc = 1; 100113c02cbbSJaakko Heinonen j = alloc_unr(uh); 100213c02cbbSJaakko Heinonen if (j != -1) { 100313c02cbbSJaakko Heinonen a[j] = 1; 1004794277daSAlan Somers VPRINTF("A %d\n", j); 100513c02cbbSJaakko Heinonen } 100613c02cbbSJaakko Heinonen no_alloc = 0; 100713c02cbbSJaakko Heinonen } 100813c02cbbSJaakko Heinonen } 100913c02cbbSJaakko Heinonen 101013c02cbbSJaakko Heinonen static void 101113c02cbbSJaakko Heinonen test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[]) 101213c02cbbSJaakko Heinonen { 101313c02cbbSJaakko Heinonen int j; 101413c02cbbSJaakko Heinonen 101513c02cbbSJaakko Heinonen j = alloc_unr_specific(uh, i); 101613c02cbbSJaakko Heinonen if (j == -1) { 1017794277daSAlan Somers VPRINTF("F %u\n", i); 101813c02cbbSJaakko Heinonen a[i] = 0; 101913c02cbbSJaakko Heinonen free_unr(uh, i); 102013c02cbbSJaakko Heinonen } else { 102113c02cbbSJaakko Heinonen a[i] = 1; 1022794277daSAlan Somers VPRINTF("A %d\n", j); 102313c02cbbSJaakko Heinonen } 102413c02cbbSJaakko Heinonen } 102513c02cbbSJaakko Heinonen 1026794277daSAlan Somers static void 1027794277daSAlan Somers usage(char** argv) 1028794277daSAlan Somers { 1029794277daSAlan Somers printf("%s [-h] [-r REPETITIONS] [-v]\n", argv[0]); 1030794277daSAlan Somers } 1031f6bde1fdSPoul-Henning Kamp 1032f6bde1fdSPoul-Henning Kamp int 1033794277daSAlan Somers main(int argc, char **argv) 1034f6bde1fdSPoul-Henning Kamp { 1035f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 1036794277daSAlan Somers char *a; 1037794277daSAlan Somers long count = 10000; /* Number of unrs to test */ 103837f32e53SAlan Somers long reps = 1, m; 1039794277daSAlan Somers int ch; 1040cd565040SConrad Meyer u_int i; 1041794277daSAlan Somers 1042794277daSAlan Somers verbose = false; 1043794277daSAlan Somers 1044794277daSAlan Somers while ((ch = getopt(argc, argv, "hr:v")) != -1) { 1045794277daSAlan Somers switch (ch) { 1046794277daSAlan Somers case 'r': 1047794277daSAlan Somers errno = 0; 1048794277daSAlan Somers reps = strtol(optarg, NULL, 0); 1049794277daSAlan Somers if (errno == ERANGE || errno == EINVAL) { 1050794277daSAlan Somers usage(argv); 1051794277daSAlan Somers exit(2); 1052794277daSAlan Somers } 1053794277daSAlan Somers 1054794277daSAlan Somers break; 1055794277daSAlan Somers case 'v': 1056794277daSAlan Somers verbose = true; 1057794277daSAlan Somers break; 1058794277daSAlan Somers case 'h': 1059794277daSAlan Somers default: 1060794277daSAlan Somers usage(argv); 1061794277daSAlan Somers exit(2); 1062794277daSAlan Somers } 1063794277daSAlan Somers } 1064f6bde1fdSPoul-Henning Kamp 1065d9a54d5cSPoul-Henning Kamp setbuf(stdout, NULL); 1066794277daSAlan Somers uh = new_unrhdr(0, count - 1, NULL); 1067d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1068f6bde1fdSPoul-Henning Kamp 1069794277daSAlan Somers a = calloc(count, sizeof(char)); 1070794277daSAlan Somers if (a == NULL) 1071794277daSAlan Somers err(1, "calloc failed"); 1072f6bde1fdSPoul-Henning Kamp 1073794277daSAlan Somers printf("sizeof(struct unr) %zu\n", sizeof(struct unr)); 1074794277daSAlan Somers printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb)); 1075794277daSAlan Somers printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); 1076b4f69365SEd Maste printf("NBITS %lu\n", (unsigned long)NBITS); 1077794277daSAlan Somers for (m = 0; m < count * reps; m++) { 1078cd565040SConrad Meyer i = arc4random_uniform(count); 1079d9a54d5cSPoul-Henning Kamp #if 0 1080d9a54d5cSPoul-Henning Kamp if (a[i] && (j & 1)) 1081d9a54d5cSPoul-Henning Kamp continue; 1082d9a54d5cSPoul-Henning Kamp #endif 1083cd565040SConrad Meyer if ((arc4random() & 1) != 0) 108413c02cbbSJaakko Heinonen test_alloc_unr(uh, i, a); 108513c02cbbSJaakko Heinonen else 108613c02cbbSJaakko Heinonen test_alloc_unr_specific(uh, i, a); 108713c02cbbSJaakko Heinonen 1088794277daSAlan Somers if (verbose) 1089f6bde1fdSPoul-Henning Kamp print_unrhdr(uh); 1090f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 1091f6bde1fdSPoul-Henning Kamp } 109237f32e53SAlan Somers for (i = 0; i < (u_int)count; i++) { 1093d9a54d5cSPoul-Henning Kamp if (a[i]) { 1094794277daSAlan Somers if (verbose) { 1095d9a54d5cSPoul-Henning Kamp printf("C %u\n", i); 1096e4fea39eSPoul-Henning Kamp print_unrhdr(uh); 1097d9a54d5cSPoul-Henning Kamp } 1098794277daSAlan Somers free_unr(uh, i); 1099794277daSAlan Somers } 1100d9a54d5cSPoul-Henning Kamp } 1101d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1102e4fea39eSPoul-Henning Kamp delete_unrhdr(uh); 1103794277daSAlan Somers free(a); 1104f6bde1fdSPoul-Henning Kamp return (0); 1105f6bde1fdSPoul-Henning Kamp } 1106f6bde1fdSPoul-Henning Kamp #endif 1107