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 44d9a54d5cSPoul-Henning Kamp * that the 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 * 55d9a54d5cSPoul-Henning Kamp * Memory usage is a very complex function of the 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 66d9a54d5cSPoul-Henning Kamp * the 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> 71f6bde1fdSPoul-Henning Kamp #include <sys/queue.h> 72f6bde1fdSPoul-Henning Kamp #include <sys/bitstring.h> 73f6bde1fdSPoul-Henning Kamp 74f6bde1fdSPoul-Henning Kamp #ifdef _KERNEL 75f6bde1fdSPoul-Henning Kamp 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 101f6bde1fdSPoul-Henning Kamp #include <stdio.h> 102f6bde1fdSPoul-Henning Kamp #include <stdlib.h> 103d9a54d5cSPoul-Henning Kamp #include <string.h> 104f6bde1fdSPoul-Henning Kamp 105f6bde1fdSPoul-Henning Kamp #define KASSERT(cond, arg) \ 106f6bde1fdSPoul-Henning Kamp do { \ 107f6bde1fdSPoul-Henning Kamp if (!(cond)) { \ 108f6bde1fdSPoul-Henning Kamp printf arg; \ 109d9a54d5cSPoul-Henning Kamp abort(); \ 110f6bde1fdSPoul-Henning Kamp } \ 111f6bde1fdSPoul-Henning Kamp } while (0) 112f6bde1fdSPoul-Henning Kamp 113d9a54d5cSPoul-Henning Kamp static int no_alloc; 114d9a54d5cSPoul-Henning Kamp #define Malloc(foo) _Malloc(foo, __LINE__) 115d9a54d5cSPoul-Henning Kamp static void * 116d9a54d5cSPoul-Henning Kamp _Malloc(size_t foo, int line) 117d9a54d5cSPoul-Henning Kamp { 118d9a54d5cSPoul-Henning Kamp 119d9a54d5cSPoul-Henning Kamp KASSERT(no_alloc == 0, ("malloc in wrong place() line %d", line)); 120d9a54d5cSPoul-Henning Kamp return (calloc(foo, 1)); 121d9a54d5cSPoul-Henning Kamp } 122f6bde1fdSPoul-Henning Kamp #define Free(foo) free(foo) 123f6bde1fdSPoul-Henning Kamp 124d9a54d5cSPoul-Henning Kamp struct unrhdr; 125d9a54d5cSPoul-Henning Kamp 126d9a54d5cSPoul-Henning Kamp 127d9a54d5cSPoul-Henning Kamp struct mtx { 128d9a54d5cSPoul-Henning Kamp int state; 129d9a54d5cSPoul-Henning Kamp } unitmtx; 130d9a54d5cSPoul-Henning Kamp 131d9a54d5cSPoul-Henning Kamp static void 132d9a54d5cSPoul-Henning Kamp mtx_lock(struct mtx *mp) 133d9a54d5cSPoul-Henning Kamp { 134d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 0, ("mutex already locked")); 135d9a54d5cSPoul-Henning Kamp mp->state = 1; 136d9a54d5cSPoul-Henning Kamp } 137d9a54d5cSPoul-Henning Kamp 138d9a54d5cSPoul-Henning Kamp static void 139d9a54d5cSPoul-Henning Kamp mtx_unlock(struct mtx *mp) 140d9a54d5cSPoul-Henning Kamp { 141d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mutex not locked")); 142d9a54d5cSPoul-Henning Kamp mp->state = 0; 143d9a54d5cSPoul-Henning Kamp } 144d9a54d5cSPoul-Henning Kamp 145d9a54d5cSPoul-Henning Kamp #define MA_OWNED 9 146d9a54d5cSPoul-Henning Kamp 147d9a54d5cSPoul-Henning Kamp static void 148d9a54d5cSPoul-Henning Kamp mtx_assert(struct mtx *mp, int flag) 149d9a54d5cSPoul-Henning Kamp { 150d9a54d5cSPoul-Henning Kamp if (flag == MA_OWNED) { 151d9a54d5cSPoul-Henning Kamp KASSERT(mp->state == 1, ("mtx_assert(MA_OWNED) not true")); 152d9a54d5cSPoul-Henning Kamp } 153d9a54d5cSPoul-Henning Kamp } 154d9a54d5cSPoul-Henning Kamp 155d9a54d5cSPoul-Henning Kamp #define CTASSERT(foo) 15624e8eaf1SJaakko Heinonen #define WITNESS_WARN(flags, lock, fmt, ...) (void)0 157d9a54d5cSPoul-Henning Kamp 158d9a54d5cSPoul-Henning Kamp #endif /* USERLAND */ 159f6bde1fdSPoul-Henning Kamp 160f6bde1fdSPoul-Henning Kamp /* 161f6bde1fdSPoul-Henning Kamp * This is our basic building block. 162f6bde1fdSPoul-Henning Kamp * 163f6bde1fdSPoul-Henning Kamp * It can be used in three different ways depending on the value of the ptr 164f6bde1fdSPoul-Henning Kamp * element: 165f6bde1fdSPoul-Henning Kamp * If ptr is NULL, it represents a run of free items. 166f6bde1fdSPoul-Henning Kamp * If ptr points to the unrhdr it represents a run of allocated items. 167f6bde1fdSPoul-Henning Kamp * Otherwise it points to an bitstring of allocated items. 168f6bde1fdSPoul-Henning Kamp * 169f6bde1fdSPoul-Henning Kamp * For runs the len field is the length of the run. 170f6bde1fdSPoul-Henning Kamp * For bitmaps the len field represents the number of allocated items. 171f6bde1fdSPoul-Henning Kamp * 172f6bde1fdSPoul-Henning Kamp * The bitmap is the same size as struct unr to optimize memory management. 173f6bde1fdSPoul-Henning Kamp */ 174f6bde1fdSPoul-Henning Kamp struct unr { 175f6bde1fdSPoul-Henning Kamp TAILQ_ENTRY(unr) list; 176f6bde1fdSPoul-Henning Kamp u_int len; 177f6bde1fdSPoul-Henning Kamp void *ptr; 178f6bde1fdSPoul-Henning Kamp }; 179f6bde1fdSPoul-Henning Kamp 180d9a54d5cSPoul-Henning Kamp struct unrb { 181d9a54d5cSPoul-Henning Kamp u_char busy; 182d9a54d5cSPoul-Henning Kamp bitstr_t map[sizeof(struct unr) - 1]; 183d9a54d5cSPoul-Henning Kamp }; 184d9a54d5cSPoul-Henning Kamp 185d9a54d5cSPoul-Henning Kamp CTASSERT(sizeof(struct unr) == sizeof(struct unrb)); 186d9a54d5cSPoul-Henning Kamp 187f6bde1fdSPoul-Henning Kamp /* Number of bits in the bitmap */ 188d9a54d5cSPoul-Henning Kamp #define NBITS ((int)sizeof(((struct unrb *)NULL)->map) * 8) 189f6bde1fdSPoul-Henning Kamp 190f6bde1fdSPoul-Henning Kamp /* Header element for a unr number space. */ 191f6bde1fdSPoul-Henning Kamp 192f6bde1fdSPoul-Henning Kamp struct unrhdr { 193f6bde1fdSPoul-Henning Kamp TAILQ_HEAD(unrhd,unr) head; 194f6bde1fdSPoul-Henning Kamp u_int low; /* Lowest item */ 195f6bde1fdSPoul-Henning Kamp u_int high; /* Highest item */ 196f6bde1fdSPoul-Henning Kamp u_int busy; /* Count of allocated items */ 197f6bde1fdSPoul-Henning Kamp u_int alloc; /* Count of memory allocations */ 198d9a54d5cSPoul-Henning Kamp u_int first; /* items in allocated from start */ 199d9a54d5cSPoul-Henning Kamp u_int last; /* items free at end */ 200d9a54d5cSPoul-Henning Kamp struct mtx *mtx; 20109828ba9SKonstantin Belousov TAILQ_HEAD(unrfr,unr) ppfree; /* Items to be freed after mtx 20209828ba9SKonstantin Belousov lock dropped */ 203f6bde1fdSPoul-Henning Kamp }; 204f6bde1fdSPoul-Henning Kamp 205f6bde1fdSPoul-Henning Kamp 206f6bde1fdSPoul-Henning Kamp #if defined(DIAGNOSTIC) || !defined(_KERNEL) 207f6bde1fdSPoul-Henning Kamp /* 208f6bde1fdSPoul-Henning Kamp * Consistency check function. 209f6bde1fdSPoul-Henning Kamp * 210f6bde1fdSPoul-Henning Kamp * Checks the internal consistency as well as we can. 211f6bde1fdSPoul-Henning Kamp * 212f6bde1fdSPoul-Henning Kamp * Called at all boundaries of this API. 213f6bde1fdSPoul-Henning Kamp */ 214f6bde1fdSPoul-Henning Kamp static void 215f6bde1fdSPoul-Henning Kamp check_unrhdr(struct unrhdr *uh, int line) 216f6bde1fdSPoul-Henning Kamp { 217f6bde1fdSPoul-Henning Kamp struct unr *up; 218d9a54d5cSPoul-Henning Kamp struct unrb *ub; 219f6bde1fdSPoul-Henning Kamp u_int x, y, z, w; 220f6bde1fdSPoul-Henning Kamp 221d9a54d5cSPoul-Henning Kamp y = uh->first; 222f6bde1fdSPoul-Henning Kamp z = 0; 223f6bde1fdSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 224f6bde1fdSPoul-Henning Kamp z++; 225f6bde1fdSPoul-Henning Kamp if (up->ptr != uh && up->ptr != NULL) { 226d9a54d5cSPoul-Henning Kamp ub = up->ptr; 227d9a54d5cSPoul-Henning Kamp KASSERT (up->len <= NBITS, 228d9a54d5cSPoul-Henning Kamp ("UNR inconsistency: len %u max %d (line %d)\n", 229d9a54d5cSPoul-Henning Kamp up->len, NBITS, line)); 230f6bde1fdSPoul-Henning Kamp z++; 231f6bde1fdSPoul-Henning Kamp w = 0; 232d9a54d5cSPoul-Henning Kamp for (x = 0; x < up->len; x++) 233d9a54d5cSPoul-Henning Kamp if (bit_test(ub->map, x)) 234f6bde1fdSPoul-Henning Kamp w++; 235d9a54d5cSPoul-Henning Kamp KASSERT (w == ub->busy, 236d9a54d5cSPoul-Henning Kamp ("UNR inconsistency: busy %u found %u (line %d)\n", 237d9a54d5cSPoul-Henning Kamp ub->busy, w, line)); 238d9a54d5cSPoul-Henning Kamp y += w; 239d9a54d5cSPoul-Henning Kamp } else if (up->ptr != NULL) 240f6bde1fdSPoul-Henning Kamp y += up->len; 241f6bde1fdSPoul-Henning Kamp } 242f6bde1fdSPoul-Henning Kamp KASSERT (y == uh->busy, 243f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: items %u found %u (line %d)\n", 244f6bde1fdSPoul-Henning Kamp uh->busy, y, line)); 245f6bde1fdSPoul-Henning Kamp KASSERT (z == uh->alloc, 246f6bde1fdSPoul-Henning Kamp ("UNR inconsistency: chunks %u found %u (line %d)\n", 247f6bde1fdSPoul-Henning Kamp uh->alloc, z, line)); 248f6bde1fdSPoul-Henning Kamp } 249f6bde1fdSPoul-Henning Kamp 250f6bde1fdSPoul-Henning Kamp #else 251f6bde1fdSPoul-Henning Kamp 252f6bde1fdSPoul-Henning Kamp static __inline void 2534a2aa5d0SJohn Baldwin check_unrhdr(struct unrhdr *uh, int line) 254f6bde1fdSPoul-Henning Kamp { 255f6bde1fdSPoul-Henning Kamp 256f6bde1fdSPoul-Henning Kamp } 257f6bde1fdSPoul-Henning Kamp 258f6bde1fdSPoul-Henning Kamp #endif 259f6bde1fdSPoul-Henning Kamp 260f6bde1fdSPoul-Henning Kamp 261f6bde1fdSPoul-Henning Kamp /* 262f6bde1fdSPoul-Henning Kamp * Userland memory management. Just use calloc and keep track of how 263f6bde1fdSPoul-Henning Kamp * many elements we have allocated for check_unrhdr(). 264f6bde1fdSPoul-Henning Kamp */ 265f6bde1fdSPoul-Henning Kamp 266f6bde1fdSPoul-Henning Kamp static __inline void * 267d9a54d5cSPoul-Henning Kamp new_unr(struct unrhdr *uh, void **p1, void **p2) 268f6bde1fdSPoul-Henning Kamp { 269d9a54d5cSPoul-Henning Kamp void *p; 270f6bde1fdSPoul-Henning Kamp 271d9a54d5cSPoul-Henning Kamp uh->alloc++; 272d9a54d5cSPoul-Henning Kamp KASSERT(*p1 != NULL || *p2 != NULL, ("Out of cached memory")); 273d9a54d5cSPoul-Henning Kamp if (*p1 != NULL) { 274d9a54d5cSPoul-Henning Kamp p = *p1; 275d9a54d5cSPoul-Henning Kamp *p1 = NULL; 276d9a54d5cSPoul-Henning Kamp return (p); 277d9a54d5cSPoul-Henning Kamp } else { 278d9a54d5cSPoul-Henning Kamp p = *p2; 279d9a54d5cSPoul-Henning Kamp *p2 = NULL; 280d9a54d5cSPoul-Henning Kamp return (p); 281d9a54d5cSPoul-Henning Kamp } 282f6bde1fdSPoul-Henning Kamp } 283f6bde1fdSPoul-Henning Kamp 284f6bde1fdSPoul-Henning Kamp static __inline void 285f6bde1fdSPoul-Henning Kamp delete_unr(struct unrhdr *uh, void *ptr) 286f6bde1fdSPoul-Henning Kamp { 28709828ba9SKonstantin Belousov struct unr *up; 288d9a54d5cSPoul-Henning Kamp 289f6bde1fdSPoul-Henning Kamp uh->alloc--; 29009828ba9SKonstantin Belousov up = ptr; 29109828ba9SKonstantin Belousov TAILQ_INSERT_TAIL(&uh->ppfree, up, list); 29209828ba9SKonstantin Belousov } 29309828ba9SKonstantin Belousov 29409828ba9SKonstantin Belousov void 29509828ba9SKonstantin Belousov clean_unrhdrl(struct unrhdr *uh) 29609828ba9SKonstantin Belousov { 29709828ba9SKonstantin Belousov struct unr *up; 29809828ba9SKonstantin Belousov 29909828ba9SKonstantin Belousov mtx_assert(uh->mtx, MA_OWNED); 30009828ba9SKonstantin Belousov while ((up = TAILQ_FIRST(&uh->ppfree)) != NULL) { 30109828ba9SKonstantin Belousov TAILQ_REMOVE(&uh->ppfree, up, list); 30209828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 30309828ba9SKonstantin Belousov Free(up); 30409828ba9SKonstantin Belousov mtx_lock(uh->mtx); 30509828ba9SKonstantin Belousov } 30609828ba9SKonstantin Belousov 30709828ba9SKonstantin Belousov } 30809828ba9SKonstantin Belousov 30909828ba9SKonstantin Belousov void 31009828ba9SKonstantin Belousov clean_unrhdr(struct unrhdr *uh) 31109828ba9SKonstantin Belousov { 31209828ba9SKonstantin Belousov 31309828ba9SKonstantin Belousov mtx_lock(uh->mtx); 31409828ba9SKonstantin Belousov clean_unrhdrl(uh); 31509828ba9SKonstantin Belousov mtx_unlock(uh->mtx); 316f6bde1fdSPoul-Henning Kamp } 317f6bde1fdSPoul-Henning Kamp 318f6bde1fdSPoul-Henning Kamp /* 319f6bde1fdSPoul-Henning Kamp * Allocate a new unrheader set. 320f6bde1fdSPoul-Henning Kamp * 321bc96d3d1SJaakko Heinonen * Highest and lowest valid values given as parameters. 322f6bde1fdSPoul-Henning Kamp */ 323f6bde1fdSPoul-Henning Kamp 324f6bde1fdSPoul-Henning Kamp struct unrhdr * 325d9a54d5cSPoul-Henning Kamp new_unrhdr(int low, int high, struct mtx *mutex) 326f6bde1fdSPoul-Henning Kamp { 327f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 328f6bde1fdSPoul-Henning Kamp 329f6bde1fdSPoul-Henning Kamp KASSERT(low <= high, 330f6bde1fdSPoul-Henning Kamp ("UNR: use error: new_unrhdr(%u, %u)", low, high)); 331f6bde1fdSPoul-Henning Kamp uh = Malloc(sizeof *uh); 332d9a54d5cSPoul-Henning Kamp if (mutex != NULL) 333d9a54d5cSPoul-Henning Kamp uh->mtx = mutex; 334d9a54d5cSPoul-Henning Kamp else 335d9a54d5cSPoul-Henning Kamp uh->mtx = &unitmtx; 336f6bde1fdSPoul-Henning Kamp TAILQ_INIT(&uh->head); 33709828ba9SKonstantin Belousov TAILQ_INIT(&uh->ppfree); 338f6bde1fdSPoul-Henning Kamp uh->low = low; 339f6bde1fdSPoul-Henning Kamp uh->high = high; 340d9a54d5cSPoul-Henning Kamp uh->first = 0; 341d9a54d5cSPoul-Henning Kamp uh->last = 1 + (high - low); 342f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 343f6bde1fdSPoul-Henning Kamp return (uh); 344f6bde1fdSPoul-Henning Kamp } 345f6bde1fdSPoul-Henning Kamp 346e4fea39eSPoul-Henning Kamp void 347e4fea39eSPoul-Henning Kamp delete_unrhdr(struct unrhdr *uh) 348e4fea39eSPoul-Henning Kamp { 349e4fea39eSPoul-Henning Kamp 350d9a54d5cSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 351e4fea39eSPoul-Henning Kamp KASSERT(uh->busy == 0, ("unrhdr has %u allocations", uh->busy)); 352e4fea39eSPoul-Henning Kamp KASSERT(uh->alloc == 0, ("UNR memory leak in delete_unrhdr")); 35309828ba9SKonstantin Belousov KASSERT(TAILQ_FIRST(&uh->ppfree) == NULL, 35409828ba9SKonstantin Belousov ("unrhdr has postponed item for free")); 355e4fea39eSPoul-Henning Kamp Free(uh); 356e4fea39eSPoul-Henning Kamp } 357e4fea39eSPoul-Henning Kamp 358d9a54d5cSPoul-Henning Kamp static __inline int 359d9a54d5cSPoul-Henning Kamp is_bitmap(struct unrhdr *uh, struct unr *up) 360d9a54d5cSPoul-Henning Kamp { 361d9a54d5cSPoul-Henning Kamp return (up->ptr != uh && up->ptr != NULL); 362d9a54d5cSPoul-Henning Kamp } 363d9a54d5cSPoul-Henning Kamp 364f6bde1fdSPoul-Henning Kamp /* 365d9a54d5cSPoul-Henning Kamp * Look for sequence of items which can be combined into a bitmap, if 366d9a54d5cSPoul-Henning Kamp * multiple are present, take the one which saves most memory. 367d9a54d5cSPoul-Henning Kamp * 368d9a54d5cSPoul-Henning Kamp * Return (1) if a sequence was found to indicate that another call 369d9a54d5cSPoul-Henning Kamp * might be able to do more. Return (0) if we found no suitable sequence. 370d9a54d5cSPoul-Henning Kamp * 371d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 372d9a54d5cSPoul-Henning Kamp */ 373d9a54d5cSPoul-Henning Kamp static int 374d9a54d5cSPoul-Henning Kamp optimize_unr(struct unrhdr *uh) 375d9a54d5cSPoul-Henning Kamp { 376d9a54d5cSPoul-Henning Kamp struct unr *up, *uf, *us; 377d9a54d5cSPoul-Henning Kamp struct unrb *ub, *ubf; 378d9a54d5cSPoul-Henning Kamp u_int a, l, ba; 379d9a54d5cSPoul-Henning Kamp 380d9a54d5cSPoul-Henning Kamp /* 381d9a54d5cSPoul-Henning Kamp * Look for the run of items (if any) which when collapsed into 382d9a54d5cSPoul-Henning Kamp * a bitmap would save most memory. 383d9a54d5cSPoul-Henning Kamp */ 384d9a54d5cSPoul-Henning Kamp us = NULL; 385d9a54d5cSPoul-Henning Kamp ba = 0; 386d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(uf, &uh->head, list) { 387d9a54d5cSPoul-Henning Kamp if (uf->len >= NBITS) 388d9a54d5cSPoul-Henning Kamp continue; 389d9a54d5cSPoul-Henning Kamp a = 1; 390d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, uf)) 391d9a54d5cSPoul-Henning Kamp a++; 392d9a54d5cSPoul-Henning Kamp l = uf->len; 393d9a54d5cSPoul-Henning Kamp up = uf; 394d9a54d5cSPoul-Henning Kamp while (1) { 395d9a54d5cSPoul-Henning Kamp up = TAILQ_NEXT(up, list); 396d9a54d5cSPoul-Henning Kamp if (up == NULL) 397d9a54d5cSPoul-Henning Kamp break; 398d9a54d5cSPoul-Henning Kamp if ((up->len + l) > NBITS) 399d9a54d5cSPoul-Henning Kamp break; 400d9a54d5cSPoul-Henning Kamp a++; 401d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) 402d9a54d5cSPoul-Henning Kamp a++; 403d9a54d5cSPoul-Henning Kamp l += up->len; 404d9a54d5cSPoul-Henning Kamp } 405d9a54d5cSPoul-Henning Kamp if (a > ba) { 406d9a54d5cSPoul-Henning Kamp ba = a; 407d9a54d5cSPoul-Henning Kamp us = uf; 408d9a54d5cSPoul-Henning Kamp } 409d9a54d5cSPoul-Henning Kamp } 410d9a54d5cSPoul-Henning Kamp if (ba < 3) 411d9a54d5cSPoul-Henning Kamp return (0); 412d9a54d5cSPoul-Henning Kamp 413d9a54d5cSPoul-Henning Kamp /* 414d9a54d5cSPoul-Henning Kamp * If the first element is not a bitmap, make it one. 415d9a54d5cSPoul-Henning Kamp * Trying to do so without allocating more memory complicates things 416d9a54d5cSPoul-Henning Kamp * a bit 417d9a54d5cSPoul-Henning Kamp */ 418d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, us)) { 419d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 420d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, us, list); 421d9a54d5cSPoul-Henning Kamp a = us->len; 422d9a54d5cSPoul-Henning Kamp l = us->ptr == uh ? 1 : 0; 423d9a54d5cSPoul-Henning Kamp ub = (void *)us; 424d9a54d5cSPoul-Henning Kamp ub->busy = 0; 425d9a54d5cSPoul-Henning Kamp if (l) { 426d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, 0, a); 427d9a54d5cSPoul-Henning Kamp ub->busy += a; 428d9a54d5cSPoul-Henning Kamp } else { 429d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, 0, a); 430d9a54d5cSPoul-Henning Kamp } 431d9a54d5cSPoul-Henning Kamp if (!is_bitmap(uh, uf)) { 432d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 433d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, a, a + uf->len - 1); 434d9a54d5cSPoul-Henning Kamp } else { 435d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, a, a + uf->len - 1); 436d9a54d5cSPoul-Henning Kamp ub->busy += uf->len; 437d9a54d5cSPoul-Henning Kamp } 438d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 439d9a54d5cSPoul-Henning Kamp uf->len += a; 440d9a54d5cSPoul-Henning Kamp us = uf; 441d9a54d5cSPoul-Henning Kamp } else { 442d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 443d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, a++) { 444d9a54d5cSPoul-Henning Kamp if (bit_test(ubf->map, l)) { 445d9a54d5cSPoul-Henning Kamp bit_set(ub->map, a); 446d9a54d5cSPoul-Henning Kamp ub->busy++; 447d9a54d5cSPoul-Henning Kamp } else { 448d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, a); 449d9a54d5cSPoul-Henning Kamp } 450d9a54d5cSPoul-Henning Kamp } 451d9a54d5cSPoul-Henning Kamp uf->len = a; 452d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf->ptr); 453d9a54d5cSPoul-Henning Kamp uf->ptr = ub; 454d9a54d5cSPoul-Henning Kamp us = uf; 455d9a54d5cSPoul-Henning Kamp } 456d9a54d5cSPoul-Henning Kamp } 457d9a54d5cSPoul-Henning Kamp ub = us->ptr; 458d9a54d5cSPoul-Henning Kamp while (1) { 459d9a54d5cSPoul-Henning Kamp uf = TAILQ_NEXT(us, list); 460d9a54d5cSPoul-Henning Kamp if (uf == NULL) 461d9a54d5cSPoul-Henning Kamp return (1); 462d9a54d5cSPoul-Henning Kamp if (uf->len + us->len > NBITS) 463d9a54d5cSPoul-Henning Kamp return (1); 464d9a54d5cSPoul-Henning Kamp if (uf->ptr == NULL) { 465d9a54d5cSPoul-Henning Kamp bit_nclear(ub->map, us->len, us->len + uf->len - 1); 466d9a54d5cSPoul-Henning Kamp us->len += uf->len; 467d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 468d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 469d9a54d5cSPoul-Henning Kamp } else if (uf->ptr == uh) { 470d9a54d5cSPoul-Henning Kamp bit_nset(ub->map, us->len, us->len + uf->len - 1); 471d9a54d5cSPoul-Henning Kamp ub->busy += uf->len; 472d9a54d5cSPoul-Henning Kamp us->len += uf->len; 473d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 474d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 475d9a54d5cSPoul-Henning Kamp } else { 476d9a54d5cSPoul-Henning Kamp ubf = uf->ptr; 477d9a54d5cSPoul-Henning Kamp for (l = 0; l < uf->len; l++, us->len++) { 478d9a54d5cSPoul-Henning Kamp if (bit_test(ubf->map, l)) { 479d9a54d5cSPoul-Henning Kamp bit_set(ub->map, us->len); 480d9a54d5cSPoul-Henning Kamp ub->busy++; 481d9a54d5cSPoul-Henning Kamp } else { 482d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, us->len); 483d9a54d5cSPoul-Henning Kamp } 484d9a54d5cSPoul-Henning Kamp } 485d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, uf, list); 486d9a54d5cSPoul-Henning Kamp delete_unr(uh, ubf); 487d9a54d5cSPoul-Henning Kamp delete_unr(uh, uf); 488d9a54d5cSPoul-Henning Kamp } 489d9a54d5cSPoul-Henning Kamp } 490d9a54d5cSPoul-Henning Kamp } 491d9a54d5cSPoul-Henning Kamp 492d9a54d5cSPoul-Henning Kamp /* 493d9a54d5cSPoul-Henning Kamp * See if a given unr should be collapsed with a neighbor. 494d9a54d5cSPoul-Henning Kamp * 495d9a54d5cSPoul-Henning Kamp * NB: called from alloc_unr(), no new memory allocation allowed. 496f6bde1fdSPoul-Henning Kamp */ 497f6bde1fdSPoul-Henning Kamp static void 498f6bde1fdSPoul-Henning Kamp collapse_unr(struct unrhdr *uh, struct unr *up) 499f6bde1fdSPoul-Henning Kamp { 500f6bde1fdSPoul-Henning Kamp struct unr *upp; 501d9a54d5cSPoul-Henning Kamp struct unrb *ub; 502f6bde1fdSPoul-Henning Kamp 503d9a54d5cSPoul-Henning Kamp /* If bitmap is all set or clear, change it to runlength */ 504d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 505d9a54d5cSPoul-Henning Kamp ub = up->ptr; 506d9a54d5cSPoul-Henning Kamp if (ub->busy == up->len) { 507d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 508d9a54d5cSPoul-Henning Kamp up->ptr = uh; 509d9a54d5cSPoul-Henning Kamp } else if (ub->busy == 0) { 510d9a54d5cSPoul-Henning Kamp delete_unr(uh, up->ptr); 511d9a54d5cSPoul-Henning Kamp up->ptr = NULL; 512d9a54d5cSPoul-Henning Kamp } 513d9a54d5cSPoul-Henning Kamp } 514d9a54d5cSPoul-Henning Kamp 515d9a54d5cSPoul-Henning Kamp /* If nothing left in runlength, delete it */ 516d9a54d5cSPoul-Henning Kamp if (up->len == 0) { 517d9a54d5cSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 518d9a54d5cSPoul-Henning Kamp if (upp == NULL) 519d9a54d5cSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 520d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, up, list); 521d9a54d5cSPoul-Henning Kamp delete_unr(uh, up); 522d9a54d5cSPoul-Henning Kamp up = upp; 523d9a54d5cSPoul-Henning Kamp } 524d9a54d5cSPoul-Henning Kamp 525d9a54d5cSPoul-Henning Kamp /* If we have "hot-spot" still, merge with neighbor if possible */ 526d9a54d5cSPoul-Henning Kamp if (up != NULL) { 527f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 528f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 529f6bde1fdSPoul-Henning Kamp up->len += upp->len; 530f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 531f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 532f6bde1fdSPoul-Henning Kamp } 533f6bde1fdSPoul-Henning Kamp upp = TAILQ_NEXT(up, list); 534f6bde1fdSPoul-Henning Kamp if (upp != NULL && up->ptr == upp->ptr) { 535f6bde1fdSPoul-Henning Kamp up->len += upp->len; 536f6bde1fdSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 537f6bde1fdSPoul-Henning Kamp delete_unr(uh, upp); 538f6bde1fdSPoul-Henning Kamp } 539f6bde1fdSPoul-Henning Kamp } 540f6bde1fdSPoul-Henning Kamp 541d9a54d5cSPoul-Henning Kamp /* Merge into ->first if possible */ 542d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 543d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == uh) { 544d9a54d5cSPoul-Henning Kamp uh->first += upp->len; 545d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 546d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 547d9a54d5cSPoul-Henning Kamp if (up == upp) 548d9a54d5cSPoul-Henning Kamp up = NULL; 549d9a54d5cSPoul-Henning Kamp } 550d9a54d5cSPoul-Henning Kamp 551d9a54d5cSPoul-Henning Kamp /* Merge into ->last if possible */ 552d9a54d5cSPoul-Henning Kamp upp = TAILQ_LAST(&uh->head, unrhd); 553d9a54d5cSPoul-Henning Kamp if (upp != NULL && upp->ptr == NULL) { 554d9a54d5cSPoul-Henning Kamp uh->last += upp->len; 555d9a54d5cSPoul-Henning Kamp TAILQ_REMOVE(&uh->head, upp, list); 556d9a54d5cSPoul-Henning Kamp delete_unr(uh, upp); 557d9a54d5cSPoul-Henning Kamp if (up == upp) 558d9a54d5cSPoul-Henning Kamp up = NULL; 559d9a54d5cSPoul-Henning Kamp } 560d9a54d5cSPoul-Henning Kamp 561d9a54d5cSPoul-Henning Kamp /* Try to make bitmaps */ 562d9a54d5cSPoul-Henning Kamp while (optimize_unr(uh)) 563d9a54d5cSPoul-Henning Kamp continue; 564d9a54d5cSPoul-Henning Kamp } 565d9a54d5cSPoul-Henning Kamp 566f6bde1fdSPoul-Henning Kamp /* 567f6bde1fdSPoul-Henning Kamp * Allocate a free unr. 568f6bde1fdSPoul-Henning Kamp */ 569d9a54d5cSPoul-Henning Kamp int 570d9a54d5cSPoul-Henning Kamp alloc_unrl(struct unrhdr *uh) 571f6bde1fdSPoul-Henning Kamp { 572d9a54d5cSPoul-Henning Kamp struct unr *up; 573d9a54d5cSPoul-Henning Kamp struct unrb *ub; 574f6bde1fdSPoul-Henning Kamp u_int x; 575f6bde1fdSPoul-Henning Kamp int y; 576f6bde1fdSPoul-Henning Kamp 577d9a54d5cSPoul-Henning Kamp mtx_assert(uh->mtx, MA_OWNED); 578f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 579d9a54d5cSPoul-Henning Kamp x = uh->low + uh->first; 580d9a54d5cSPoul-Henning Kamp 581f6bde1fdSPoul-Henning Kamp up = TAILQ_FIRST(&uh->head); 582f6bde1fdSPoul-Henning Kamp 583d9a54d5cSPoul-Henning Kamp /* 584d9a54d5cSPoul-Henning Kamp * If we have an ideal split, just adjust the first+last 585d9a54d5cSPoul-Henning Kamp */ 586d9a54d5cSPoul-Henning Kamp if (up == NULL && uh->last > 0) { 587d9a54d5cSPoul-Henning Kamp uh->first++; 588d9a54d5cSPoul-Henning Kamp uh->last--; 589f6bde1fdSPoul-Henning Kamp uh->busy++; 590f6bde1fdSPoul-Henning Kamp return (x); 591f6bde1fdSPoul-Henning Kamp } 592f6bde1fdSPoul-Henning Kamp 593f6bde1fdSPoul-Henning Kamp /* 594d9a54d5cSPoul-Henning Kamp * We can always allocate from the first list element, so if we have 595d9a54d5cSPoul-Henning Kamp * nothing on the list, we must have run out of unit numbers. 596f6bde1fdSPoul-Henning Kamp */ 59793f6c81eSPoul-Henning Kamp if (up == NULL) 598d9a54d5cSPoul-Henning Kamp return (-1); 599d9a54d5cSPoul-Henning Kamp 600d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr != uh, ("UNR first element is allocated")); 601d9a54d5cSPoul-Henning Kamp 602d9a54d5cSPoul-Henning Kamp if (up->ptr == NULL) { /* free run */ 603d9a54d5cSPoul-Henning Kamp uh->first++; 604f6bde1fdSPoul-Henning Kamp up->len--; 605d9a54d5cSPoul-Henning Kamp } else { /* bitmap */ 606d9a54d5cSPoul-Henning Kamp ub = up->ptr; 607d9a54d5cSPoul-Henning Kamp KASSERT(ub->busy < up->len, ("UNR bitmap confusion")); 608d9a54d5cSPoul-Henning Kamp bit_ffc(ub->map, up->len, &y); 609d9a54d5cSPoul-Henning Kamp KASSERT(y != -1, ("UNR corruption: No clear bit in bitmap.")); 610d9a54d5cSPoul-Henning Kamp bit_set(ub->map, y); 611d9a54d5cSPoul-Henning Kamp ub->busy++; 612d9a54d5cSPoul-Henning Kamp x += y; 613d9a54d5cSPoul-Henning Kamp } 614f6bde1fdSPoul-Henning Kamp uh->busy++; 615d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 616f6bde1fdSPoul-Henning Kamp return (x); 617f6bde1fdSPoul-Henning Kamp } 618f6bde1fdSPoul-Henning Kamp 619d9a54d5cSPoul-Henning Kamp int 620d9a54d5cSPoul-Henning Kamp alloc_unr(struct unrhdr *uh) 621d9a54d5cSPoul-Henning Kamp { 622d9a54d5cSPoul-Henning Kamp int i; 623d9a54d5cSPoul-Henning Kamp 624d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 625d9a54d5cSPoul-Henning Kamp i = alloc_unrl(uh); 62609828ba9SKonstantin Belousov clean_unrhdrl(uh); 627d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 628d9a54d5cSPoul-Henning Kamp return (i); 629d9a54d5cSPoul-Henning Kamp } 630d9a54d5cSPoul-Henning Kamp 631*13c02cbbSJaakko Heinonen static int 632*13c02cbbSJaakko Heinonen alloc_unr_specificl(struct unrhdr *uh, u_int item, void **p1, void **p2) 633*13c02cbbSJaakko Heinonen { 634*13c02cbbSJaakko Heinonen struct unr *up, *upn; 635*13c02cbbSJaakko Heinonen struct unrb *ub; 636*13c02cbbSJaakko Heinonen u_int i, last, tl; 637*13c02cbbSJaakko Heinonen 638*13c02cbbSJaakko Heinonen mtx_assert(uh->mtx, MA_OWNED); 639*13c02cbbSJaakko Heinonen 640*13c02cbbSJaakko Heinonen if (item < uh->low + uh->first || item > uh->high) 641*13c02cbbSJaakko Heinonen return (-1); 642*13c02cbbSJaakko Heinonen 643*13c02cbbSJaakko Heinonen up = TAILQ_FIRST(&uh->head); 644*13c02cbbSJaakko Heinonen /* Ideal split. */ 645*13c02cbbSJaakko Heinonen if (up == NULL && item - uh->low == uh->first) { 646*13c02cbbSJaakko Heinonen uh->first++; 647*13c02cbbSJaakko Heinonen uh->last--; 648*13c02cbbSJaakko Heinonen uh->busy++; 649*13c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 650*13c02cbbSJaakko Heinonen return (item); 651*13c02cbbSJaakko Heinonen } 652*13c02cbbSJaakko Heinonen 653*13c02cbbSJaakko Heinonen i = item - uh->low - uh->first; 654*13c02cbbSJaakko Heinonen 655*13c02cbbSJaakko Heinonen if (up == NULL) { 656*13c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 657*13c02cbbSJaakko Heinonen up->ptr = NULL; 658*13c02cbbSJaakko Heinonen up->len = i; 659*13c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 660*13c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 661*13c02cbbSJaakko Heinonen up->ptr = uh; 662*13c02cbbSJaakko Heinonen up->len = 1; 663*13c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 664*13c02cbbSJaakko Heinonen uh->last = uh->high - uh->low - i; 665*13c02cbbSJaakko Heinonen uh->busy++; 666*13c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 667*13c02cbbSJaakko Heinonen return (item); 668*13c02cbbSJaakko Heinonen } else { 669*13c02cbbSJaakko Heinonen /* Find the item which contains the unit we want to allocate. */ 670*13c02cbbSJaakko Heinonen TAILQ_FOREACH(up, &uh->head, list) { 671*13c02cbbSJaakko Heinonen if (up->len > i) 672*13c02cbbSJaakko Heinonen break; 673*13c02cbbSJaakko Heinonen i -= up->len; 674*13c02cbbSJaakko Heinonen } 675*13c02cbbSJaakko Heinonen } 676*13c02cbbSJaakko Heinonen 677*13c02cbbSJaakko Heinonen if (up == NULL) { 678*13c02cbbSJaakko Heinonen if (i > 0) { 679*13c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 680*13c02cbbSJaakko Heinonen up->ptr = NULL; 681*13c02cbbSJaakko Heinonen up->len = i; 682*13c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 683*13c02cbbSJaakko Heinonen } 684*13c02cbbSJaakko Heinonen up = new_unr(uh, p1, p2); 685*13c02cbbSJaakko Heinonen up->ptr = uh; 686*13c02cbbSJaakko Heinonen up->len = 1; 687*13c02cbbSJaakko Heinonen TAILQ_INSERT_TAIL(&uh->head, up, list); 688*13c02cbbSJaakko Heinonen goto done; 689*13c02cbbSJaakko Heinonen } 690*13c02cbbSJaakko Heinonen 691*13c02cbbSJaakko Heinonen if (is_bitmap(uh, up)) { 692*13c02cbbSJaakko Heinonen ub = up->ptr; 693*13c02cbbSJaakko Heinonen if (bit_test(ub->map, i) == 0) { 694*13c02cbbSJaakko Heinonen bit_set(ub->map, i); 695*13c02cbbSJaakko Heinonen ub->busy++; 696*13c02cbbSJaakko Heinonen goto done; 697*13c02cbbSJaakko Heinonen } else 698*13c02cbbSJaakko Heinonen return (-1); 699*13c02cbbSJaakko Heinonen } else if (up->ptr == uh) 700*13c02cbbSJaakko Heinonen return (-1); 701*13c02cbbSJaakko Heinonen 702*13c02cbbSJaakko Heinonen KASSERT(up->ptr == NULL, 703*13c02cbbSJaakko Heinonen ("alloc_unr_specificl: up->ptr != NULL (up=%p)", up)); 704*13c02cbbSJaakko Heinonen 705*13c02cbbSJaakko Heinonen /* Split off the tail end, if any. */ 706*13c02cbbSJaakko Heinonen tl = up->len - (1 + i); 707*13c02cbbSJaakko Heinonen if (tl > 0) { 708*13c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 709*13c02cbbSJaakko Heinonen upn->ptr = NULL; 710*13c02cbbSJaakko Heinonen upn->len = tl; 711*13c02cbbSJaakko Heinonen TAILQ_INSERT_AFTER(&uh->head, up, upn, list); 712*13c02cbbSJaakko Heinonen } 713*13c02cbbSJaakko Heinonen 714*13c02cbbSJaakko Heinonen /* Split off head end, if any */ 715*13c02cbbSJaakko Heinonen if (i > 0) { 716*13c02cbbSJaakko Heinonen upn = new_unr(uh, p1, p2); 717*13c02cbbSJaakko Heinonen upn->len = i; 718*13c02cbbSJaakko Heinonen upn->ptr = NULL; 719*13c02cbbSJaakko Heinonen TAILQ_INSERT_BEFORE(up, upn, list); 720*13c02cbbSJaakko Heinonen } 721*13c02cbbSJaakko Heinonen up->len = 1; 722*13c02cbbSJaakko Heinonen up->ptr = uh; 723*13c02cbbSJaakko Heinonen 724*13c02cbbSJaakko Heinonen done: 725*13c02cbbSJaakko Heinonen last = uh->high - uh->low - (item - uh->low); 726*13c02cbbSJaakko Heinonen if (uh->last > last) 727*13c02cbbSJaakko Heinonen uh->last = last; 728*13c02cbbSJaakko Heinonen uh->busy++; 729*13c02cbbSJaakko Heinonen collapse_unr(uh, up); 730*13c02cbbSJaakko Heinonen check_unrhdr(uh, __LINE__); 731*13c02cbbSJaakko Heinonen return (item); 732*13c02cbbSJaakko Heinonen } 733*13c02cbbSJaakko Heinonen 734*13c02cbbSJaakko Heinonen int 735*13c02cbbSJaakko Heinonen alloc_unr_specific(struct unrhdr *uh, u_int item) 736*13c02cbbSJaakko Heinonen { 737*13c02cbbSJaakko Heinonen void *p1, *p2; 738*13c02cbbSJaakko Heinonen int i; 739*13c02cbbSJaakko Heinonen 740*13c02cbbSJaakko Heinonen WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "alloc_unr_specific"); 741*13c02cbbSJaakko Heinonen 742*13c02cbbSJaakko Heinonen p1 = Malloc(sizeof(struct unr)); 743*13c02cbbSJaakko Heinonen p2 = Malloc(sizeof(struct unr)); 744*13c02cbbSJaakko Heinonen 745*13c02cbbSJaakko Heinonen mtx_lock(uh->mtx); 746*13c02cbbSJaakko Heinonen i = alloc_unr_specificl(uh, item, &p1, &p2); 747*13c02cbbSJaakko Heinonen mtx_unlock(uh->mtx); 748*13c02cbbSJaakko Heinonen 749*13c02cbbSJaakko Heinonen if (p1 != NULL) 750*13c02cbbSJaakko Heinonen Free(p1); 751*13c02cbbSJaakko Heinonen if (p2 != NULL) 752*13c02cbbSJaakko Heinonen Free(p2); 753*13c02cbbSJaakko Heinonen 754*13c02cbbSJaakko Heinonen return (i); 755*13c02cbbSJaakko Heinonen } 756*13c02cbbSJaakko Heinonen 757f6bde1fdSPoul-Henning Kamp /* 758f6bde1fdSPoul-Henning Kamp * Free a unr. 759f6bde1fdSPoul-Henning Kamp * 760f6bde1fdSPoul-Henning Kamp * If we can save unrs by using a bitmap, do so. 761f6bde1fdSPoul-Henning Kamp */ 762d9a54d5cSPoul-Henning Kamp static void 763d9a54d5cSPoul-Henning Kamp free_unrl(struct unrhdr *uh, u_int item, void **p1, void **p2) 764f6bde1fdSPoul-Henning Kamp { 765d9a54d5cSPoul-Henning Kamp struct unr *up, *upp, *upn; 766d9a54d5cSPoul-Henning Kamp struct unrb *ub; 767d9a54d5cSPoul-Henning Kamp u_int pl; 768f6bde1fdSPoul-Henning Kamp 769f6bde1fdSPoul-Henning Kamp KASSERT(item >= uh->low && item <= uh->high, 770f6bde1fdSPoul-Henning Kamp ("UNR: free_unr(%u) out of range [%u...%u]", 771f6bde1fdSPoul-Henning Kamp item, uh->low, uh->high)); 772f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 773f6bde1fdSPoul-Henning Kamp item -= uh->low; 774d9a54d5cSPoul-Henning Kamp upp = TAILQ_FIRST(&uh->head); 775f6bde1fdSPoul-Henning Kamp /* 776d9a54d5cSPoul-Henning Kamp * Freeing in the ideal split case 777f6bde1fdSPoul-Henning Kamp */ 778d9a54d5cSPoul-Henning Kamp if (item + 1 == uh->first && upp == NULL) { 779d9a54d5cSPoul-Henning Kamp uh->last++; 780d9a54d5cSPoul-Henning Kamp uh->first--; 781d9a54d5cSPoul-Henning Kamp uh->busy--; 782f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 783f6bde1fdSPoul-Henning Kamp return; 784f6bde1fdSPoul-Henning Kamp } 785d9a54d5cSPoul-Henning Kamp /* 786d9a54d5cSPoul-Henning Kamp * Freeing in the ->first section. Create a run starting at the 787d9a54d5cSPoul-Henning Kamp * freed item. The code below will subdivide it. 788d9a54d5cSPoul-Henning Kamp */ 789d9a54d5cSPoul-Henning Kamp if (item < uh->first) { 790d9a54d5cSPoul-Henning Kamp up = new_unr(uh, p1, p2); 791d9a54d5cSPoul-Henning Kamp up->ptr = uh; 792d9a54d5cSPoul-Henning Kamp up->len = uh->first - item; 793d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_HEAD(&uh->head, up, list); 794d9a54d5cSPoul-Henning Kamp uh->first -= up->len; 795f6bde1fdSPoul-Henning Kamp } 796f6bde1fdSPoul-Henning Kamp 797d9a54d5cSPoul-Henning Kamp item -= uh->first; 798d9a54d5cSPoul-Henning Kamp 799d9a54d5cSPoul-Henning Kamp /* Find the item which contains the unit we want to free */ 800d9a54d5cSPoul-Henning Kamp TAILQ_FOREACH(up, &uh->head, list) { 801d9a54d5cSPoul-Henning Kamp if (up->len > item) 802d9a54d5cSPoul-Henning Kamp break; 803d9a54d5cSPoul-Henning Kamp item -= up->len; 804d9a54d5cSPoul-Henning Kamp } 805d9a54d5cSPoul-Henning Kamp 806d9a54d5cSPoul-Henning Kamp /* Handle bitmap items */ 807d9a54d5cSPoul-Henning Kamp if (is_bitmap(uh, up)) { 808d9a54d5cSPoul-Henning Kamp ub = up->ptr; 809d9a54d5cSPoul-Henning Kamp 810d9a54d5cSPoul-Henning Kamp KASSERT(bit_test(ub->map, item) != 0, 811d9a54d5cSPoul-Henning Kamp ("UNR: Freeing free item %d (bitmap)\n", item)); 812d9a54d5cSPoul-Henning Kamp bit_clear(ub->map, item); 813d9a54d5cSPoul-Henning Kamp uh->busy--; 814d9a54d5cSPoul-Henning Kamp ub->busy--; 815d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 816d9a54d5cSPoul-Henning Kamp return; 817d9a54d5cSPoul-Henning Kamp } 818d9a54d5cSPoul-Henning Kamp 819d9a54d5cSPoul-Henning Kamp KASSERT(up->ptr == uh, ("UNR Freeing free item %d (run))\n", item)); 820f6bde1fdSPoul-Henning Kamp 821f6bde1fdSPoul-Henning Kamp /* Just this one left, reap it */ 822f6bde1fdSPoul-Henning Kamp if (up->len == 1) { 823f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 824f6bde1fdSPoul-Henning Kamp uh->busy--; 825f6bde1fdSPoul-Henning Kamp collapse_unr(uh, up); 826f6bde1fdSPoul-Henning Kamp return; 827f6bde1fdSPoul-Henning Kamp } 828f6bde1fdSPoul-Henning Kamp 829d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item into the previous 'free' run */ 830f6bde1fdSPoul-Henning Kamp upp = TAILQ_PREV(up, unrhd, list); 831d9a54d5cSPoul-Henning Kamp if (item == 0 && upp != NULL && upp->ptr == NULL) { 832f6bde1fdSPoul-Henning Kamp upp->len++; 833f6bde1fdSPoul-Henning Kamp up->len--; 834f6bde1fdSPoul-Henning Kamp uh->busy--; 835d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 836f6bde1fdSPoul-Henning Kamp return; 837f6bde1fdSPoul-Henning Kamp } 838f6bde1fdSPoul-Henning Kamp 839d9a54d5cSPoul-Henning Kamp /* Check if we can shift the item to the next 'free' run */ 840f6bde1fdSPoul-Henning Kamp upn = TAILQ_NEXT(up, list); 841d9a54d5cSPoul-Henning Kamp if (item == up->len - 1 && upn != NULL && upn->ptr == NULL) { 842f6bde1fdSPoul-Henning Kamp upn->len++; 843f6bde1fdSPoul-Henning Kamp up->len--; 844f6bde1fdSPoul-Henning Kamp uh->busy--; 845d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 846f6bde1fdSPoul-Henning Kamp return; 847f6bde1fdSPoul-Henning Kamp } 848f6bde1fdSPoul-Henning Kamp 849f6bde1fdSPoul-Henning Kamp /* Split off the tail end, if any. */ 850d9a54d5cSPoul-Henning Kamp pl = up->len - (1 + item); 851f6bde1fdSPoul-Henning Kamp if (pl > 0) { 852d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 853f6bde1fdSPoul-Henning Kamp upp->ptr = uh; 854f6bde1fdSPoul-Henning Kamp upp->len = pl; 855f6bde1fdSPoul-Henning Kamp TAILQ_INSERT_AFTER(&uh->head, up, upp, list); 856f6bde1fdSPoul-Henning Kamp } 857f6bde1fdSPoul-Henning Kamp 858d9a54d5cSPoul-Henning Kamp /* Split off head end, if any */ 859d9a54d5cSPoul-Henning Kamp if (item > 0) { 860d9a54d5cSPoul-Henning Kamp upp = new_unr(uh, p1, p2); 861d9a54d5cSPoul-Henning Kamp upp->len = item; 862d9a54d5cSPoul-Henning Kamp upp->ptr = uh; 863d9a54d5cSPoul-Henning Kamp TAILQ_INSERT_BEFORE(up, upp, list); 864d9a54d5cSPoul-Henning Kamp } 865f6bde1fdSPoul-Henning Kamp up->len = 1; 866f6bde1fdSPoul-Henning Kamp up->ptr = NULL; 867f6bde1fdSPoul-Henning Kamp uh->busy--; 868d9a54d5cSPoul-Henning Kamp collapse_unr(uh, up); 869f6bde1fdSPoul-Henning Kamp } 870f6bde1fdSPoul-Henning Kamp 871d9a54d5cSPoul-Henning Kamp void 872d9a54d5cSPoul-Henning Kamp free_unr(struct unrhdr *uh, u_int item) 873d9a54d5cSPoul-Henning Kamp { 874d9a54d5cSPoul-Henning Kamp void *p1, *p2; 875f6bde1fdSPoul-Henning Kamp 8767550e3eaSKonstantin Belousov WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "free_unr"); 877d9a54d5cSPoul-Henning Kamp p1 = Malloc(sizeof(struct unr)); 878d9a54d5cSPoul-Henning Kamp p2 = Malloc(sizeof(struct unr)); 879d9a54d5cSPoul-Henning Kamp mtx_lock(uh->mtx); 880d9a54d5cSPoul-Henning Kamp free_unrl(uh, item, &p1, &p2); 88109828ba9SKonstantin Belousov clean_unrhdrl(uh); 882d9a54d5cSPoul-Henning Kamp mtx_unlock(uh->mtx); 883d9a54d5cSPoul-Henning Kamp if (p1 != NULL) 884d9a54d5cSPoul-Henning Kamp Free(p1); 885d9a54d5cSPoul-Henning Kamp if (p2 != NULL) 886d9a54d5cSPoul-Henning Kamp Free(p2); 887f6bde1fdSPoul-Henning Kamp } 888f6bde1fdSPoul-Henning Kamp 88993f6c81eSPoul-Henning Kamp #ifndef _KERNEL /* USERLAND test driver */ 89093f6c81eSPoul-Henning Kamp 891f6bde1fdSPoul-Henning Kamp /* 892f6bde1fdSPoul-Henning Kamp * Simple stochastic test driver for the above functions 893f6bde1fdSPoul-Henning Kamp */ 894f6bde1fdSPoul-Henning Kamp 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 939*13c02cbbSJaakko Heinonen static void 940*13c02cbbSJaakko Heinonen test_alloc_unr(struct unrhdr *uh, u_int i, char a[]) 941*13c02cbbSJaakko Heinonen { 942*13c02cbbSJaakko Heinonen int j; 943*13c02cbbSJaakko Heinonen 944*13c02cbbSJaakko Heinonen if (a[i]) { 945*13c02cbbSJaakko Heinonen printf("F %u\n", i); 946*13c02cbbSJaakko Heinonen free_unr(uh, i); 947*13c02cbbSJaakko Heinonen a[i] = 0; 948*13c02cbbSJaakko Heinonen } else { 949*13c02cbbSJaakko Heinonen no_alloc = 1; 950*13c02cbbSJaakko Heinonen j = alloc_unr(uh); 951*13c02cbbSJaakko Heinonen if (j != -1) { 952*13c02cbbSJaakko Heinonen a[j] = 1; 953*13c02cbbSJaakko Heinonen printf("A %d\n", j); 954*13c02cbbSJaakko Heinonen } 955*13c02cbbSJaakko Heinonen no_alloc = 0; 956*13c02cbbSJaakko Heinonen } 957*13c02cbbSJaakko Heinonen } 958*13c02cbbSJaakko Heinonen 959*13c02cbbSJaakko Heinonen static void 960*13c02cbbSJaakko Heinonen test_alloc_unr_specific(struct unrhdr *uh, u_int i, char a[]) 961*13c02cbbSJaakko Heinonen { 962*13c02cbbSJaakko Heinonen int j; 963*13c02cbbSJaakko Heinonen 964*13c02cbbSJaakko Heinonen j = alloc_unr_specific(uh, i); 965*13c02cbbSJaakko Heinonen if (j == -1) { 966*13c02cbbSJaakko Heinonen printf("F %u\n", i); 967*13c02cbbSJaakko Heinonen a[i] = 0; 968*13c02cbbSJaakko Heinonen free_unr(uh, i); 969*13c02cbbSJaakko Heinonen } else { 970*13c02cbbSJaakko Heinonen a[i] = 1; 971*13c02cbbSJaakko Heinonen printf("A %d\n", j); 972*13c02cbbSJaakko Heinonen } 973*13c02cbbSJaakko Heinonen } 974*13c02cbbSJaakko Heinonen 975f6bde1fdSPoul-Henning Kamp /* Number of unrs to test */ 976f6bde1fdSPoul-Henning Kamp #define NN 10000 977f6bde1fdSPoul-Henning Kamp 978f6bde1fdSPoul-Henning Kamp int 979f6bde1fdSPoul-Henning Kamp main(int argc __unused, const char **argv __unused) 980f6bde1fdSPoul-Henning Kamp { 981f6bde1fdSPoul-Henning Kamp struct unrhdr *uh; 982d9a54d5cSPoul-Henning Kamp u_int i, x, m, j; 983f6bde1fdSPoul-Henning Kamp char a[NN]; 984f6bde1fdSPoul-Henning Kamp 985d9a54d5cSPoul-Henning Kamp setbuf(stdout, NULL); 9863b3f38edSPoul-Henning Kamp uh = new_unrhdr(0, NN - 1, NULL); 987d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 988f6bde1fdSPoul-Henning Kamp 989f6bde1fdSPoul-Henning Kamp memset(a, 0, sizeof a); 990*13c02cbbSJaakko Heinonen srandomdev(); 991f6bde1fdSPoul-Henning Kamp 99224e8eaf1SJaakko Heinonen fprintf(stderr, "sizeof(struct unr) %zu\n", sizeof(struct unr)); 99324e8eaf1SJaakko Heinonen fprintf(stderr, "sizeof(struct unrb) %zu\n", sizeof(struct unrb)); 99424e8eaf1SJaakko Heinonen fprintf(stderr, "sizeof(struct unrhdr) %zu\n", sizeof(struct unrhdr)); 995d9a54d5cSPoul-Henning Kamp fprintf(stderr, "NBITS %d\n", NBITS); 996f6bde1fdSPoul-Henning Kamp x = 1; 997d9a54d5cSPoul-Henning Kamp for (m = 0; m < NN * 100; m++) { 998d9a54d5cSPoul-Henning Kamp j = random(); 999d9a54d5cSPoul-Henning Kamp i = (j >> 1) % NN; 1000d9a54d5cSPoul-Henning Kamp #if 0 1001d9a54d5cSPoul-Henning Kamp if (a[i] && (j & 1)) 1002d9a54d5cSPoul-Henning Kamp continue; 1003d9a54d5cSPoul-Henning Kamp #endif 1004*13c02cbbSJaakko Heinonen if ((random() & 1) != 0) 1005*13c02cbbSJaakko Heinonen test_alloc_unr(uh, i, a); 1006*13c02cbbSJaakko Heinonen else 1007*13c02cbbSJaakko Heinonen test_alloc_unr_specific(uh, i, a); 1008*13c02cbbSJaakko Heinonen 1009f6bde1fdSPoul-Henning Kamp if (1) /* XXX: change this for detailed debug printout */ 1010f6bde1fdSPoul-Henning Kamp print_unrhdr(uh); 1011f6bde1fdSPoul-Henning Kamp check_unrhdr(uh, __LINE__); 1012f6bde1fdSPoul-Henning Kamp } 1013d9a54d5cSPoul-Henning Kamp for (i = 0; i < NN; i++) { 1014d9a54d5cSPoul-Henning Kamp if (a[i]) { 1015d9a54d5cSPoul-Henning Kamp printf("C %u\n", i); 1016e4fea39eSPoul-Henning Kamp free_unr(uh, i); 1017e4fea39eSPoul-Henning Kamp print_unrhdr(uh); 1018d9a54d5cSPoul-Henning Kamp } 1019d9a54d5cSPoul-Henning Kamp } 1020d9a54d5cSPoul-Henning Kamp print_unrhdr(uh); 1021e4fea39eSPoul-Henning Kamp delete_unrhdr(uh); 1022f6bde1fdSPoul-Henning Kamp return (0); 1023f6bde1fdSPoul-Henning Kamp } 1024f6bde1fdSPoul-Henning Kamp #endif 1025