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*0542eecfSRafael Vanoni * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23fb2f18f8Sesaxe */ 24fb2f18f8Sesaxe 25fb2f18f8Sesaxe #include <sys/bitset.h> 26fb2f18f8Sesaxe #include <sys/kmem.h> 27fb2f18f8Sesaxe #include <sys/systm.h> 286890d023SEric Saxe #include <sys/cpuvar.h> 29fb2f18f8Sesaxe #include <sys/cmn_err.h> 30fb2f18f8Sesaxe #include <sys/sysmacros.h> 31fb2f18f8Sesaxe 32fb2f18f8Sesaxe /* 33fb2f18f8Sesaxe * Initialize a bitset_t. 34fb2f18f8Sesaxe * After bitset_init(), the bitset will be zero sized. 35fb2f18f8Sesaxe */ 36fb2f18f8Sesaxe void 37fb2f18f8Sesaxe bitset_init(bitset_t *b) 38fb2f18f8Sesaxe { 39fb2f18f8Sesaxe bzero(b, sizeof (bitset_t)); 40fb2f18f8Sesaxe } 41fb2f18f8Sesaxe 42fb2f18f8Sesaxe /* 43*0542eecfSRafael Vanoni * Initialize a bitset_t using a fanout. The fanout factor is platform 44*0542eecfSRafael Vanoni * specific and passed in as a power of two. 45*0542eecfSRafael Vanoni */ 46*0542eecfSRafael Vanoni void 47*0542eecfSRafael Vanoni bitset_init_fanout(bitset_t *b, uint_t fanout) 48*0542eecfSRafael Vanoni { 49*0542eecfSRafael Vanoni bzero(b, sizeof (bitset_t)); 50*0542eecfSRafael Vanoni b->bs_fanout = fanout; 51*0542eecfSRafael Vanoni } 52*0542eecfSRafael Vanoni 53*0542eecfSRafael Vanoni /* 54fb2f18f8Sesaxe * Uninitialize a bitset_t. 55fb2f18f8Sesaxe * This will free the bitset's data, leaving it zero sized. 56fb2f18f8Sesaxe */ 57fb2f18f8Sesaxe void 58fb2f18f8Sesaxe bitset_fini(bitset_t *b) 59fb2f18f8Sesaxe { 60fb2f18f8Sesaxe if (b->bs_words > 0) 61fb2f18f8Sesaxe kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t)); 62fb2f18f8Sesaxe } 63fb2f18f8Sesaxe 64fb2f18f8Sesaxe /* 65*0542eecfSRafael Vanoni * Resize a bitset to where it can hold els number of elements. 66fb2f18f8Sesaxe * This can either grow or shrink the bitset holding capacity. 67fb2f18f8Sesaxe * In the case of shrinkage, elements that reside outside the new 68fb2f18f8Sesaxe * holding capacity of the bitset are lost. 69fb2f18f8Sesaxe */ 70fb2f18f8Sesaxe void 71*0542eecfSRafael Vanoni bitset_resize(bitset_t *b, uint_t els) 72fb2f18f8Sesaxe { 73fb2f18f8Sesaxe uint_t nwords; 74fb2f18f8Sesaxe ulong_t *bset_new, *bset_tmp; 75fb2f18f8Sesaxe 76*0542eecfSRafael Vanoni nwords = BT_BITOUL(els << b->bs_fanout); 77fb2f18f8Sesaxe if (b->bs_words == nwords) 78fb2f18f8Sesaxe return; /* already properly sized */ 79fb2f18f8Sesaxe 80fb2f18f8Sesaxe /* 816890d023SEric Saxe * Allocate the new ulong_t array, and copy the old one, if there 826890d023SEric Saxe * was an old one. 83fb2f18f8Sesaxe */ 84fb2f18f8Sesaxe if (nwords > 0) { 85fb2f18f8Sesaxe bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP); 866890d023SEric Saxe if (b->bs_words > 0) 87fb2f18f8Sesaxe bcopy(b->bs_set, bset_new, 88fb2f18f8Sesaxe MIN(b->bs_words, nwords) * sizeof (ulong_t)); 89fb2f18f8Sesaxe } else { 90fb2f18f8Sesaxe bset_new = NULL; 91fb2f18f8Sesaxe } 92fb2f18f8Sesaxe 93fb2f18f8Sesaxe /* swap out the old ulong_t array for new one */ 94fb2f18f8Sesaxe bset_tmp = b->bs_set; 95fb2f18f8Sesaxe b->bs_set = bset_new; 96fb2f18f8Sesaxe 97fb2f18f8Sesaxe /* free up the old array */ 986890d023SEric Saxe if (b->bs_words > 0) 99fb2f18f8Sesaxe kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t)); 100*0542eecfSRafael Vanoni 101fb2f18f8Sesaxe b->bs_words = nwords; 102fb2f18f8Sesaxe } 103fb2f18f8Sesaxe 104fb2f18f8Sesaxe /* 105*0542eecfSRafael Vanoni * Returns the current holding capacity of the bitset. 106fb2f18f8Sesaxe */ 107fb2f18f8Sesaxe uint_t 108fb2f18f8Sesaxe bitset_capacity(bitset_t *b) 109fb2f18f8Sesaxe { 110fb2f18f8Sesaxe return (b->bs_words * BT_NBIPUL); 111fb2f18f8Sesaxe } 112fb2f18f8Sesaxe 113fb2f18f8Sesaxe /* 114*0542eecfSRafael Vanoni * Add (set) and delete (clear) bits in the bitset. 115fb2f18f8Sesaxe * 116*0542eecfSRafael Vanoni * Adding a bit that is already set, or removing a bit that's already clear 117fb2f18f8Sesaxe * is legal. 118fb2f18f8Sesaxe * 119fb2f18f8Sesaxe * Adding or deleting an element that falls outside the bitset's current 120fb2f18f8Sesaxe * holding capacity is illegal. 121fb2f18f8Sesaxe */ 122fb2f18f8Sesaxe void 123fb2f18f8Sesaxe bitset_add(bitset_t *b, uint_t elt) 124fb2f18f8Sesaxe { 125*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 126fb2f18f8Sesaxe 127*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 128*0542eecfSRafael Vanoni BT_SET(b->bs_set, pos); 129fb2f18f8Sesaxe } 130fb2f18f8Sesaxe 1316890d023SEric Saxe /* 132*0542eecfSRafael Vanoni * Set a bit in an atomically safe way. 1336890d023SEric Saxe */ 1346890d023SEric Saxe void 1356890d023SEric Saxe bitset_atomic_add(bitset_t *b, uint_t elt) 1366890d023SEric Saxe { 137*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 1386890d023SEric Saxe 139*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 140*0542eecfSRafael Vanoni BT_ATOMIC_SET(b->bs_set, pos); 1416890d023SEric Saxe } 1426890d023SEric Saxe 1436890d023SEric Saxe /* 1446890d023SEric Saxe * Atomically test that a given bit isn't set, and set it. 1456890d023SEric Saxe * Returns -1 if the bit was already set. 1466890d023SEric Saxe */ 1476890d023SEric Saxe int 1486890d023SEric Saxe bitset_atomic_test_and_add(bitset_t *b, uint_t elt) 1496890d023SEric Saxe { 150*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 151*0542eecfSRafael Vanoni int ret; 1526890d023SEric Saxe 153*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 154*0542eecfSRafael Vanoni BT_ATOMIC_SET_EXCL(b->bs_set, pos, ret); 1556890d023SEric Saxe 156*0542eecfSRafael Vanoni return (ret); 1576890d023SEric Saxe } 1586890d023SEric Saxe 1596890d023SEric Saxe /* 160*0542eecfSRafael Vanoni * Clear a bit. 1616890d023SEric Saxe */ 162fb2f18f8Sesaxe void 163fb2f18f8Sesaxe bitset_del(bitset_t *b, uint_t elt) 164fb2f18f8Sesaxe { 165*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 166fb2f18f8Sesaxe 167*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 168*0542eecfSRafael Vanoni BT_CLEAR(b->bs_set, pos); 169fb2f18f8Sesaxe } 170fb2f18f8Sesaxe 171fb2f18f8Sesaxe /* 172*0542eecfSRafael Vanoni * Clear a bit in an atomically safe way. 1736890d023SEric Saxe */ 1746890d023SEric Saxe void 1756890d023SEric Saxe bitset_atomic_del(bitset_t *b, uint_t elt) 1766890d023SEric Saxe { 177*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 1786890d023SEric Saxe 179*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 180*0542eecfSRafael Vanoni BT_ATOMIC_CLEAR(b->bs_set, pos); 1816890d023SEric Saxe } 1826890d023SEric Saxe 1836890d023SEric Saxe /* 1846890d023SEric Saxe * Atomically test that a bit is set, and clear it. 1856890d023SEric Saxe * Returns -1 if the bit was already clear. 1866890d023SEric Saxe */ 1876890d023SEric Saxe int 1886890d023SEric Saxe bitset_atomic_test_and_del(bitset_t *b, uint_t elt) 1896890d023SEric Saxe { 190*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 191*0542eecfSRafael Vanoni int ret; 1926890d023SEric Saxe 193*0542eecfSRafael Vanoni ASSERT(b->bs_words * BT_NBIPUL > pos); 194*0542eecfSRafael Vanoni BT_ATOMIC_CLEAR_EXCL(b->bs_set, pos, ret); 1956890d023SEric Saxe 196*0542eecfSRafael Vanoni return (ret); 1976890d023SEric Saxe } 1986890d023SEric Saxe 1996890d023SEric Saxe /* 200*0542eecfSRafael Vanoni * Return non-zero if the bit is present in the set. 201fb2f18f8Sesaxe */ 202fb2f18f8Sesaxe int 203fb2f18f8Sesaxe bitset_in_set(bitset_t *b, uint_t elt) 204fb2f18f8Sesaxe { 205*0542eecfSRafael Vanoni uint_t pos = (elt << b->bs_fanout); 206*0542eecfSRafael Vanoni 207*0542eecfSRafael Vanoni if (pos >= b->bs_words * BT_NBIPUL) 2080f424180Sesaxe return (0); 209fb2f18f8Sesaxe 210*0542eecfSRafael Vanoni return (BT_TEST(b->bs_set, pos)); 211fb2f18f8Sesaxe } 212fb2f18f8Sesaxe 213fb2f18f8Sesaxe /* 214*0542eecfSRafael Vanoni * Return non-zero if the bitset is empty. 215fb2f18f8Sesaxe */ 216fb2f18f8Sesaxe int 217fb2f18f8Sesaxe bitset_is_null(bitset_t *b) 218fb2f18f8Sesaxe { 219fb2f18f8Sesaxe int i; 220fb2f18f8Sesaxe 221fb2f18f8Sesaxe for (i = 0; i < b->bs_words; i++) 222fb2f18f8Sesaxe if (b->bs_set[i] != 0) 223fb2f18f8Sesaxe return (0); 224fb2f18f8Sesaxe return (1); 225fb2f18f8Sesaxe } 226fb2f18f8Sesaxe 227fb2f18f8Sesaxe /* 228*0542eecfSRafael Vanoni * Perform a non-victimizing search for a set bit in a word. 2296890d023SEric Saxe * A "seed" is passed to pseudo-randomize the search. 230*0542eecfSRafael Vanoni * Return -1 if no set bit was found. 2316890d023SEric Saxe */ 2326890d023SEric Saxe static uint_t 2336890d023SEric Saxe bitset_find_in_word(ulong_t w, uint_t seed) 2346890d023SEric Saxe { 2356890d023SEric Saxe uint_t rotate_bit, elt = (uint_t)-1; 2366890d023SEric Saxe ulong_t rotated_word; 2376890d023SEric Saxe 2386890d023SEric Saxe if (w == (ulong_t)0) 2396890d023SEric Saxe return (elt); 2406890d023SEric Saxe 2416890d023SEric Saxe rotate_bit = seed % BT_NBIPUL; 2426890d023SEric Saxe rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit)); 2436890d023SEric Saxe elt = (uint_t)(lowbit(rotated_word) - 1); 2446890d023SEric Saxe if (elt != (uint_t)-1) 2456890d023SEric Saxe elt = ((elt + rotate_bit) % BT_NBIPUL); 2466890d023SEric Saxe 2476890d023SEric Saxe return (elt); 2486890d023SEric Saxe } 2496890d023SEric Saxe 2506890d023SEric Saxe /* 2516890d023SEric Saxe * Select a bit that is set in the bitset in a non-victimizing fashion 2526890d023SEric Saxe * (e.g. doesn't bias the low/high order bits/words). 2536890d023SEric Saxe * Return -1 if no set bit was found 254fb2f18f8Sesaxe */ 255fb2f18f8Sesaxe uint_t 256fb2f18f8Sesaxe bitset_find(bitset_t *b) 257fb2f18f8Sesaxe { 2586890d023SEric Saxe uint_t start, i; 259fb2f18f8Sesaxe uint_t elt = (uint_t)-1; 2606890d023SEric Saxe uint_t seed; 261fb2f18f8Sesaxe 2626890d023SEric Saxe seed = CPU_PSEUDO_RANDOM(); 263*0542eecfSRafael Vanoni 264*0542eecfSRafael Vanoni ASSERT(b->bs_words > 0); 2656890d023SEric Saxe start = seed % b->bs_words; 2666890d023SEric Saxe 2676890d023SEric Saxe i = start; 2686890d023SEric Saxe do { 2696890d023SEric Saxe elt = bitset_find_in_word(b->bs_set[i], seed); 270fb2f18f8Sesaxe if (elt != (uint_t)-1) { 271fb2f18f8Sesaxe elt += i * BT_NBIPUL; 272*0542eecfSRafael Vanoni return (elt >> b->bs_fanout); 273fb2f18f8Sesaxe } 2746890d023SEric Saxe if (++i == b->bs_words) 2756890d023SEric Saxe i = 0; 2766890d023SEric Saxe } while (i != start); 2776890d023SEric Saxe 278fb2f18f8Sesaxe return (elt); 279fb2f18f8Sesaxe } 2804c06356bSdh142964 2814c06356bSdh142964 /* 282*0542eecfSRafael Vanoni * AND, OR, and XOR bitset computations, returns 1 if resulting bitset has any 283*0542eecfSRafael Vanoni * set bits. Operands must have the same fanout, if any. 2844c06356bSdh142964 */ 2854c06356bSdh142964 int 2864c06356bSdh142964 bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 2874c06356bSdh142964 { 2884c06356bSdh142964 int i, anyset; 2894c06356bSdh142964 290*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == bs2->bs_fanout); 291*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == res->bs_fanout); 292*0542eecfSRafael Vanoni 2934c06356bSdh142964 for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 2944c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0) 2954c06356bSdh142964 anyset = 1; 2964c06356bSdh142964 } 2974c06356bSdh142964 return (anyset); 2984c06356bSdh142964 } 2994c06356bSdh142964 3004c06356bSdh142964 int 3014c06356bSdh142964 bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 3024c06356bSdh142964 { 3034c06356bSdh142964 int i, anyset; 3044c06356bSdh142964 305*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == bs2->bs_fanout); 306*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == res->bs_fanout); 307*0542eecfSRafael Vanoni 3084c06356bSdh142964 for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 3094c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0) 3104c06356bSdh142964 anyset = 1; 3114c06356bSdh142964 } 3124c06356bSdh142964 return (anyset); 3134c06356bSdh142964 } 3144c06356bSdh142964 3154c06356bSdh142964 int 3164c06356bSdh142964 bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 3174c06356bSdh142964 { 318*0542eecfSRafael Vanoni int i, anyset = 0; 319*0542eecfSRafael Vanoni 320*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == bs2->bs_fanout); 321*0542eecfSRafael Vanoni ASSERT(bs1->bs_fanout == res->bs_fanout); 3224c06356bSdh142964 3234c06356bSdh142964 for (i = 0; i < bs1->bs_words; i++) { 3244c06356bSdh142964 if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0) 3254c06356bSdh142964 anyset = 1; 3264c06356bSdh142964 } 3274c06356bSdh142964 return (anyset); 3284c06356bSdh142964 } 3294c06356bSdh142964 3304c06356bSdh142964 /* 331*0542eecfSRafael Vanoni * Return 1 if bitmaps are identical. 3324c06356bSdh142964 */ 3334c06356bSdh142964 int 3344c06356bSdh142964 bitset_match(bitset_t *bs1, bitset_t *bs2) 3354c06356bSdh142964 { 3364c06356bSdh142964 int i; 3374c06356bSdh142964 3384c06356bSdh142964 if (bs1->bs_words != bs2->bs_words) 3394c06356bSdh142964 return (0); 3404c06356bSdh142964 3414c06356bSdh142964 for (i = 0; i < bs1->bs_words; i++) 3424c06356bSdh142964 if (bs1->bs_set[i] != bs2->bs_set[i]) 3434c06356bSdh142964 return (0); 3444c06356bSdh142964 return (1); 3454c06356bSdh142964 } 3464c06356bSdh142964 3474c06356bSdh142964 /* 348*0542eecfSRafael Vanoni * Zero a bitset_t. 3494c06356bSdh142964 */ 3504c06356bSdh142964 void 3514c06356bSdh142964 bitset_zero(bitset_t *b) 3524c06356bSdh142964 { 3534c06356bSdh142964 bzero(b->bs_set, sizeof (ulong_t) * b->bs_words); 3544c06356bSdh142964 } 3554c06356bSdh142964 3564c06356bSdh142964 /* 357*0542eecfSRafael Vanoni * Copy a bitset_t. 3584c06356bSdh142964 */ 3594c06356bSdh142964 void 3604c06356bSdh142964 bitset_copy(bitset_t *src, bitset_t *dest) 3614c06356bSdh142964 { 362*0542eecfSRafael Vanoni ASSERT(src->bs_fanout == dest->bs_fanout); 3634c06356bSdh142964 bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words); 3644c06356bSdh142964 } 365