1f6bde1fdSPoul-Henning Kamp /*- 2f6bde1fdSPoul-Henning Kamp * Copyright (c) 2004 Poul-Henning Kamp 3f6bde1fdSPoul-Henning Kamp * All rights reserved. 4f6bde1fdSPoul-Henning Kamp * 5f6bde1fdSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 6f6bde1fdSPoul-Henning Kamp * modification, are permitted provided that the following conditions 7f6bde1fdSPoul-Henning Kamp * are met: 8f6bde1fdSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 9f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 10f6bde1fdSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 11f6bde1fdSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 12f6bde1fdSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 13f6bde1fdSPoul-Henning Kamp * 14f6bde1fdSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15f6bde1fdSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16f6bde1fdSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17f6bde1fdSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18f6bde1fdSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19f6bde1fdSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20f6bde1fdSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21f6bde1fdSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22f6bde1fdSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23f6bde1fdSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24f6bde1fdSPoul-Henning Kamp * SUCH DAMAGE. 25f6bde1fdSPoul-Henning Kamp * 26f6bde1fdSPoul-Henning Kamp * $FreeBSD$ 27d9a54d5cSPoul-Henning Kamp * 28d9a54d5cSPoul-Henning Kamp * 29d9a54d5cSPoul-Henning Kamp * Unit number allocation functions. 30f6bde1fdSPoul-Henning Kamp * 31f6bde1fdSPoul-Henning Kamp * These functions implement a mixed run-length/bitmap management of unit 32d9a54d5cSPoul-Henning Kamp * number spaces in a very memory efficient manner. 33f6bde1fdSPoul-Henning Kamp * 34d9a54d5cSPoul-Henning Kamp * Allocation policy is always lowest free number first. 35f6bde1fdSPoul-Henning Kamp * 36d9a54d5cSPoul-Henning Kamp * A return value of -1 signals that no more unit numbers are available. 37f6bde1fdSPoul-Henning Kamp * 38d9a54d5cSPoul-Henning Kamp * There is no cost associated with the range of unitnumbers, so unless 39d9a54d5cSPoul-Henning Kamp * the resource really is finite, specify INT_MAX to new_unrhdr() and 40d9a54d5cSPoul-Henning Kamp * forget about checking the return value. 41f6bde1fdSPoul-Henning Kamp * 42d9a54d5cSPoul-Henning Kamp * If a mutex is not provided when the unit number space is created, a 43d9a54d5cSPoul-Henning Kamp * default global mutex is used. The advantage to passing a mutex in, is 446bccea7cSRebecca Cran * that the alloc_unrl() function can be called with the mutex already 45d9a54d5cSPoul-Henning Kamp * held (it will not be released by alloc_unrl()). 46d9a54d5cSPoul-Henning Kamp * 47d9a54d5cSPoul-Henning Kamp * The allocation function alloc_unr{l}() never sleeps (but it may block on 48d9a54d5cSPoul-Henning Kamp * the mutex of course). 49d9a54d5cSPoul-Henning Kamp * 50d9a54d5cSPoul-Henning Kamp * Freeing a unit number may require allocating memory, and can therefore 51d9a54d5cSPoul-Henning Kamp * sleep so the free_unr() function does not come in a pre-locked variant. 52f6bde1fdSPoul-Henning Kamp * 53f6bde1fdSPoul-Henning Kamp * A userland test program is included. 54f6bde1fdSPoul-Henning Kamp * 556bccea7cSRebecca Cran * Memory usage is a very complex function of the exact allocation 56d9a54d5cSPoul-Henning Kamp * pattern, but always very compact: 57d9a54d5cSPoul-Henning Kamp * * For the very typical case where a single unbroken run of unit 58d9a54d5cSPoul-Henning Kamp * numbers are allocated 44 bytes are used on i386. 59d9a54d5cSPoul-Henning Kamp * * For a unit number space of 1000 units and the random pattern 60d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 61d9a54d5cSPoul-Henning Kamp * was 252 bytes on i386 for 500 allocated and 500 free units. 62d9a54d5cSPoul-Henning Kamp * * For a unit number space of 10000 units and the random pattern 63d9a54d5cSPoul-Henning Kamp * in the usermode test program included, the worst case usage 64d9a54d5cSPoul-Henning Kamp * was 798 bytes on i386 for 5000 allocated and 5000 free units. 65d9a54d5cSPoul-Henning Kamp * * The worst case is where every other unit number is allocated and 6696240c89SEitan Adler * the rest are free. In that case 44 + N/4 bytes are used where 67d9a54d5cSPoul-Henning Kamp * N is the number of the highest unit allocated. 68f6bde1fdSPoul-Henning Kamp */ 69f6bde1fdSPoul-Henning Kamp 70f6bde1fdSPoul-Henning Kamp #include <sys/types.h> 71dc872d46SKonstantin Belousov #include <sys/_unrhdr.h> 72f6bde1fdSPoul-Henning Kamp 73f6bde1fdSPoul-Henning Kamp #ifdef _KERNEL 74f6bde1fdSPoul-Henning Kamp 75*794277daSAlan Somers #include <sys/bitstring.h> 76f6bde1fdSPoul-Henning Kamp #include <sys/param.h> 77f6bde1fdSPoul-Henning Kamp #include <sys/malloc.h> 78f6bde1fdSPoul-Henning Kamp #include <sys/kernel.h> 79f6bde1fdSPoul-Henning Kamp #include <sys/systm.h> 80d9a54d5cSPoul-Henning Kamp #include <sys/limits.h> 81d9a54d5cSPoul-Henning Kamp #include <sys/lock.h> 82d9a54d5cSPoul-Henning Kamp #include <sys/mutex.h> 83f6bde1fdSPoul-Henning Kamp 84f6bde1fdSPoul-Henning Kamp /* 85f6bde1fdSPoul-Henning Kamp * In theory it would be smarter to allocate the individual blocks 86f6bde1fdSPoul-Henning Kamp * with the zone allocator, but at this time the expectation is that 87f6bde1fdSPoul-Henning Kamp * there will typically not even be enough allocations to fill a single 88f6bde1fdSPoul-Henning Kamp * page, so we stick with malloc for now. 89f6bde1fdSPoul-Henning Kamp */ 90f6bde1fdSPoul-Henning Kamp static MALLOC_DEFINE(M_UNIT, "Unitno", "Unit number allocation"); 91f6bde1fdSPoul-Henning Kamp 92f6bde1fdSPoul-Henning Kamp #define Malloc(foo) malloc(foo, M_UNIT, M_WAITOK | M_ZERO) 93f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo, M_UNIT) 94f6bde1fdSPoul-Henning Kamp 95d9a54d5cSPoul-Henning Kamp static struct mtx unitmtx; 96d9a54d5cSPoul-Henning Kamp 97d9a54d5cSPoul-Henning Kamp MTX_SYSINIT(unit, &unitmtx, "unit# allocation", MTX_DEF); 98d9a54d5cSPoul-Henning Kamp 99f6bde1fdSPoul-Henning Kamp #else /* ...USERLAND */ 100f6bde1fdSPoul-Henning Kamp 101*794277daSAlan Somers #include <bitstring.h> 102*794277daSAlan Somers #include <err.h> 103*794277daSAlan Somers #include <errno.h> 104*794277daSAlan Somers #include <getopt.h> 105*794277daSAlan Somers #include <stdbool.h> 106f6bde1fdSPoul-Henning Kamp #include <stdio.h> 107f6bde1fdSPoul-Henning Kamp #include <stdlib.h> 108d9a54d5cSPoul-Henning Kamp #include <string.h> 109f6bde1fdSPoul-Henning Kamp 110f6bde1fdSPoul-Henning Kamp #define KASSERT(cond, arg) \ 111f6bde1fdSPoul-Henning Kamp do { \ 112f6bde1fdSPoul-Henning Kamp if (!(cond)) { \ 113f6bde1fdSPoul-Henning Kamp printf arg; \ 114d9a54d5cSPoul-Henning Kamp abort(); \ 115f6bde1fdSPoul-Henning Kamp } \ 116f6bde1fdSPoul-Henning Kamp } while (0) 117f6bde1fdSPoul-Henning Kamp 118d9a54d5cSPoul-Henning Kamp static int no_alloc; 119d9a54d5cSPoul-Henning Kamp #define Malloc(foo) _Malloc(foo, __LINE__) 120d9a54d5cSPoul-Henning Kamp static void * 121d9a54d5cSPoul-Henning Kamp _Malloc(size_t foo, int line) 122d9a54d5cSPoul-Henning Kamp { 123d9a54d5cSPoul-Henning Kamp 124d9a54d5cSPoul-Henning Kamp KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line)); 125d9a54d5cSPoul-Henning Kamp return (calloc(foo, 1)); 126d9a54d5cSPoul-Henning Kamp } 127f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo) 128f6bde1fdSPoul-Henning Kamp 129d9a54d5cSPoul-Henning Kamp struct unrhdr; 130d9a54d5cSPoul-Henning Kamp 131d9a54d5cSPoul-Henning Kamp 132d9a54d5cSPoul-Henning Kamp struct mtx { 133d9a54d5cSPoul-Henning Kamp int state; 134d9a54d5cSPoul-Henning Kamp } unitmtx; 135d9a54d5cSPoul-Henning Kamp 136d9a54d5cSPoul-Henning Kamp static void 137d9a54d5cSPoul-Henning Kamp mtx_lock(struct mtx *mp) 138d9a54d5cSPoul-Henning Kamp { 139d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 0, ("mutex already locked")); 140d9a54d5cSPoul-Henning Kamp mp->state = 1; 141d9a54d5cSPoul-Henning Kamp } 142d9a54d5cSPoul-Henning Kamp 143d9a54d5cSPoul-Henning Kamp static void 144d9a54d5cSPoul-Henning Kamp mtx_unlock(struct mtx *mp) 145d9a54d5cSPoul-Henning Kamp { 146d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mutex not locked")); 147d9a54d5cSPoul-Henning Kamp mp->state = 0; 148d9a54d5cSPoul-Henning Kamp } 149d9a54d5cSPoul-Henning Kamp 150d9a54d5cSPoul-Henning Kamp #define MA_OWNED 9 151d9a54d5cSPoul-Henning Kamp 152d9a54d5cSPoul-Henning Kamp static void 153d9a54d5cSPoul-Henning Kamp mtx_assert(struct mtx *mp, int flag) 154d9a54d5cSPoul-Henning Kamp { 155d9a54d5cSPoul-Henning Kamp if (flag == MA_OWNED) { 156d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true")); 157d9a54d5cSPoul-Henning Kamp } 158d9a54d5cSPoul-Henning Kamp } 159d9a54d5cSPoul-Henning Kamp 160d9a54d5cSPoul-Henning Kamp #define CTASSERT(foo) 16124e8eaf1SJaakko Heinonen #define WITNESS_WARN(flags, lock, fmt, ...) (void)0 162d9a54d5cSPoul-Henning Kamp 163d9a54d5cSPoul-Henning Kamp #endif /* USERLAND */ 164f6bde1fdSPoul-Henning Kamp 165f6bde1fdSPoul-Henning Kamp /* 166f6bde1fdSPoul-Henning Kamp * This is our basic building block. 167f6bde1fdSPoul-Henning Kamp * 168f6bde1fdSPoul-Henning Kamp * It can be used in three different ways depending on the value of the ptr 169f6bde1fdSPoul-Henning Kamp * element: 170f6bde1fdSPoul-Henning Kamp * If ptr is NULL, it represents a run of free items. 171f6bde1fdSPoul-Henning Kamp * If ptr points to the unrhdr it represents a run of allocated items. 172f6bde1fdSPoul-Henning Kamp * Otherwise it points to an bitstring of allocated items. 173f6bde1fdSPoul-Henning Kamp * 174f6bde1fdSPoul-Henning Kamp * For runs the len field is the length of the run. 175f6bde1fdSPoul-Henning Kamp * For bitmaps the len field represents the number of allocated items. 176f6bde1fdSPoul-Henning Kamp * 177f6bde1fdSPoul-Henning Kamp * The bitmap is the same size as struct unr to optimize memory management. 178f6bde1fdSPoul-Henning Kamp */ 179f6bde1fdSPoul-Henning Kamp struct unr { 180f6bde1fdSPoul-Henning Kamp TAILQ_ENTRY(unr) list; 181f6bde1fdSPoul-Henning Kamp u_int len; 182f6bde1fdSPoul-Henning Kamp void *ptr; 183f6bde1fdSPoul-Henning Kamp }; 184f6bde1fdSPoul-Henning Kamp 185d9a54d5cSPoul-Henning Kamp struct unrb { 186d9a54d5cSPoul-Henning Kamp u_char busy; 187d9a54d5cSPoul-Henning Kamp bitstr_t map[sizeof(struct unr) - 1]; 188d9a54d5cSPoul-Henning Kamp }; 189d9a54d5cSPoul-Henning Kamp 190d9a54d5cSPoul-Henning Kamp CTASSERT(sizeof(struct unr) == sizeof(struct unrb)); 191d9a54d5cSPoul-Henning Kamp 192f6bde1fdSPoul-Henning Kamp /* Number of bits in the bitmap */ 193d9a54d5cSPoul-Henning Kamp #define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8) 194f6bde1fdSPoul-Henning Kamp 195f6bde1fdSPoul-Henning Kamp #if defined(DIAGNOSTIC) || !defined(_KERNEL) 196f6bde1fdSPoul-Henning Kamp /* 197f6bde1fdSPoul-Henning Kamp * Consistency check function. 198f6bde1fdSPoul-Henning Kamp * 199f6bde1fdSPoul-Henning Kamp * Checks the internal consistency as well as we can. 200f6bde1fdSPoul-Henning Kamp * 201f6bde1fdSPoul-Henning Kamp * Called at all boundaries of this API. 202f6bde1fdSPoul-Henning Kamp */ 203f6bde1fdSPoul-Henning Kamp static void 204f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unrhdr *uh, int line) 205f6bde1fdSPoul-Henning Kamp { 206f6bde1fdSPoul-Henning Kamp struct unr *up; 207d9a54d5cSPoul-Henning Kamp struct unrb *ub; 208f6bde1fdSPoul-Henning Kamp u_int x, y, z, w; 209f6bde1fdSPoul-Henning Kamp 210d9a54d5cSPoul-Henning Kamp y = uh->first; 211f6bde1fdSPoul-Henning Kamp z = 0; 212f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 213f6bde1fdSPoul-Henning Kamp z++; 214f6bde1fdSPoul-Henning Kamp if (up->ptr != uh && up->ptr != NULL) { 215d9a54d5cSPoul-Henning Kamp ub = up->ptr; 216d9a54d5cSPoul-Henning Kamp KASSERT (up->len <= NBITS, 217d9a54d5cSPoul-Henning Kamp ("UNR inconsistency: len %u max %d (line %d)\n", 218d9a54d5cSPoul-Henning Kamp up->len, NBITS, line)); 219f6bde1fdSPoul-Henning Kamp z++; 220f6bde1fdSPoul-Henning Kamp w = 0; 221d9a54d5cSPoul-Henning Kamp for (x = 0; x < up->len; x++) 222d9a54d5cSPoul-Henning Kamp if (bit_test(ub->map, x)) 223f6bde1fdSPoul-Henning Kamp w++; 224d9a54d5cSPoul-Henning Kamp KASSERT (w == ub->busy, 225d9a54d5cSPoul-Henning Kamp ("UNR inconsistency: busy %u found %u (line %d)\n", 226d9a54d5cSPoul-Henning Kamp ub->busy, w, line)); 227d9a54d5cSPoul-Henning Kamp y += w; 228d9a54d5cSPoul-Henning Kamp } else if (up->ptr != NULL) 229f6bde1fdSPoul-Henning Kamp y += up->len; 230f6bde1fdSPoul-Henning Kamp } 231f6bde1fdSPoul-Henning Kamp KASSERT (y == uh->busy, 232f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: items %u found %u (line %d)\n", 233f6bde1fdSPoul-Henning Kamp uh->busy, y, line)); 234f6bde1fdSPoul-Henning Kamp KASSERT (z == uh->alloc, 235f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: chunks %u found %u (line %d)\n", 236f6bde1fdSPoul-Henning Kamp uh->alloc, z, line)); 237f6bde1fdSPoul-Henning Kamp } 238f6bde1fdSPoul-Henning Kamp 239f6bde1fdSPoul-Henning Kamp #else 240f6bde1fdSPoul-Henning Kamp 241f6bde1fdSPoul-Henning Kamp static __inline void 2424a2aa5d0SJohn Baldwin check_unrhdr(struct unrhdr *uh, int line) 243f6bde1fdSPoul-Henning Kamp { 244f6bde1fdSPoul-Henning Kamp 245f6bde1fdSPoul-Henning Kamp } 246f6bde1fdSPoul-Henning Kamp 247f6bde1fdSPoul-Henning Kamp #endif 248f6bde1fdSPoul-Henning Kamp 249f6bde1fdSPoul-Henning Kamp 250f6bde1fdSPoul-Henning Kamp /* 251f6bde1fdSPoul-Henning Kamp * Userland memory management. Just use calloc and keep track of how 252f6bde1fdSPoul-Henning Kamp * many elements we have allocated for check_unrhdr(). 253f6bde1fdSPoul-Henning Kamp */ 254f6bde1fdSPoul-Henning Kamp 255f6bde1fdSPoul-Henning Kamp static __inline void * 256d9a54d5cSPoul-Henning Kamp new_unr(struct unrhdr *uh, void **p1, void **p2) 257f6bde1fdSPoul-Henning Kamp { 258d9a54d5cSPoul-Henning Kamp void *p; 259f6bde1fdSPoul-Henning Kamp 260d9a54d5cSPoul-Henning Kamp uh->alloc++; 261d9a54d5cSPoul-Henning Kamp KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory")); 262d9a54d5cSPoul-Henning Kamp if (*p1 != NULL) { 263d9a54d5cSPoul-Henning Kamp p = *p1; 264d9a54d5cSPoul-Henning Kamp *p1 = NULL; 265d9a54d5cSPoul-Henning Kamp return (p); 266d9a54d5cSPoul-Henning Kamp } else { 267d9a54d5cSPoul-Henning Kamp p = *p2; 268d9a54d5cSPoul-Henning Kamp *p2 = NULL; 269d9a54d5cSPoul-Henning Kamp return (p); 270d9a54d5cSPoul-Henning Kamp } 271f6bde1fdSPoul-Henning Kamp } 272f6bde1fdSPoul-Henning Kamp 273f6bde1fdSPoul-Henning Kamp static __inline void 274f6bde1fdSPoul-Henning Kamp delete_unr(struct unrhdr *uh, void *ptr) 275f6bde1fdSPoul-Henning Kamp { 27609828ba9SKonstantin Belousov struct unr *up; 277d9a54d5cSPoul-Henning Kamp 278f6bde1fdSPoul-Henning Kamp uh->alloc--; 27909828ba9SKonstantin Belousov up = ptr; 28009828ba9SKonstantin Belousov TAILQ_INSERT_TAIL(&uh->ppfree, up, list); 28109828ba9SKonstantin Belousov } 28209828ba9SKonstantin Belousov 28309828ba9SKonstantin Belousov void 28409828ba9SKonstantin Belousov clean_unrhdrl(struct unrhdr *uh) 28509828ba9SKonstantin Belousov { 28609828ba9SKonstantin Belousov struct unr *up; 28709828ba9SKonstantin Belousov 28809828ba9SKonstantin Belousov mtx_assert(uh->mtx, MA_OWNED); 28909828ba9SKonstantin Belousov while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) { 29009828ba9SKonstantin Belousov TAILQ_REMOVE(&uh->ppfree, up, list); 29109828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 29209828ba9SKonstantin Belousov Free(up); 29309828ba9SKonstantin Belousov mtx_lock(uh->mtx); 29409828ba9SKonstantin Belousov } 29509828ba9SKonstantin Belousov 29609828ba9SKonstantin Belousov } 29709828ba9SKonstantin Belousov 29809828ba9SKonstantin Belousov void 29909828ba9SKonstantin Belousov clean_unrhdr(struct unrhdr *uh) 30009828ba9SKonstantin Belousov { 30109828ba9SKonstantin Belousov 30209828ba9SKonstantin Belousov mtx_lock(uh->mtx); 30309828ba9SKonstantin Belousov clean_unrhdrl(uh); 30409828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 305f6bde1fdSPoul-Henning Kamp } 306f6bde1fdSPoul-Henning Kamp 307dc872d46SKonstantin Belousov void 308dc872d46SKonstantin Belousov init_unrhdr(struct unrhdr *uh, int low, int high, struct mtx *mutex) 309f6bde1fdSPoul-Henning Kamp { 310f6bde1fdSPoul-Henning Kamp 311831aa555SJaakko Heinonen KASSERT(low >= 0 && low <= high, 312501812f2SJaakko Heinonen ("UNR: use error: new_unrhdr(%d, %d)", low, high)); 313d9a54d5cSPoul-Henning Kamp if (mutex != NULL) 314d9a54d5cSPoul-Henning Kamp uh->mtx = mutex; 315d9a54d5cSPoul-Henning Kamp else 316d9a54d5cSPoul-Henning Kamp uh->mtx = &unitmtx; 317f6bde1fdSPoul-Henning Kamp TAILQ_INIT(&uh->head); 31809828ba9SKonstantin Belousov TAILQ_INIT(&uh->ppfree); 319f6bde1fdSPoul-Henning Kamp uh->low = low; 320f6bde1fdSPoul-Henning Kamp uh->high = high; 321d9a54d5cSPoul-Henning Kamp uh->first = 0; 322d9a54d5cSPoul-Henning Kamp uh->last = 1 + (high - low); 323f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 324dc872d46SKonstantin Belousov } 325dc872d46SKonstantin Belousov 326dc872d46SKonstantin Belousov /* 327dc872d46SKonstantin Belousov * Allocate a new unrheader set. 328dc872d46SKonstantin Belousov * 329dc872d46SKonstantin Belousov * Highest and lowest valid values given as parameters. 330dc872d46SKonstantin Belousov */ 331dc872d46SKonstantin Belousov 332dc872d46SKonstantin Belousov struct unrhdr * 333dc872d46SKonstantin Belousov new_unrhdr(int low, int high, struct mtx *mutex) 334dc872d46SKonstantin Belousov { 335dc872d46SKonstantin Belousov struct unrhdr *uh; 336dc872d46SKonstantin Belousov 337dc872d46SKonstantin Belousov uh = Malloc(sizeof *uh); 338dc872d46SKonstantin Belousov init_unrhdr(uh, low, high, mutex); 339f6bde1fdSPoul-Henning Kamp return (uh); 340f6bde1fdSPoul-Henning Kamp } 341f6bde1fdSPoul-Henning Kamp 342e4fea39eSPoul-Henning Kamp void 343e4fea39eSPoul-Henning Kamp delete_unrhdr(struct unrhdr *uh) 344e4fea39eSPoul-Henning Kamp { 345e4fea39eSPoul-Henning Kamp 346d9a54d5cSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 347e4fea39eSPoul-Henning Kamp KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy)); 348e4fea39eSPoul-Henning Kamp KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr")); 34909828ba9SKonstantin Belousov KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL, 35009828ba9SKonstantin Belousov ("unrhdr has postponed item for free")); 351e4fea39eSPoul-Henning Kamp Free(uh); 352e4fea39eSPoul-Henning Kamp } 353e4fea39eSPoul-Henning Kamp 354d9a54d5cSPoul-Henning Kamp static __inline int 355d9a54d5cSPoul-Henning Kamp is_bitmap(struct unrhdr *uh, struct unr *up) 356d9a54d5cSPoul-Henning Kamp { 357d9a54d5cSPoul-Henning Kamp return (up->ptr != uh && up->ptr != NULL); 358d9a54d5cSPoul-Henning Kamp } 359d9a54d5cSPoul-Henning Kamp 360f6bde1fdSPoul-Henning Kamp /* 361d9a54d5cSPoul-Henning Kamp * Look for sequence of items which can be combined into a bitmap, if 362d9a54d5cSPoul-Henning Kamp * multiple are present, take the one which saves most memory. 363d9a54d5cSPoul-Henning Kamp * 364d9a54d5cSPoul-Henning Kamp * Return (1) if a sequence was found to indicate that another call 365d9a54d5cSPoul-Henning Kamp * might be able to do more. Return (0) if we found no suitable sequence. 366d9a54d5cSPoul-Henning Kamp * 367d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 368d9a54d5cSPoul-Henning Kamp */ 369d9a54d5cSPoul-Henning Kamp static int 370d9a54d5cSPoul-Henning Kamp optimize_unr(struct unrhdr *uh) 371d9a54d5cSPoul-Henning Kamp { 372d9a54d5cSPoul-Henning Kamp struct unr *up, *uf, *us; 373d9a54d5cSPoul-Henning Kamp struct unrb *ub, *ubf; 374d9a54d5cSPoul-Henning Kamp u_int a, l, ba; 375d9a54d5cSPoul-Henning Kamp 376d9a54d5cSPoul-Henning Kamp /* 377d9a54d5cSPoul-Henning Kamp * Look for the run of items (if any) which when collapsed into 378d9a54d5cSPoul-Henning Kamp * a bitmap would save most memory. 379d9a54d5cSPoul-Henning Kamp */ 380d9a54d5cSPoul-Henning Kamp us = NULL; 381d9a54d5cSPoul-Henning Kamp ba = 0; 382d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(uf, &uh->head, list) { 383d9a54d5cSPoul-Henning Kamp if (uf->len >= NBITS) 384d9a54d5cSPoul-Henning Kamp continue; 385d9a54d5cSPoul-Henning Kamp a = 1; 386d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, uf)) 387d9a54d5cSPoul-Henning Kamp a++; 388d9a54d5cSPoul-Henning Kamp l = uf->len; 389d9a54d5cSPoul-Henning Kamp up = uf; 390d9a54d5cSPoul-Henning Kamp while (1) { 391d9a54d5cSPoul-Henning Kamp up = TAILQ_NEXT(up, list); 392d9a54d5cSPoul-Henning Kamp if (up == NULL) 393d9a54d5cSPoul-Henning Kamp break; 394d9a54d5cSPoul-Henning Kamp if ((up->len + l) > NBITS) 395d9a54d5cSPoul-Henning Kamp break; 396d9a54d5cSPoul-Henning Kamp a++; 397d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) 398d9a54d5cSPoul-Henning Kamp a++; 399d9a54d5cSPoul-Henning Kamp l += up->len; 400d9a54d5cSPoul-Henning Kamp } 401d9a54d5cSPoul-Henning Kamp if (a > ba) { 402d9a54d5cSPoul-Henning Kamp ba = a; 403d9a54d5cSPoul-Henning Kamp us = uf; 404d9a54d5cSPoul-Henning Kamp } 405d9a54d5cSPoul-Henning Kamp } 406d9a54d5cSPoul-Henning Kamp if (ba < 3) 407d9a54d5cSPoul-Henning Kamp return (0); 408d9a54d5cSPoul-Henning Kamp 409d9a54d5cSPoul-Henning Kamp /* 410d9a54d5cSPoul-Henning Kamp * If the first element is not a bitmap, make it one. 411d9a54d5cSPoul-Henning Kamp * Trying to do so without allocating more memory complicates things 412d9a54d5cSPoul-Henning Kamp * a bit 413d9a54d5cSPoul-Henning Kamp */ 414d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, us)) { 415d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 416d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, us, list); 417d9a54d5cSPoul-Henning Kamp a = us->len; 418d9a54d5cSPoul-Henning Kamp l = us->ptr == uh ? 1 : 0; 419d9a54d5cSPoul-Henning Kamp ub = (void *)us; 420d9a54d5cSPoul-Henning Kamp ub->busy = 0; 421d9a54d5cSPoul-Henning Kamp if (l) { 422d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, 0, a); 423d9a54d5cSPoul-Henning Kamp ub->busy += a; 424d9a54d5cSPoul-Henning Kamp } else { 425d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, 0, a); 426d9a54d5cSPoul-Henning Kamp } 427d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, uf)) { 428d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 429d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, a, a + uf->len - 1); 430d9a54d5cSPoul-Henning Kamp } else { 431d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, a, a + uf->len - 1); 432d9a54d5cSPoul-Henning Kamp ub->busy += uf->len; 433d9a54d5cSPoul-Henning Kamp } 434d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 435d9a54d5cSPoul-Henning Kamp uf->len += a; 436d9a54d5cSPoul-Henning Kamp us = uf; 437d9a54d5cSPoul-Henning Kamp } else { 438d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 439d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, a++) { 440d9a54d5cSPoul-Henning Kamp if (bit_test(ubf->map, l)) { 441d9a54d5cSPoul-Henning Kamp bit_set(ub->map, a); 442d9a54d5cSPoul-Henning Kamp ub->busy++; 443d9a54d5cSPoul-Henning Kamp } else { 444d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, a); 445d9a54d5cSPoul-Henning Kamp } 446d9a54d5cSPoul-Henning Kamp } 447d9a54d5cSPoul-Henning Kamp uf->len = a; 448d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf->ptr); 449d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 450d9a54d5cSPoul-Henning Kamp us = uf; 451d9a54d5cSPoul-Henning Kamp } 452d9a54d5cSPoul-Henning Kamp } 453d9a54d5cSPoul-Henning Kamp ub = us->ptr; 454d9a54d5cSPoul-Henning Kamp while (1) { 455d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 456d9a54d5cSPoul-Henning Kamp if (uf == NULL) 457d9a54d5cSPoul-Henning Kamp return (1); 458d9a54d5cSPoul-Henning Kamp if (uf->len + us->len > NBITS) 459d9a54d5cSPoul-Henning Kamp return (1); 460d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 461d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, us->len, us->len + uf->len - 1); 462d9a54d5cSPoul-Henning Kamp us->len += uf->len; 463d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 464d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 465d9a54d5cSPoul-Henning Kamp } else if (uf->ptr == uh) { 466d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, us->len, us->len + uf->len - 1); 467d9a54d5cSPoul-Henning Kamp ub->busy += uf->len; 468d9a54d5cSPoul-Henning Kamp us->len += uf->len; 469d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 470d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 471d9a54d5cSPoul-Henning Kamp } else { 472d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 473d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, us->len++) { 474d9a54d5cSPoul-Henning Kamp if (bit_test(ubf->map, l)) { 475d9a54d5cSPoul-Henning Kamp bit_set(ub->map, us->len); 476d9a54d5cSPoul-Henning Kamp ub->busy++; 477d9a54d5cSPoul-Henning Kamp } else { 478d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, us->len); 479d9a54d5cSPoul-Henning Kamp } 480d9a54d5cSPoul-Henning Kamp } 481d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 482d9a54d5cSPoul-Henning Kamp delete_unr(uh, ubf); 483d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 484d9a54d5cSPoul-Henning Kamp } 485d9a54d5cSPoul-Henning Kamp } 486d9a54d5cSPoul-Henning Kamp } 487d9a54d5cSPoul-Henning Kamp 488d9a54d5cSPoul-Henning Kamp /* 489d9a54d5cSPoul-Henning Kamp * See if a given unr should be collapsed with a neighbor. 490d9a54d5cSPoul-Henning Kamp * 491d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 492f6bde1fdSPoul-Henning Kamp */ 493f6bde1fdSPoul-Henning Kamp static void 494f6bde1fdSPoul-Henning Kamp collapse_unr(struct unrhdr *uh, struct unr *up) 495f6bde1fdSPoul-Henning Kamp { 496f6bde1fdSPoul-Henning Kamp struct unr *upp; 497d9a54d5cSPoul-Henning Kamp struct unrb *ub; 498f6bde1fdSPoul-Henning Kamp 499d9a54d5cSPoul-Henning Kamp /* If bitmap is all set or clear, change it to runlength */ 500d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 501d9a54d5cSPoul-Henning Kamp ub = up->ptr; 502d9a54d5cSPoul-Henning Kamp if (ub->busy == up->len) { 503d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 504d9a54d5cSPoul-Henning Kamp up->ptr = uh; 505d9a54d5cSPoul-Henning Kamp } else if (ub->busy == 0) { 506d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 507d9a54d5cSPoul-Henning Kamp up->ptr = NULL; 508d9a54d5cSPoul-Henning Kamp } 509d9a54d5cSPoul-Henning Kamp } 510d9a54d5cSPoul-Henning Kamp 511d9a54d5cSPoul-Henning Kamp /* If nothing left in runlength, delete it */ 512d9a54d5cSPoul-Henning Kamp if (up->len == 0) { 513d9a54d5cSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 514d9a54d5cSPoul-Henning Kamp if (upp == NULL) 515d9a54d5cSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 516d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, up, list); 517d9a54d5cSPoul-Henning Kamp delete_unr(uh, up); 518d9a54d5cSPoul-Henning Kamp up = upp; 519d9a54d5cSPoul-Henning Kamp } 520d9a54d5cSPoul-Henning Kamp 521d9a54d5cSPoul-Henning Kamp /* If we have "hot-spot" still, merge with neighbor if possible */ 522d9a54d5cSPoul-Henning Kamp if (up != NULL) { 523f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 524f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 525f6bde1fdSPoul-Henning Kamp up->len += upp->len; 526f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 527f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 528f6bde1fdSPoul-Henning Kamp } 529f6bde1fdSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 530f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 531f6bde1fdSPoul-Henning Kamp up->len += upp->len; 532f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 533f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 534f6bde1fdSPoul-Henning Kamp } 535f6bde1fdSPoul-Henning Kamp } 536f6bde1fdSPoul-Henning Kamp 537d9a54d5cSPoul-Henning Kamp /* Merge into ->first if possible */ 538d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 539d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == uh) { 540d9a54d5cSPoul-Henning Kamp uh->first += upp->len; 541d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 542d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 543d9a54d5cSPoul-Henning Kamp if (up == upp) 544d9a54d5cSPoul-Henning Kamp up = NULL; 545d9a54d5cSPoul-Henning Kamp } 546d9a54d5cSPoul-Henning Kamp 547d9a54d5cSPoul-Henning Kamp /* Merge into ->last if possible */ 548d9a54d5cSPoul-Henning Kamp upp = TAILQ_LAST(&uh->head, unrhd); 549d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == NULL) { 550d9a54d5cSPoul-Henning Kamp uh->last += upp->len; 551d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 552d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 553d9a54d5cSPoul-Henning Kamp if (up == upp) 554d9a54d5cSPoul-Henning Kamp up = NULL; 555d9a54d5cSPoul-Henning Kamp } 556d9a54d5cSPoul-Henning Kamp 557d9a54d5cSPoul-Henning Kamp /* Try to make bitmaps */ 558d9a54d5cSPoul-Henning Kamp while (optimize_unr(uh)) 559d9a54d5cSPoul-Henning Kamp continue; 560d9a54d5cSPoul-Henning Kamp } 561d9a54d5cSPoul-Henning Kamp 562f6bde1fdSPoul-Henning Kamp /* 563f6bde1fdSPoul-Henning Kamp * Allocate a free unr. 564f6bde1fdSPoul-Henning Kamp */ 565d9a54d5cSPoul-Henning Kamp int 566d9a54d5cSPoul-Henning Kamp alloc_unrl(struct unrhdr *uh) 567f6bde1fdSPoul-Henning Kamp { 568d9a54d5cSPoul-Henning Kamp struct unr *up; 569d9a54d5cSPoul-Henning Kamp struct unrb *ub; 570f6bde1fdSPoul-Henning Kamp u_int x; 571f6bde1fdSPoul-Henning Kamp int y; 572f6bde1fdSPoul-Henning Kamp 573d9a54d5cSPoul-Henning Kamp mtx_assert(uh->mtx, MA_OWNED); 574f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 575d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 576d9a54d5cSPoul-Henning Kamp 577f6bde1fdSPoul-Henning Kamp up = TAILQ_FIRST(&uh->head); 578f6bde1fdSPoul-Henning Kamp 579d9a54d5cSPoul-Henning Kamp /* 580d9a54d5cSPoul-Henning Kamp * If we have an ideal split, just adjust the first+last 581d9a54d5cSPoul-Henning Kamp */ 582d9a54d5cSPoul-Henning Kamp if (up == NULL && uh->last > 0) { 583d9a54d5cSPoul-Henning Kamp uh->first++; 584d9a54d5cSPoul-Henning Kamp uh->last--; 585f6bde1fdSPoul-Henning Kamp uh->busy++; 586f6bde1fdSPoul-Henning Kamp return (x); 587f6bde1fdSPoul-Henning Kamp } 588f6bde1fdSPoul-Henning Kamp 589f6bde1fdSPoul-Henning Kamp /* 590d9a54d5cSPoul-Henning Kamp * We can always allocate from the first list element, so if we have 591d9a54d5cSPoul-Henning Kamp * nothing on the list, we must have run out of unit numbers. 592f6bde1fdSPoul-Henning Kamp */ 59393f6c81eSPoul-Henning Kamp if (up == NULL) 594d9a54d5cSPoul-Henning Kamp return (-1); 595d9a54d5cSPoul-Henning Kamp 596d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr != uh, ("UNR first element is allocated")); 597d9a54d5cSPoul-Henning Kamp 598d9a54d5cSPoul-Henning Kamp if (up->ptr == NULL) { /* free run */ 599d9a54d5cSPoul-Henning Kamp uh->first++; 600f6bde1fdSPoul-Henning Kamp up->len--; 601d9a54d5cSPoul-Henning Kamp } else { /* bitmap */ 602d9a54d5cSPoul-Henning Kamp ub = up->ptr; 603d9a54d5cSPoul-Henning Kamp KASSERT(ub->busy < up->len, ("UNR bitmap confusion")); 604d9a54d5cSPoul-Henning Kamp bit_ffc(ub->map, up->len, &y); 605d9a54d5cSPoul-Henning Kamp KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); 606d9a54d5cSPoul-Henning Kamp bit_set(ub->map, y); 607d9a54d5cSPoul-Henning Kamp ub->busy++; 608d9a54d5cSPoul-Henning Kamp x += y; 609d9a54d5cSPoul-Henning Kamp } 610f6bde1fdSPoul-Henning Kamp uh->busy++; 611d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 612f6bde1fdSPoul-Henning Kamp return (x); 613f6bde1fdSPoul-Henning Kamp } 614f6bde1fdSPoul-Henning Kamp 615d9a54d5cSPoul-Henning Kamp int 616d9a54d5cSPoul-Henning Kamp alloc_unr(struct unrhdr *uh) 617d9a54d5cSPoul-Henning Kamp { 618d9a54d5cSPoul-Henning Kamp int i; 619d9a54d5cSPoul-Henning Kamp 620d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 621d9a54d5cSPoul-Henning Kamp i = alloc_unrl(uh); 62209828ba9SKonstantin Belousov clean_unrhdrl(uh); 623d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 624d9a54d5cSPoul-Henning Kamp return (i); 625d9a54d5cSPoul-Henning Kamp } 626d9a54d5cSPoul-Henning Kamp 62713c02cbbSJaakko Heinonen static int 62813c02cbbSJaakko Heinonen alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2) 62913c02cbbSJaakko Heinonen { 63013c02cbbSJaakko Heinonen struct unr *up, *upn; 63113c02cbbSJaakko Heinonen struct unrb *ub; 63213c02cbbSJaakko Heinonen u_int i, last, tl; 63313c02cbbSJaakko Heinonen 63413c02cbbSJaakko Heinonen mtx_assert(uh->mtx, MA_OWNED); 63513c02cbbSJaakko Heinonen 63613c02cbbSJaakko Heinonen if (item < uh->low + uh->first || item > uh->high) 63713c02cbbSJaakko Heinonen return (-1); 63813c02cbbSJaakko Heinonen 63913c02cbbSJaakko Heinonen up = TAILQ_FIRST(&uh->head); 64013c02cbbSJaakko Heinonen /* Ideal split. */ 64113c02cbbSJaakko Heinonen if (up == NULL && item - uh->low == uh->first) { 64213c02cbbSJaakko Heinonen uh->first++; 64313c02cbbSJaakko Heinonen uh->last--; 64413c02cbbSJaakko Heinonen uh->busy++; 64513c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 64613c02cbbSJaakko Heinonen return (item); 64713c02cbbSJaakko Heinonen } 64813c02cbbSJaakko Heinonen 64913c02cbbSJaakko Heinonen i = item - uh->low - uh->first; 65013c02cbbSJaakko Heinonen 65113c02cbbSJaakko Heinonen if (up == NULL) { 65213c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 65313c02cbbSJaakko Heinonen up->ptr = NULL; 65413c02cbbSJaakko Heinonen up->len = i; 65513c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 65613c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 65713c02cbbSJaakko Heinonen up->ptr = uh; 65813c02cbbSJaakko Heinonen up->len = 1; 65913c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 66013c02cbbSJaakko Heinonen uh->last = uh->high - uh->low - i; 66113c02cbbSJaakko Heinonen uh->busy++; 66213c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 66313c02cbbSJaakko Heinonen return (item); 66413c02cbbSJaakko Heinonen } else { 66513c02cbbSJaakko Heinonen /* Find the item which contains the unit we want to allocate. */ 66613c02cbbSJaakko Heinonen TAILQ_FOREACH(up, &uh->head, list) { 66713c02cbbSJaakko Heinonen if (up->len > i) 66813c02cbbSJaakko Heinonen break; 66913c02cbbSJaakko Heinonen i -= up->len; 67013c02cbbSJaakko Heinonen } 67113c02cbbSJaakko Heinonen } 67213c02cbbSJaakko Heinonen 67313c02cbbSJaakko Heinonen if (up == NULL) { 67413c02cbbSJaakko Heinonen if (i > 0) { 67513c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 67613c02cbbSJaakko Heinonen up->ptr = NULL; 67713c02cbbSJaakko Heinonen up->len = i; 67813c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 67913c02cbbSJaakko Heinonen } 68013c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 68113c02cbbSJaakko Heinonen up->ptr = uh; 68213c02cbbSJaakko Heinonen up->len = 1; 68313c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 68413c02cbbSJaakko Heinonen goto done; 68513c02cbbSJaakko Heinonen } 68613c02cbbSJaakko Heinonen 68713c02cbbSJaakko Heinonen if (is_bitmap(uh, up)) { 68813c02cbbSJaakko Heinonen ub = up->ptr; 68913c02cbbSJaakko Heinonen if (bit_test(ub->map, i) == 0) { 69013c02cbbSJaakko Heinonen bit_set(ub->map, i); 69113c02cbbSJaakko Heinonen ub->busy++; 69213c02cbbSJaakko Heinonen goto done; 69313c02cbbSJaakko Heinonen } else 69413c02cbbSJaakko Heinonen return (-1); 69513c02cbbSJaakko Heinonen } else if (up->ptr == uh) 69613c02cbbSJaakko Heinonen return (-1); 69713c02cbbSJaakko Heinonen 69813c02cbbSJaakko Heinonen KASSERT(up->ptr == NULL, 69913c02cbbSJaakko Heinonen ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up)); 70013c02cbbSJaakko Heinonen 70113c02cbbSJaakko Heinonen /* Split off the tail end, if any. */ 70213c02cbbSJaakko Heinonen tl = up->len - (1 + i); 70313c02cbbSJaakko Heinonen if (tl > 0) { 70413c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 70513c02cbbSJaakko Heinonen upn->ptr = NULL; 70613c02cbbSJaakko Heinonen upn->len = tl; 70713c02cbbSJaakko Heinonen TAILQ_INSERT_AFTER(&uh->head, up, upn, list); 70813c02cbbSJaakko Heinonen } 70913c02cbbSJaakko Heinonen 71013c02cbbSJaakko Heinonen /* Split off head end, if any */ 71113c02cbbSJaakko Heinonen if (i > 0) { 71213c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 71313c02cbbSJaakko Heinonen upn->len = i; 71413c02cbbSJaakko Heinonen upn->ptr = NULL; 71513c02cbbSJaakko Heinonen TAILQ_INSERT_BEFORE(up, upn, list); 71613c02cbbSJaakko Heinonen } 71713c02cbbSJaakko Heinonen up->len = 1; 71813c02cbbSJaakko Heinonen up->ptr = uh; 71913c02cbbSJaakko Heinonen 72013c02cbbSJaakko Heinonen done: 72113c02cbbSJaakko Heinonen last = uh->high - uh->low - (item - uh->low); 72213c02cbbSJaakko Heinonen if (uh->last > last) 72313c02cbbSJaakko Heinonen uh->last = last; 72413c02cbbSJaakko Heinonen uh->busy++; 72513c02cbbSJaakko Heinonen collapse_unr(uh, up); 72613c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 72713c02cbbSJaakko Heinonen return (item); 72813c02cbbSJaakko Heinonen } 72913c02cbbSJaakko Heinonen 73013c02cbbSJaakko Heinonen int 73113c02cbbSJaakko Heinonen alloc_unr_specific(struct unrhdr *uh, u_int item) 73213c02cbbSJaakko Heinonen { 73313c02cbbSJaakko Heinonen void *p1, *p2; 73413c02cbbSJaakko Heinonen int i; 73513c02cbbSJaakko Heinonen 73613c02cbbSJaakko Heinonen WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific"); 73713c02cbbSJaakko Heinonen 73813c02cbbSJaakko Heinonen p1 = Malloc(sizeof(struct unr)); 73913c02cbbSJaakko Heinonen p2 = Malloc(sizeof(struct unr)); 74013c02cbbSJaakko Heinonen 74113c02cbbSJaakko Heinonen mtx_lock(uh->mtx); 74213c02cbbSJaakko Heinonen i = alloc_unr_specificl(uh, item, &p1, &p2); 74313c02cbbSJaakko Heinonen mtx_unlock(uh->mtx); 74413c02cbbSJaakko Heinonen 74513c02cbbSJaakko Heinonen if (p1 != NULL) 74613c02cbbSJaakko Heinonen Free(p1); 74713c02cbbSJaakko Heinonen if (p2 != NULL) 74813c02cbbSJaakko Heinonen Free(p2); 74913c02cbbSJaakko Heinonen 75013c02cbbSJaakko Heinonen return (i); 75113c02cbbSJaakko Heinonen } 75213c02cbbSJaakko Heinonen 753f6bde1fdSPoul-Henning Kamp /* 754f6bde1fdSPoul-Henning Kamp * Free a unr. 755f6bde1fdSPoul-Henning Kamp * 756f6bde1fdSPoul-Henning Kamp * If we can save unrs by using a bitmap, do so. 757f6bde1fdSPoul-Henning Kamp */ 758d9a54d5cSPoul-Henning Kamp static void 759d9a54d5cSPoul-Henning Kamp free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2) 760f6bde1fdSPoul-Henning Kamp { 761d9a54d5cSPoul-Henning Kamp struct unr *up, *upp, *upn; 762d9a54d5cSPoul-Henning Kamp struct unrb *ub; 763d9a54d5cSPoul-Henning Kamp u_int pl; 764f6bde1fdSPoul-Henning Kamp 765f6bde1fdSPoul-Henning Kamp KASSERT(item >= uh->low && item <= uh->high, 766f6bde1fdSPoul-Henning Kamp ("UNR: free_unr(%u) out of range [%u...%u]", 767f6bde1fdSPoul-Henning Kamp item, uh->low, uh->high)); 768f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 769f6bde1fdSPoul-Henning Kamp item -= uh->low; 770d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 771f6bde1fdSPoul-Henning Kamp /* 772d9a54d5cSPoul-Henning Kamp * Freeing in the ideal split case 773f6bde1fdSPoul-Henning Kamp */ 774d9a54d5cSPoul-Henning Kamp if (item + 1 == uh->first && upp == NULL) { 775d9a54d5cSPoul-Henning Kamp uh->last++; 776d9a54d5cSPoul-Henning Kamp uh->first--; 777d9a54d5cSPoul-Henning Kamp uh->busy--; 778f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 779f6bde1fdSPoul-Henning Kamp return; 780f6bde1fdSPoul-Henning Kamp } 781d9a54d5cSPoul-Henning Kamp /* 782d9a54d5cSPoul-Henning Kamp * Freeing in the ->first section. Create a run starting at the 783d9a54d5cSPoul-Henning Kamp * freed item. The code below will subdivide it. 784d9a54d5cSPoul-Henning Kamp */ 785d9a54d5cSPoul-Henning Kamp if (item < uh->first) { 786d9a54d5cSPoul-Henning Kamp up = new_unr(uh, p1, p2); 787d9a54d5cSPoul-Henning Kamp up->ptr = uh; 788d9a54d5cSPoul-Henning Kamp up->len = uh->first - item; 789d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_HEAD(&uh->head, up, list); 790d9a54d5cSPoul-Henning Kamp uh->first -= up->len; 791f6bde1fdSPoul-Henning Kamp } 792f6bde1fdSPoul-Henning Kamp 793d9a54d5cSPoul-Henning Kamp item -= uh->first; 794d9a54d5cSPoul-Henning Kamp 795d9a54d5cSPoul-Henning Kamp /* Find the item which contains the unit we want to free */ 796d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 797d9a54d5cSPoul-Henning Kamp if (up->len > item) 798d9a54d5cSPoul-Henning Kamp break; 799d9a54d5cSPoul-Henning Kamp item -= up->len; 800d9a54d5cSPoul-Henning Kamp } 801d9a54d5cSPoul-Henning Kamp 802d9a54d5cSPoul-Henning Kamp /* Handle bitmap items */ 803d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 804d9a54d5cSPoul-Henning Kamp ub = up->ptr; 805d9a54d5cSPoul-Henning Kamp 806d9a54d5cSPoul-Henning Kamp KASSERT(bit_test(ub->map, item) != 0, 807d9a54d5cSPoul-Henning Kamp ("UNR: Freeing free item %d (bitmap)\n", item)); 808d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, item); 809d9a54d5cSPoul-Henning Kamp uh->busy--; 810d9a54d5cSPoul-Henning Kamp ub->busy--; 811d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 812d9a54d5cSPoul-Henning Kamp return; 813d9a54d5cSPoul-Henning Kamp } 814d9a54d5cSPoul-Henning Kamp 815d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item)); 816f6bde1fdSPoul-Henning Kamp 817f6bde1fdSPoul-Henning Kamp /* Just this one left, reap it */ 818f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 819f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 820f6bde1fdSPoul-Henning Kamp uh->busy--; 821f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 822f6bde1fdSPoul-Henning Kamp return; 823f6bde1fdSPoul-Henning Kamp } 824f6bde1fdSPoul-Henning Kamp 825d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item into the previous 'free' run */ 826f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 827d9a54d5cSPoul-Henning Kamp if (item == 0 && upp != NULL && upp->ptr == NULL) { 828f6bde1fdSPoul-Henning Kamp upp->len++; 829f6bde1fdSPoul-Henning Kamp up->len--; 830f6bde1fdSPoul-Henning Kamp uh->busy--; 831d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 832f6bde1fdSPoul-Henning Kamp return; 833f6bde1fdSPoul-Henning Kamp } 834f6bde1fdSPoul-Henning Kamp 835d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item to the next 'free' run */ 836f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(up, list); 837d9a54d5cSPoul-Henning Kamp if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) { 838f6bde1fdSPoul-Henning Kamp upn->len++; 839f6bde1fdSPoul-Henning Kamp up->len--; 840f6bde1fdSPoul-Henning Kamp uh->busy--; 841d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 842f6bde1fdSPoul-Henning Kamp return; 843f6bde1fdSPoul-Henning Kamp } 844f6bde1fdSPoul-Henning Kamp 845f6bde1fdSPoul-Henning Kamp /* Split off the tail end, if any. */ 846d9a54d5cSPoul-Henning Kamp pl = up->len - (1 + item); 847f6bde1fdSPoul-Henning Kamp if (pl > 0) { 848d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 849f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 850f6bde1fdSPoul-Henning Kamp upp->len = pl; 851f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 852f6bde1fdSPoul-Henning Kamp } 853f6bde1fdSPoul-Henning Kamp 854d9a54d5cSPoul-Henning Kamp /* Split off head end, if any */ 855d9a54d5cSPoul-Henning Kamp if (item > 0) { 856d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 857d9a54d5cSPoul-Henning Kamp upp->len = item; 858d9a54d5cSPoul-Henning Kamp upp->ptr = uh; 859d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_BEFORE(up, upp, list); 860d9a54d5cSPoul-Henning Kamp } 861f6bde1fdSPoul-Henning Kamp up->len = 1; 862f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 863f6bde1fdSPoul-Henning Kamp uh->busy--; 864d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 865f6bde1fdSPoul-Henning Kamp } 866f6bde1fdSPoul-Henning Kamp 867d9a54d5cSPoul-Henning Kamp void 868d9a54d5cSPoul-Henning Kamp free_unr(struct unrhdr *uh, u_int item) 869d9a54d5cSPoul-Henning Kamp { 870d9a54d5cSPoul-Henning Kamp void *p1, *p2; 871f6bde1fdSPoul-Henning Kamp 8727550e3eaSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr"); 873d9a54d5cSPoul-Henning Kamp p1 = Malloc(sizeof(struct unr)); 874d9a54d5cSPoul-Henning Kamp p2 = Malloc(sizeof(struct unr)); 875d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 876d9a54d5cSPoul-Henning Kamp free_unrl(uh, item, &p1, &p2); 87709828ba9SKonstantin Belousov clean_unrhdrl(uh); 878d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 879d9a54d5cSPoul-Henning Kamp if (p1 != NULL) 880d9a54d5cSPoul-Henning Kamp Free(p1); 881d9a54d5cSPoul-Henning Kamp if (p2 != NULL) 882d9a54d5cSPoul-Henning Kamp Free(p2); 883f6bde1fdSPoul-Henning Kamp } 884f6bde1fdSPoul-Henning Kamp 88593f6c81eSPoul-Henning Kamp #ifndef _KERNEL /* USERLAND test driver */ 88693f6c81eSPoul-Henning Kamp 887f6bde1fdSPoul-Henning Kamp /* 888*794277daSAlan Somers * Simple stochastic test driver for the above functions. The code resides 889*794277daSAlan Somers * here so that it can access static functions and structures. 890f6bde1fdSPoul-Henning Kamp */ 891f6bde1fdSPoul-Henning Kamp 892*794277daSAlan Somers static bool verbose; 893*794277daSAlan Somers #define VPRINTF(...) {if (verbose) printf(__VA_ARGS__);} 894*794277daSAlan Somers 895f6bde1fdSPoul-Henning Kamp static void 896f6bde1fdSPoul-Henning Kamp print_unr(struct unrhdr *uh, struct unr *up) 897f6bde1fdSPoul-Henning Kamp { 898f6bde1fdSPoul-Henning Kamp u_int x; 899d9a54d5cSPoul-Henning Kamp struct unrb *ub; 900f6bde1fdSPoul-Henning Kamp 901f6bde1fdSPoul-Henning Kamp printf(" %p len = %5u ", up, up->len); 902f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL) 903f6bde1fdSPoul-Henning Kamp printf("free\n"); 904f6bde1fdSPoul-Henning Kamp else if (up->ptr == uh) 905f6bde1fdSPoul-Henning Kamp printf("alloc\n"); 906f6bde1fdSPoul-Henning Kamp else { 907d9a54d5cSPoul-Henning Kamp ub = up->ptr; 908d9a54d5cSPoul-Henning Kamp printf("bitmap(%d) [", ub->busy); 909d9a54d5cSPoul-Henning Kamp for (x = 0; x < up->len; x++) { 910d9a54d5cSPoul-Henning Kamp if (bit_test(ub->map, x)) 911d9a54d5cSPoul-Henning Kamp printf("#"); 912f6bde1fdSPoul-Henning Kamp else 913d9a54d5cSPoul-Henning Kamp printf(" "); 914f6bde1fdSPoul-Henning Kamp } 915f6bde1fdSPoul-Henning Kamp printf("]\n"); 916f6bde1fdSPoul-Henning Kamp } 917f6bde1fdSPoul-Henning Kamp } 918f6bde1fdSPoul-Henning Kamp 919f6bde1fdSPoul-Henning Kamp static void 920f6bde1fdSPoul-Henning Kamp print_unrhdr(struct unrhdr *uh) 921f6bde1fdSPoul-Henning Kamp { 922f6bde1fdSPoul-Henning Kamp struct unr *up; 923f6bde1fdSPoul-Henning Kamp u_int x; 924f6bde1fdSPoul-Henning Kamp 925d9a54d5cSPoul-Henning Kamp printf( 926d9a54d5cSPoul-Henning Kamp "%p low = %u high = %u first = %u last = %u busy %u chunks = %u\n", 927d9a54d5cSPoul-Henning Kamp uh, uh->low, uh->high, uh->first, uh->last, uh->busy, uh->alloc); 928d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 929f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 930f6bde1fdSPoul-Henning Kamp printf(" from = %5u", x); 931f6bde1fdSPoul-Henning Kamp print_unr(uh, up); 932f6bde1fdSPoul-Henning Kamp if (up->ptr == NULL || up->ptr == uh) 933f6bde1fdSPoul-Henning Kamp x += up->len; 934f6bde1fdSPoul-Henning Kamp else 935f6bde1fdSPoul-Henning Kamp x += NBITS; 936f6bde1fdSPoul-Henning Kamp } 937f6bde1fdSPoul-Henning Kamp } 938f6bde1fdSPoul-Henning Kamp 93913c02cbbSJaakko Heinonen static void 94013c02cbbSJaakko Heinonen test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) 94113c02cbbSJaakko Heinonen { 94213c02cbbSJaakko Heinonen int j; 94313c02cbbSJaakko Heinonen 94413c02cbbSJaakko Heinonen if (a[i]) { 945*794277daSAlan Somers VPRINTF("F %u\n", i); 94613c02cbbSJaakko Heinonen free_unr(uh, i); 94713c02cbbSJaakko Heinonen a[i] = 0; 94813c02cbbSJaakko Heinonen } else { 94913c02cbbSJaakko Heinonen no_alloc = 1; 95013c02cbbSJaakko Heinonen j = alloc_unr(uh); 95113c02cbbSJaakko Heinonen if (j != -1) { 95213c02cbbSJaakko Heinonen a[j] = 1; 953*794277daSAlan Somers VPRINTF("A %d\n", j); 95413c02cbbSJaakko Heinonen } 95513c02cbbSJaakko Heinonen no_alloc = 0; 95613c02cbbSJaakko Heinonen } 95713c02cbbSJaakko Heinonen } 95813c02cbbSJaakko Heinonen 95913c02cbbSJaakko Heinonen static void 96013c02cbbSJaakko Heinonen test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[]) 96113c02cbbSJaakko Heinonen { 96213c02cbbSJaakko Heinonen int j; 96313c02cbbSJaakko Heinonen 96413c02cbbSJaakko Heinonen j = alloc_unr_specific(uh, i); 96513c02cbbSJaakko Heinonen if (j == -1) { 966*794277daSAlan Somers VPRINTF("F %u\n", i); 96713c02cbbSJaakko Heinonen a[i] = 0; 96813c02cbbSJaakko Heinonen free_unr(uh, i); 96913c02cbbSJaakko Heinonen } else { 97013c02cbbSJaakko Heinonen a[i] = 1; 971*794277daSAlan Somers VPRINTF("A %d\n", j); 97213c02cbbSJaakko Heinonen } 97313c02cbbSJaakko Heinonen } 97413c02cbbSJaakko Heinonen 975*794277daSAlan Somers static void 976*794277daSAlan Somers usage(char** argv) 977*794277daSAlan Somers { 978*794277daSAlan Somers printf("%s [-h] [-r REPETITIONS] [-v]\n", argv[0]); 979*794277daSAlan Somers } 980f6bde1fdSPoul-Henning Kamp 981f6bde1fdSPoul-Henning Kamp int 982*794277daSAlan Somers main(int argc, char **argv) 983f6bde1fdSPoul-Henning Kamp { 984f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 985*794277daSAlan Somers char *a; 986*794277daSAlan Somers long count = 10000; /* Number of unrs to test */ 987*794277daSAlan Somers long reps = 1; 988*794277daSAlan Somers int ch; 989d9a54d5cSPoul-Henning Kamp u_int i, x, m, j; 990*794277daSAlan Somers 991*794277daSAlan Somers verbose = false; 992*794277daSAlan Somers 993*794277daSAlan Somers while ((ch = getopt(argc, argv, "hr:v")) != -1) { 994*794277daSAlan Somers switch (ch) { 995*794277daSAlan Somers case 'r': 996*794277daSAlan Somers errno = 0; 997*794277daSAlan Somers reps = strtol(optarg, NULL, 0); 998*794277daSAlan Somers if (errno == ERANGE || errno == EINVAL) { 999*794277daSAlan Somers usage(argv); 1000*794277daSAlan Somers exit(2); 1001*794277daSAlan Somers } 1002*794277daSAlan Somers 1003*794277daSAlan Somers break; 1004*794277daSAlan Somers case 'v': 1005*794277daSAlan Somers verbose = true; 1006*794277daSAlan Somers break; 1007*794277daSAlan Somers case 'h': 1008*794277daSAlan Somers default: 1009*794277daSAlan Somers usage(argv); 1010*794277daSAlan Somers exit(2); 1011*794277daSAlan Somers } 1012*794277daSAlan Somers 1013*794277daSAlan Somers 1014*794277daSAlan Somers } 1015f6bde1fdSPoul-Henning Kamp 1016d9a54d5cSPoul-Henning Kamp setbuf(stdout, NULL); 1017*794277daSAlan Somers uh = new_unrhdr(0, count - 1, NULL); 1018d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1019f6bde1fdSPoul-Henning Kamp 1020*794277daSAlan Somers a = calloc(count, sizeof(char)); 1021*794277daSAlan Somers if (a == NULL) 1022*794277daSAlan Somers err(1, "calloc failed"); 102313c02cbbSJaakko Heinonen srandomdev(); 1024f6bde1fdSPoul-Henning Kamp 1025*794277daSAlan Somers printf("sizeof(struct unr) %zu\n", sizeof(struct unr)); 1026*794277daSAlan Somers printf("sizeof(struct unrb) %zu\n", sizeof(struct unrb)); 1027*794277daSAlan Somers printf("sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); 1028*794277daSAlan Somers printf("NBITS %d\n", NBITS); 1029f6bde1fdSPoul-Henning Kamp x = 1; 1030*794277daSAlan Somers for (m = 0; m < count * reps; m++) { 1031d9a54d5cSPoul-Henning Kamp j = random(); 1032*794277daSAlan Somers i = (j >> 1) % count; 1033d9a54d5cSPoul-Henning Kamp #if 0 1034d9a54d5cSPoul-Henning Kamp if (a[i] && (j & 1)) 1035d9a54d5cSPoul-Henning Kamp continue; 1036d9a54d5cSPoul-Henning Kamp #endif 103713c02cbbSJaakko Heinonen if ((random() & 1) != 0) 103813c02cbbSJaakko Heinonen test_alloc_unr(uh, i, a); 103913c02cbbSJaakko Heinonen else 104013c02cbbSJaakko Heinonen test_alloc_unr_specific(uh, i, a); 104113c02cbbSJaakko Heinonen 1042*794277daSAlan Somers if (verbose) 1043f6bde1fdSPoul-Henning Kamp print_unrhdr(uh); 1044f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 1045f6bde1fdSPoul-Henning Kamp } 1046*794277daSAlan Somers for (i = 0; i < count; i++) { 1047d9a54d5cSPoul-Henning Kamp if (a[i]) { 1048*794277daSAlan Somers if (verbose) { 1049d9a54d5cSPoul-Henning Kamp printf("C %u\n", i); 1050e4fea39eSPoul-Henning Kamp print_unrhdr(uh); 1051d9a54d5cSPoul-Henning Kamp } 1052*794277daSAlan Somers free_unr(uh, i); 1053*794277daSAlan Somers } 1054d9a54d5cSPoul-Henning Kamp } 1055d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1056e4fea39eSPoul-Henning Kamp delete_unrhdr(uh); 1057*794277daSAlan Somers free(a); 1058f6bde1fdSPoul-Henning Kamp return (0); 1059f6bde1fdSPoul-Henning Kamp } 1060f6bde1fdSPoul-Henning Kamp #endif 1061