1fb2f18f8Sesaxe /* 2fb2f18f8Sesaxe * CDDL HEADER START 3fb2f18f8Sesaxe * 4fb2f18f8Sesaxe * The contents of this file are subject to the terms of the 5fb2f18f8Sesaxe * Common Development and Distribution License (the "License"). 6fb2f18f8Sesaxe * You may not use this file except in compliance with the License. 7fb2f18f8Sesaxe * 8fb2f18f8Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fb2f18f8Sesaxe * or http://www.opensolaris.org/os/licensing. 10fb2f18f8Sesaxe * See the License for the specific language governing permissions 11fb2f18f8Sesaxe * and limitations under the License. 12fb2f18f8Sesaxe * 13fb2f18f8Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 14fb2f18f8Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fb2f18f8Sesaxe * If applicable, add the following below this CDDL HEADER, with the 16fb2f18f8Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 17fb2f18f8Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 18fb2f18f8Sesaxe * 19fb2f18f8Sesaxe * CDDL HEADER END 20fb2f18f8Sesaxe */ 21fb2f18f8Sesaxe /* 22*6890d023SEric Saxe * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23fb2f18f8Sesaxe * Use is subject to license terms. 24fb2f18f8Sesaxe */ 25fb2f18f8Sesaxe 26fb2f18f8Sesaxe #include <sys/bitset.h> 27fb2f18f8Sesaxe #include <sys/kmem.h> 28fb2f18f8Sesaxe #include <sys/systm.h> 29*6890d023SEric Saxe #include <sys/cpuvar.h> 30fb2f18f8Sesaxe #include <sys/cmn_err.h> 31fb2f18f8Sesaxe #include <sys/sysmacros.h> 32fb2f18f8Sesaxe 33fb2f18f8Sesaxe /* 34fb2f18f8Sesaxe * Initialize a bitset_t. 35fb2f18f8Sesaxe * After bitset_init(), the bitset will be zero sized. 36fb2f18f8Sesaxe */ 37fb2f18f8Sesaxe void 38fb2f18f8Sesaxe bitset_init(bitset_t *b) 39fb2f18f8Sesaxe { 40fb2f18f8Sesaxe bzero(b, sizeof (bitset_t)); 41fb2f18f8Sesaxe } 42fb2f18f8Sesaxe 43fb2f18f8Sesaxe /* 44fb2f18f8Sesaxe * Uninitialize a bitset_t. 45fb2f18f8Sesaxe * This will free the bitset's data, leaving it zero sized. 46fb2f18f8Sesaxe */ 47fb2f18f8Sesaxe void 48fb2f18f8Sesaxe bitset_fini(bitset_t *b) 49fb2f18f8Sesaxe { 50fb2f18f8Sesaxe if (b->bs_words > 0) 51fb2f18f8Sesaxe kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t)); 52fb2f18f8Sesaxe } 53fb2f18f8Sesaxe 54fb2f18f8Sesaxe /* 55fb2f18f8Sesaxe * Resize a bitset to where it can hold sz number of bits. 56fb2f18f8Sesaxe * This can either grow or shrink the bitset holding capacity. 57fb2f18f8Sesaxe * In the case of shrinkage, elements that reside outside the new 58fb2f18f8Sesaxe * holding capacity of the bitset are lost. 59fb2f18f8Sesaxe */ 60fb2f18f8Sesaxe void 61fb2f18f8Sesaxe bitset_resize(bitset_t *b, uint_t sz) 62fb2f18f8Sesaxe { 63fb2f18f8Sesaxe uint_t nwords; 64fb2f18f8Sesaxe ulong_t *bset_new, *bset_tmp; 65fb2f18f8Sesaxe 66fb2f18f8Sesaxe nwords = BT_BITOUL(sz); 67fb2f18f8Sesaxe if (b->bs_words == nwords) 68fb2f18f8Sesaxe return; /* already properly sized */ 69fb2f18f8Sesaxe 70fb2f18f8Sesaxe /* 71*6890d023SEric Saxe * Allocate the new ulong_t array, and copy the old one, if there 72*6890d023SEric Saxe * was an old one. 73fb2f18f8Sesaxe */ 74fb2f18f8Sesaxe if (nwords > 0) { 75fb2f18f8Sesaxe bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP); 76*6890d023SEric Saxe if (b->bs_words > 0) 77fb2f18f8Sesaxe bcopy(b->bs_set, bset_new, 78fb2f18f8Sesaxe MIN(b->bs_words, nwords) * sizeof (ulong_t)); 79fb2f18f8Sesaxe } else { 80fb2f18f8Sesaxe bset_new = NULL; 81fb2f18f8Sesaxe } 82fb2f18f8Sesaxe 83fb2f18f8Sesaxe /* swap out the old ulong_t array for new one */ 84fb2f18f8Sesaxe bset_tmp = b->bs_set; 85fb2f18f8Sesaxe b->bs_set = bset_new; 86fb2f18f8Sesaxe 87fb2f18f8Sesaxe /* free up the old array */ 88*6890d023SEric Saxe if (b->bs_words > 0) 89fb2f18f8Sesaxe kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t)); 90fb2f18f8Sesaxe b->bs_words = nwords; 91fb2f18f8Sesaxe } 92fb2f18f8Sesaxe 93fb2f18f8Sesaxe /* 94fb2f18f8Sesaxe * Returns the current holding capacity of the bitset 95fb2f18f8Sesaxe */ 96fb2f18f8Sesaxe uint_t 97fb2f18f8Sesaxe bitset_capacity(bitset_t *b) 98fb2f18f8Sesaxe { 99fb2f18f8Sesaxe return (b->bs_words * BT_NBIPUL); 100fb2f18f8Sesaxe } 101fb2f18f8Sesaxe 102fb2f18f8Sesaxe /* 103fb2f18f8Sesaxe * Add and delete bits in the bitset. 104fb2f18f8Sesaxe * 105fb2f18f8Sesaxe * Adding a bit that is already set, and clearing a bit that's already clear 106fb2f18f8Sesaxe * is legal. 107fb2f18f8Sesaxe * 108fb2f18f8Sesaxe * Adding or deleting an element that falls outside the bitset's current 109fb2f18f8Sesaxe * holding capacity is illegal. 110fb2f18f8Sesaxe */ 111*6890d023SEric Saxe 112*6890d023SEric Saxe /* 113*6890d023SEric Saxe * Set a bit 114*6890d023SEric Saxe */ 115fb2f18f8Sesaxe void 116fb2f18f8Sesaxe bitset_add(bitset_t *b, uint_t elt) 117fb2f18f8Sesaxe { 118fb2f18f8Sesaxe ASSERT(b->bs_words * BT_NBIPUL > elt); 119fb2f18f8Sesaxe 120fb2f18f8Sesaxe BT_SET(b->bs_set, elt); 121fb2f18f8Sesaxe } 122fb2f18f8Sesaxe 123*6890d023SEric Saxe /* 124*6890d023SEric Saxe * Set a bit in an atomically safe way 125*6890d023SEric Saxe */ 126*6890d023SEric Saxe void 127*6890d023SEric Saxe bitset_atomic_add(bitset_t *b, uint_t elt) 128*6890d023SEric Saxe { 129*6890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 130*6890d023SEric Saxe 131*6890d023SEric Saxe BT_ATOMIC_SET(b->bs_set, elt); 132*6890d023SEric Saxe } 133*6890d023SEric Saxe 134*6890d023SEric Saxe /* 135*6890d023SEric Saxe * Atomically test that a given bit isn't set, and set it. 136*6890d023SEric Saxe * Returns -1 if the bit was already set. 137*6890d023SEric Saxe */ 138*6890d023SEric Saxe int 139*6890d023SEric Saxe bitset_atomic_test_and_add(bitset_t *b, uint_t elt) 140*6890d023SEric Saxe { 141*6890d023SEric Saxe int r; 142*6890d023SEric Saxe 143*6890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 144*6890d023SEric Saxe BT_ATOMIC_SET_EXCL(b->bs_set, elt, r); 145*6890d023SEric Saxe 146*6890d023SEric Saxe return (r); 147*6890d023SEric Saxe } 148*6890d023SEric Saxe 149*6890d023SEric Saxe /* 150*6890d023SEric Saxe * Clear a bit 151*6890d023SEric Saxe */ 152fb2f18f8Sesaxe void 153fb2f18f8Sesaxe bitset_del(bitset_t *b, uint_t elt) 154fb2f18f8Sesaxe { 155fb2f18f8Sesaxe ASSERT(b->bs_words * BT_NBIPUL > elt); 156fb2f18f8Sesaxe 157fb2f18f8Sesaxe BT_CLEAR(b->bs_set, elt); 158fb2f18f8Sesaxe } 159fb2f18f8Sesaxe 160fb2f18f8Sesaxe /* 161*6890d023SEric Saxe * Clear a bit in an atomically safe way 162*6890d023SEric Saxe */ 163*6890d023SEric Saxe void 164*6890d023SEric Saxe bitset_atomic_del(bitset_t *b, uint_t elt) 165*6890d023SEric Saxe { 166*6890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 167*6890d023SEric Saxe 168*6890d023SEric Saxe BT_ATOMIC_CLEAR(b->bs_set, elt); 169*6890d023SEric Saxe } 170*6890d023SEric Saxe 171*6890d023SEric Saxe /* 172*6890d023SEric Saxe * Atomically test that a bit is set, and clear it. 173*6890d023SEric Saxe * Returns -1 if the bit was already clear. 174*6890d023SEric Saxe */ 175*6890d023SEric Saxe int 176*6890d023SEric Saxe bitset_atomic_test_and_del(bitset_t *b, uint_t elt) 177*6890d023SEric Saxe { 178*6890d023SEric Saxe int r; 179*6890d023SEric Saxe 180*6890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 181*6890d023SEric Saxe BT_ATOMIC_CLEAR_EXCL(b->bs_set, elt, r); 182*6890d023SEric Saxe 183*6890d023SEric Saxe return (r); 184*6890d023SEric Saxe } 185*6890d023SEric Saxe 186*6890d023SEric Saxe /* 187fb2f18f8Sesaxe * Return non-zero if the bit is present in the set 188fb2f18f8Sesaxe */ 189fb2f18f8Sesaxe int 190fb2f18f8Sesaxe bitset_in_set(bitset_t *b, uint_t elt) 191fb2f18f8Sesaxe { 1920f424180Sesaxe if (elt >= b->bs_words * BT_NBIPUL) 1930f424180Sesaxe return (0); 194fb2f18f8Sesaxe 195fb2f18f8Sesaxe return (BT_TEST(b->bs_set, elt)); 196fb2f18f8Sesaxe } 197fb2f18f8Sesaxe 198fb2f18f8Sesaxe /* 199fb2f18f8Sesaxe * Return non-zero if the bitset is empty 200fb2f18f8Sesaxe */ 201fb2f18f8Sesaxe int 202fb2f18f8Sesaxe bitset_is_null(bitset_t *b) 203fb2f18f8Sesaxe { 204fb2f18f8Sesaxe int i; 205fb2f18f8Sesaxe 206fb2f18f8Sesaxe for (i = 0; i < b->bs_words; i++) 207fb2f18f8Sesaxe if (b->bs_set[i] != 0) 208fb2f18f8Sesaxe return (0); 209fb2f18f8Sesaxe return (1); 210fb2f18f8Sesaxe } 211fb2f18f8Sesaxe 212fb2f18f8Sesaxe /* 213*6890d023SEric Saxe * Perform a non-victimizing search for a set bit in a word 214*6890d023SEric Saxe * A "seed" is passed to pseudo-randomize the search. 215*6890d023SEric Saxe * Return -1 if no set bit was found 216*6890d023SEric Saxe */ 217*6890d023SEric Saxe static uint_t 218*6890d023SEric Saxe bitset_find_in_word(ulong_t w, uint_t seed) 219*6890d023SEric Saxe { 220*6890d023SEric Saxe uint_t rotate_bit, elt = (uint_t)-1; 221*6890d023SEric Saxe ulong_t rotated_word; 222*6890d023SEric Saxe 223*6890d023SEric Saxe if (w == (ulong_t)0) 224*6890d023SEric Saxe return (elt); 225*6890d023SEric Saxe 226*6890d023SEric Saxe rotate_bit = seed % BT_NBIPUL; 227*6890d023SEric Saxe rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit)); 228*6890d023SEric Saxe elt = (uint_t)(lowbit(rotated_word) - 1); 229*6890d023SEric Saxe if (elt != (uint_t)-1) 230*6890d023SEric Saxe elt = ((elt + rotate_bit) % BT_NBIPUL); 231*6890d023SEric Saxe 232*6890d023SEric Saxe return (elt); 233*6890d023SEric Saxe } 234*6890d023SEric Saxe 235*6890d023SEric Saxe /* 236*6890d023SEric Saxe * Select a bit that is set in the bitset in a non-victimizing fashion 237*6890d023SEric Saxe * (e.g. doesn't bias the low/high order bits/words). 238*6890d023SEric Saxe * Return -1 if no set bit was found 239fb2f18f8Sesaxe */ 240fb2f18f8Sesaxe uint_t 241fb2f18f8Sesaxe bitset_find(bitset_t *b) 242fb2f18f8Sesaxe { 243*6890d023SEric Saxe uint_t start, i; 244fb2f18f8Sesaxe uint_t elt = (uint_t)-1; 245*6890d023SEric Saxe uint_t seed; 246fb2f18f8Sesaxe 247*6890d023SEric Saxe seed = CPU_PSEUDO_RANDOM(); 248*6890d023SEric Saxe start = seed % b->bs_words; 249*6890d023SEric Saxe 250*6890d023SEric Saxe i = start; 251*6890d023SEric Saxe do { 252*6890d023SEric Saxe elt = bitset_find_in_word(b->bs_set[i], seed); 253fb2f18f8Sesaxe if (elt != (uint_t)-1) { 254fb2f18f8Sesaxe elt += i * BT_NBIPUL; 255fb2f18f8Sesaxe break; 256fb2f18f8Sesaxe } 257*6890d023SEric Saxe if (++i == b->bs_words) 258*6890d023SEric Saxe i = 0; 259*6890d023SEric Saxe } while (i != start); 260*6890d023SEric Saxe 261fb2f18f8Sesaxe return (elt); 262fb2f18f8Sesaxe } 263