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*4c06356bSdh142964 * Copyright 2009 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> 296890d023SEric 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 /* 716890d023SEric Saxe * Allocate the new ulong_t array, and copy the old one, if there 726890d023SEric Saxe * was an old one. 73fb2f18f8Sesaxe */ 74fb2f18f8Sesaxe if (nwords > 0) { 75fb2f18f8Sesaxe bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP); 766890d023SEric 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 */ 886890d023SEric 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 */ 1116890d023SEric Saxe 1126890d023SEric Saxe /* 1136890d023SEric Saxe * Set a bit 1146890d023SEric 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 1236890d023SEric Saxe /* 1246890d023SEric Saxe * Set a bit in an atomically safe way 1256890d023SEric Saxe */ 1266890d023SEric Saxe void 1276890d023SEric Saxe bitset_atomic_add(bitset_t *b, uint_t elt) 1286890d023SEric Saxe { 1296890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1306890d023SEric Saxe 1316890d023SEric Saxe BT_ATOMIC_SET(b->bs_set, elt); 1326890d023SEric Saxe } 1336890d023SEric Saxe 1346890d023SEric Saxe /* 1356890d023SEric Saxe * Atomically test that a given bit isn't set, and set it. 1366890d023SEric Saxe * Returns -1 if the bit was already set. 1376890d023SEric Saxe */ 1386890d023SEric Saxe int 1396890d023SEric Saxe bitset_atomic_test_and_add(bitset_t *b, uint_t elt) 1406890d023SEric Saxe { 1416890d023SEric Saxe int r; 1426890d023SEric Saxe 1436890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1446890d023SEric Saxe BT_ATOMIC_SET_EXCL(b->bs_set, elt, r); 1456890d023SEric Saxe 1466890d023SEric Saxe return (r); 1476890d023SEric Saxe } 1486890d023SEric Saxe 1496890d023SEric Saxe /* 1506890d023SEric Saxe * Clear a bit 1516890d023SEric 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 /* 1616890d023SEric Saxe * Clear a bit in an atomically safe way 1626890d023SEric Saxe */ 1636890d023SEric Saxe void 1646890d023SEric Saxe bitset_atomic_del(bitset_t *b, uint_t elt) 1656890d023SEric Saxe { 1666890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1676890d023SEric Saxe 1686890d023SEric Saxe BT_ATOMIC_CLEAR(b->bs_set, elt); 1696890d023SEric Saxe } 1706890d023SEric Saxe 1716890d023SEric Saxe /* 1726890d023SEric Saxe * Atomically test that a bit is set, and clear it. 1736890d023SEric Saxe * Returns -1 if the bit was already clear. 1746890d023SEric Saxe */ 1756890d023SEric Saxe int 1766890d023SEric Saxe bitset_atomic_test_and_del(bitset_t *b, uint_t elt) 1776890d023SEric Saxe { 1786890d023SEric Saxe int r; 1796890d023SEric Saxe 1806890d023SEric Saxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1816890d023SEric Saxe BT_ATOMIC_CLEAR_EXCL(b->bs_set, elt, r); 1826890d023SEric Saxe 1836890d023SEric Saxe return (r); 1846890d023SEric Saxe } 1856890d023SEric Saxe 1866890d023SEric 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 /* 2136890d023SEric Saxe * Perform a non-victimizing search for a set bit in a word 2146890d023SEric Saxe * A "seed" is passed to pseudo-randomize the search. 2156890d023SEric Saxe * Return -1 if no set bit was found 2166890d023SEric Saxe */ 2176890d023SEric Saxe static uint_t 2186890d023SEric Saxe bitset_find_in_word(ulong_t w, uint_t seed) 2196890d023SEric Saxe { 2206890d023SEric Saxe uint_t rotate_bit, elt = (uint_t)-1; 2216890d023SEric Saxe ulong_t rotated_word; 2226890d023SEric Saxe 2236890d023SEric Saxe if (w == (ulong_t)0) 2246890d023SEric Saxe return (elt); 2256890d023SEric Saxe 2266890d023SEric Saxe rotate_bit = seed % BT_NBIPUL; 2276890d023SEric Saxe rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit)); 2286890d023SEric Saxe elt = (uint_t)(lowbit(rotated_word) - 1); 2296890d023SEric Saxe if (elt != (uint_t)-1) 2306890d023SEric Saxe elt = ((elt + rotate_bit) % BT_NBIPUL); 2316890d023SEric Saxe 2326890d023SEric Saxe return (elt); 2336890d023SEric Saxe } 2346890d023SEric Saxe 2356890d023SEric Saxe /* 2366890d023SEric Saxe * Select a bit that is set in the bitset in a non-victimizing fashion 2376890d023SEric Saxe * (e.g. doesn't bias the low/high order bits/words). 2386890d023SEric Saxe * Return -1 if no set bit was found 239fb2f18f8Sesaxe */ 240fb2f18f8Sesaxe uint_t 241fb2f18f8Sesaxe bitset_find(bitset_t *b) 242fb2f18f8Sesaxe { 2436890d023SEric Saxe uint_t start, i; 244fb2f18f8Sesaxe uint_t elt = (uint_t)-1; 2456890d023SEric Saxe uint_t seed; 246fb2f18f8Sesaxe 2476890d023SEric Saxe seed = CPU_PSEUDO_RANDOM(); 2486890d023SEric Saxe start = seed % b->bs_words; 2496890d023SEric Saxe 2506890d023SEric Saxe i = start; 2516890d023SEric Saxe do { 2526890d023SEric 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 } 2576890d023SEric Saxe if (++i == b->bs_words) 2586890d023SEric Saxe i = 0; 2596890d023SEric Saxe } while (i != start); 2606890d023SEric Saxe 261fb2f18f8Sesaxe return (elt); 262fb2f18f8Sesaxe } 263*4c06356bSdh142964 264*4c06356bSdh142964 /* 265*4c06356bSdh142964 * AND, OR, and XOR bitset computations 266*4c06356bSdh142964 * Returns 1 if resulting bitset has any set bits 267*4c06356bSdh142964 */ 268*4c06356bSdh142964 int 269*4c06356bSdh142964 bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 270*4c06356bSdh142964 { 271*4c06356bSdh142964 int i, anyset; 272*4c06356bSdh142964 273*4c06356bSdh142964 for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 274*4c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0) 275*4c06356bSdh142964 anyset = 1; 276*4c06356bSdh142964 } 277*4c06356bSdh142964 return (anyset); 278*4c06356bSdh142964 } 279*4c06356bSdh142964 280*4c06356bSdh142964 int 281*4c06356bSdh142964 bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 282*4c06356bSdh142964 { 283*4c06356bSdh142964 int i, anyset; 284*4c06356bSdh142964 285*4c06356bSdh142964 for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 286*4c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0) 287*4c06356bSdh142964 anyset = 1; 288*4c06356bSdh142964 } 289*4c06356bSdh142964 return (anyset); 290*4c06356bSdh142964 } 291*4c06356bSdh142964 292*4c06356bSdh142964 int 293*4c06356bSdh142964 bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 294*4c06356bSdh142964 { 295*4c06356bSdh142964 int i; 296*4c06356bSdh142964 int anyset = 0; 297*4c06356bSdh142964 298*4c06356bSdh142964 for (i = 0; i < bs1->bs_words; i++) { 299*4c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0) 300*4c06356bSdh142964 anyset = 1; 301*4c06356bSdh142964 } 302*4c06356bSdh142964 return (anyset); 303*4c06356bSdh142964 } 304*4c06356bSdh142964 305*4c06356bSdh142964 /* 306*4c06356bSdh142964 * return 1 if bitmaps are identical 307*4c06356bSdh142964 */ 308*4c06356bSdh142964 int 309*4c06356bSdh142964 bitset_match(bitset_t *bs1, bitset_t *bs2) 310*4c06356bSdh142964 { 311*4c06356bSdh142964 int i; 312*4c06356bSdh142964 313*4c06356bSdh142964 if (bs1->bs_words != bs2->bs_words) 314*4c06356bSdh142964 return (0); 315*4c06356bSdh142964 316*4c06356bSdh142964 for (i = 0; i < bs1->bs_words; i++) 317*4c06356bSdh142964 if (bs1->bs_set[i] != bs2->bs_set[i]) 318*4c06356bSdh142964 return (0); 319*4c06356bSdh142964 return (1); 320*4c06356bSdh142964 } 321*4c06356bSdh142964 322*4c06356bSdh142964 /* 323*4c06356bSdh142964 * Zero a bitset_t 324*4c06356bSdh142964 */ 325*4c06356bSdh142964 void 326*4c06356bSdh142964 bitset_zero(bitset_t *b) 327*4c06356bSdh142964 { 328*4c06356bSdh142964 bzero(b->bs_set, sizeof (ulong_t) * b->bs_words); 329*4c06356bSdh142964 } 330*4c06356bSdh142964 331*4c06356bSdh142964 332*4c06356bSdh142964 /* 333*4c06356bSdh142964 * Copy a bitset_t 334*4c06356bSdh142964 */ 335*4c06356bSdh142964 void 336*4c06356bSdh142964 bitset_copy(bitset_t *src, bitset_t *dest) 337*4c06356bSdh142964 { 338*4c06356bSdh142964 bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words); 339*4c06356bSdh142964 } 340