13434Sesaxe /* 23434Sesaxe * CDDL HEADER START 33434Sesaxe * 43434Sesaxe * The contents of this file are subject to the terms of the 53434Sesaxe * Common Development and Distribution License (the "License"). 63434Sesaxe * You may not use this file except in compliance with the License. 73434Sesaxe * 83434Sesaxe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93434Sesaxe * or http://www.opensolaris.org/os/licensing. 103434Sesaxe * See the License for the specific language governing permissions 113434Sesaxe * and limitations under the License. 123434Sesaxe * 133434Sesaxe * When distributing Covered Code, include this CDDL HEADER in each 143434Sesaxe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153434Sesaxe * If applicable, add the following below this CDDL HEADER, with the 163434Sesaxe * fields enclosed by brackets "[]" replaced with your own identifying 173434Sesaxe * information: Portions Copyright [yyyy] [name of copyright owner] 183434Sesaxe * 193434Sesaxe * CDDL HEADER END 203434Sesaxe */ 213434Sesaxe /* 22*10696SDavid.Hollister@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 233434Sesaxe * Use is subject to license terms. 243434Sesaxe */ 253434Sesaxe 263434Sesaxe #include <sys/bitset.h> 273434Sesaxe #include <sys/kmem.h> 283434Sesaxe #include <sys/systm.h> 298408SEric.Saxe@Sun.COM #include <sys/cpuvar.h> 303434Sesaxe #include <sys/cmn_err.h> 313434Sesaxe #include <sys/sysmacros.h> 323434Sesaxe 333434Sesaxe /* 343434Sesaxe * Initialize a bitset_t. 353434Sesaxe * After bitset_init(), the bitset will be zero sized. 363434Sesaxe */ 373434Sesaxe void 383434Sesaxe bitset_init(bitset_t *b) 393434Sesaxe { 403434Sesaxe bzero(b, sizeof (bitset_t)); 413434Sesaxe } 423434Sesaxe 433434Sesaxe /* 443434Sesaxe * Uninitialize a bitset_t. 453434Sesaxe * This will free the bitset's data, leaving it zero sized. 463434Sesaxe */ 473434Sesaxe void 483434Sesaxe bitset_fini(bitset_t *b) 493434Sesaxe { 503434Sesaxe if (b->bs_words > 0) 513434Sesaxe kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t)); 523434Sesaxe } 533434Sesaxe 543434Sesaxe /* 553434Sesaxe * Resize a bitset to where it can hold sz number of bits. 563434Sesaxe * This can either grow or shrink the bitset holding capacity. 573434Sesaxe * In the case of shrinkage, elements that reside outside the new 583434Sesaxe * holding capacity of the bitset are lost. 593434Sesaxe */ 603434Sesaxe void 613434Sesaxe bitset_resize(bitset_t *b, uint_t sz) 623434Sesaxe { 633434Sesaxe uint_t nwords; 643434Sesaxe ulong_t *bset_new, *bset_tmp; 653434Sesaxe 663434Sesaxe nwords = BT_BITOUL(sz); 673434Sesaxe if (b->bs_words == nwords) 683434Sesaxe return; /* already properly sized */ 693434Sesaxe 703434Sesaxe /* 718408SEric.Saxe@Sun.COM * Allocate the new ulong_t array, and copy the old one, if there 728408SEric.Saxe@Sun.COM * was an old one. 733434Sesaxe */ 743434Sesaxe if (nwords > 0) { 753434Sesaxe bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP); 768408SEric.Saxe@Sun.COM if (b->bs_words > 0) 778408SEric.Saxe@Sun.COM bcopy(b->bs_set, bset_new, 788408SEric.Saxe@Sun.COM MIN(b->bs_words, nwords) * sizeof (ulong_t)); 793434Sesaxe } else { 803434Sesaxe bset_new = NULL; 813434Sesaxe } 823434Sesaxe 833434Sesaxe /* swap out the old ulong_t array for new one */ 843434Sesaxe bset_tmp = b->bs_set; 853434Sesaxe b->bs_set = bset_new; 863434Sesaxe 873434Sesaxe /* free up the old array */ 888408SEric.Saxe@Sun.COM if (b->bs_words > 0) 898408SEric.Saxe@Sun.COM kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t)); 903434Sesaxe b->bs_words = nwords; 913434Sesaxe } 923434Sesaxe 933434Sesaxe /* 943434Sesaxe * Returns the current holding capacity of the bitset 953434Sesaxe */ 963434Sesaxe uint_t 973434Sesaxe bitset_capacity(bitset_t *b) 983434Sesaxe { 993434Sesaxe return (b->bs_words * BT_NBIPUL); 1003434Sesaxe } 1013434Sesaxe 1023434Sesaxe /* 1033434Sesaxe * Add and delete bits in the bitset. 1043434Sesaxe * 1053434Sesaxe * Adding a bit that is already set, and clearing a bit that's already clear 1063434Sesaxe * is legal. 1073434Sesaxe * 1083434Sesaxe * Adding or deleting an element that falls outside the bitset's current 1093434Sesaxe * holding capacity is illegal. 1103434Sesaxe */ 1118408SEric.Saxe@Sun.COM 1128408SEric.Saxe@Sun.COM /* 1138408SEric.Saxe@Sun.COM * Set a bit 1148408SEric.Saxe@Sun.COM */ 1153434Sesaxe void 1163434Sesaxe bitset_add(bitset_t *b, uint_t elt) 1173434Sesaxe { 1183434Sesaxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1193434Sesaxe 1203434Sesaxe BT_SET(b->bs_set, elt); 1213434Sesaxe } 1223434Sesaxe 1238408SEric.Saxe@Sun.COM /* 1248408SEric.Saxe@Sun.COM * Set a bit in an atomically safe way 1258408SEric.Saxe@Sun.COM */ 1268408SEric.Saxe@Sun.COM void 1278408SEric.Saxe@Sun.COM bitset_atomic_add(bitset_t *b, uint_t elt) 1288408SEric.Saxe@Sun.COM { 1298408SEric.Saxe@Sun.COM ASSERT(b->bs_words * BT_NBIPUL > elt); 1308408SEric.Saxe@Sun.COM 1318408SEric.Saxe@Sun.COM BT_ATOMIC_SET(b->bs_set, elt); 1328408SEric.Saxe@Sun.COM } 1338408SEric.Saxe@Sun.COM 1348408SEric.Saxe@Sun.COM /* 1358408SEric.Saxe@Sun.COM * Atomically test that a given bit isn't set, and set it. 1368408SEric.Saxe@Sun.COM * Returns -1 if the bit was already set. 1378408SEric.Saxe@Sun.COM */ 1388408SEric.Saxe@Sun.COM int 1398408SEric.Saxe@Sun.COM bitset_atomic_test_and_add(bitset_t *b, uint_t elt) 1408408SEric.Saxe@Sun.COM { 1418408SEric.Saxe@Sun.COM int r; 1428408SEric.Saxe@Sun.COM 1438408SEric.Saxe@Sun.COM ASSERT(b->bs_words * BT_NBIPUL > elt); 1448408SEric.Saxe@Sun.COM BT_ATOMIC_SET_EXCL(b->bs_set, elt, r); 1458408SEric.Saxe@Sun.COM 1468408SEric.Saxe@Sun.COM return (r); 1478408SEric.Saxe@Sun.COM } 1488408SEric.Saxe@Sun.COM 1498408SEric.Saxe@Sun.COM /* 1508408SEric.Saxe@Sun.COM * Clear a bit 1518408SEric.Saxe@Sun.COM */ 1523434Sesaxe void 1533434Sesaxe bitset_del(bitset_t *b, uint_t elt) 1543434Sesaxe { 1553434Sesaxe ASSERT(b->bs_words * BT_NBIPUL > elt); 1563434Sesaxe 1573434Sesaxe BT_CLEAR(b->bs_set, elt); 1583434Sesaxe } 1593434Sesaxe 1603434Sesaxe /* 1618408SEric.Saxe@Sun.COM * Clear a bit in an atomically safe way 1628408SEric.Saxe@Sun.COM */ 1638408SEric.Saxe@Sun.COM void 1648408SEric.Saxe@Sun.COM bitset_atomic_del(bitset_t *b, uint_t elt) 1658408SEric.Saxe@Sun.COM { 1668408SEric.Saxe@Sun.COM ASSERT(b->bs_words * BT_NBIPUL > elt); 1678408SEric.Saxe@Sun.COM 1688408SEric.Saxe@Sun.COM BT_ATOMIC_CLEAR(b->bs_set, elt); 1698408SEric.Saxe@Sun.COM } 1708408SEric.Saxe@Sun.COM 1718408SEric.Saxe@Sun.COM /* 1728408SEric.Saxe@Sun.COM * Atomically test that a bit is set, and clear it. 1738408SEric.Saxe@Sun.COM * Returns -1 if the bit was already clear. 1748408SEric.Saxe@Sun.COM */ 1758408SEric.Saxe@Sun.COM int 1768408SEric.Saxe@Sun.COM bitset_atomic_test_and_del(bitset_t *b, uint_t elt) 1778408SEric.Saxe@Sun.COM { 1788408SEric.Saxe@Sun.COM int r; 1798408SEric.Saxe@Sun.COM 1808408SEric.Saxe@Sun.COM ASSERT(b->bs_words * BT_NBIPUL > elt); 1818408SEric.Saxe@Sun.COM BT_ATOMIC_CLEAR_EXCL(b->bs_set, elt, r); 1828408SEric.Saxe@Sun.COM 1838408SEric.Saxe@Sun.COM return (r); 1848408SEric.Saxe@Sun.COM } 1858408SEric.Saxe@Sun.COM 1868408SEric.Saxe@Sun.COM /* 1873434Sesaxe * Return non-zero if the bit is present in the set 1883434Sesaxe */ 1893434Sesaxe int 1903434Sesaxe bitset_in_set(bitset_t *b, uint_t elt) 1913434Sesaxe { 1923693Sesaxe if (elt >= b->bs_words * BT_NBIPUL) 1933693Sesaxe return (0); 1943434Sesaxe 1953434Sesaxe return (BT_TEST(b->bs_set, elt)); 1963434Sesaxe } 1973434Sesaxe 1983434Sesaxe /* 1993434Sesaxe * Return non-zero if the bitset is empty 2003434Sesaxe */ 2013434Sesaxe int 2023434Sesaxe bitset_is_null(bitset_t *b) 2033434Sesaxe { 2043434Sesaxe int i; 2053434Sesaxe 2063434Sesaxe for (i = 0; i < b->bs_words; i++) 2073434Sesaxe if (b->bs_set[i] != 0) 2083434Sesaxe return (0); 2093434Sesaxe return (1); 2103434Sesaxe } 2113434Sesaxe 2123434Sesaxe /* 2138408SEric.Saxe@Sun.COM * Perform a non-victimizing search for a set bit in a word 2148408SEric.Saxe@Sun.COM * A "seed" is passed to pseudo-randomize the search. 2158408SEric.Saxe@Sun.COM * Return -1 if no set bit was found 2168408SEric.Saxe@Sun.COM */ 2178408SEric.Saxe@Sun.COM static uint_t 2188408SEric.Saxe@Sun.COM bitset_find_in_word(ulong_t w, uint_t seed) 2198408SEric.Saxe@Sun.COM { 2208408SEric.Saxe@Sun.COM uint_t rotate_bit, elt = (uint_t)-1; 2218408SEric.Saxe@Sun.COM ulong_t rotated_word; 2228408SEric.Saxe@Sun.COM 2238408SEric.Saxe@Sun.COM if (w == (ulong_t)0) 2248408SEric.Saxe@Sun.COM return (elt); 2258408SEric.Saxe@Sun.COM 2268408SEric.Saxe@Sun.COM rotate_bit = seed % BT_NBIPUL; 2278408SEric.Saxe@Sun.COM rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit)); 2288408SEric.Saxe@Sun.COM elt = (uint_t)(lowbit(rotated_word) - 1); 2298408SEric.Saxe@Sun.COM if (elt != (uint_t)-1) 2308408SEric.Saxe@Sun.COM elt = ((elt + rotate_bit) % BT_NBIPUL); 2318408SEric.Saxe@Sun.COM 2328408SEric.Saxe@Sun.COM return (elt); 2338408SEric.Saxe@Sun.COM } 2348408SEric.Saxe@Sun.COM 2358408SEric.Saxe@Sun.COM /* 2368408SEric.Saxe@Sun.COM * Select a bit that is set in the bitset in a non-victimizing fashion 2378408SEric.Saxe@Sun.COM * (e.g. doesn't bias the low/high order bits/words). 2388408SEric.Saxe@Sun.COM * Return -1 if no set bit was found 2393434Sesaxe */ 2403434Sesaxe uint_t 2413434Sesaxe bitset_find(bitset_t *b) 2423434Sesaxe { 2438408SEric.Saxe@Sun.COM uint_t start, i; 2448408SEric.Saxe@Sun.COM uint_t elt = (uint_t)-1; 2458408SEric.Saxe@Sun.COM uint_t seed; 2463434Sesaxe 2478408SEric.Saxe@Sun.COM seed = CPU_PSEUDO_RANDOM(); 2488408SEric.Saxe@Sun.COM start = seed % b->bs_words; 2498408SEric.Saxe@Sun.COM 2508408SEric.Saxe@Sun.COM i = start; 2518408SEric.Saxe@Sun.COM do { 2528408SEric.Saxe@Sun.COM elt = bitset_find_in_word(b->bs_set[i], seed); 2533434Sesaxe if (elt != (uint_t)-1) { 2543434Sesaxe elt += i * BT_NBIPUL; 2553434Sesaxe break; 2563434Sesaxe } 2578408SEric.Saxe@Sun.COM if (++i == b->bs_words) 2588408SEric.Saxe@Sun.COM i = 0; 2598408SEric.Saxe@Sun.COM } while (i != start); 2608408SEric.Saxe@Sun.COM 2613434Sesaxe return (elt); 2623434Sesaxe } 263*10696SDavid.Hollister@Sun.COM 264*10696SDavid.Hollister@Sun.COM /* 265*10696SDavid.Hollister@Sun.COM * AND, OR, and XOR bitset computations 266*10696SDavid.Hollister@Sun.COM * Returns 1 if resulting bitset has any set bits 267*10696SDavid.Hollister@Sun.COM */ 268*10696SDavid.Hollister@Sun.COM int 269*10696SDavid.Hollister@Sun.COM bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 270*10696SDavid.Hollister@Sun.COM { 271*10696SDavid.Hollister@Sun.COM int i, anyset; 272*10696SDavid.Hollister@Sun.COM 273*10696SDavid.Hollister@Sun.COM for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 274*10696SDavid.Hollister@Sun.COM if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0) 275*10696SDavid.Hollister@Sun.COM anyset = 1; 276*10696SDavid.Hollister@Sun.COM } 277*10696SDavid.Hollister@Sun.COM return (anyset); 278*10696SDavid.Hollister@Sun.COM } 279*10696SDavid.Hollister@Sun.COM 280*10696SDavid.Hollister@Sun.COM int 281*10696SDavid.Hollister@Sun.COM bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 282*10696SDavid.Hollister@Sun.COM { 283*10696SDavid.Hollister@Sun.COM int i, anyset; 284*10696SDavid.Hollister@Sun.COM 285*10696SDavid.Hollister@Sun.COM for (anyset = 0, i = 0; i < bs1->bs_words; i++) { 286*10696SDavid.Hollister@Sun.COM if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0) 287*10696SDavid.Hollister@Sun.COM anyset = 1; 288*10696SDavid.Hollister@Sun.COM } 289*10696SDavid.Hollister@Sun.COM return (anyset); 290*10696SDavid.Hollister@Sun.COM } 291*10696SDavid.Hollister@Sun.COM 292*10696SDavid.Hollister@Sun.COM int 293*10696SDavid.Hollister@Sun.COM bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res) 294*10696SDavid.Hollister@Sun.COM { 295*10696SDavid.Hollister@Sun.COM int i; 296*10696SDavid.Hollister@Sun.COM int anyset = 0; 297*10696SDavid.Hollister@Sun.COM 298*10696SDavid.Hollister@Sun.COM for (i = 0; i < bs1->bs_words; i++) { 299*10696SDavid.Hollister@Sun.COM if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0) 300*10696SDavid.Hollister@Sun.COM anyset = 1; 301*10696SDavid.Hollister@Sun.COM } 302*10696SDavid.Hollister@Sun.COM return (anyset); 303*10696SDavid.Hollister@Sun.COM } 304*10696SDavid.Hollister@Sun.COM 305*10696SDavid.Hollister@Sun.COM /* 306*10696SDavid.Hollister@Sun.COM * return 1 if bitmaps are identical 307*10696SDavid.Hollister@Sun.COM */ 308*10696SDavid.Hollister@Sun.COM int 309*10696SDavid.Hollister@Sun.COM bitset_match(bitset_t *bs1, bitset_t *bs2) 310*10696SDavid.Hollister@Sun.COM { 311*10696SDavid.Hollister@Sun.COM int i; 312*10696SDavid.Hollister@Sun.COM 313*10696SDavid.Hollister@Sun.COM if (bs1->bs_words != bs2->bs_words) 314*10696SDavid.Hollister@Sun.COM return (0); 315*10696SDavid.Hollister@Sun.COM 316*10696SDavid.Hollister@Sun.COM for (i = 0; i < bs1->bs_words; i++) 317*10696SDavid.Hollister@Sun.COM if (bs1->bs_set[i] != bs2->bs_set[i]) 318*10696SDavid.Hollister@Sun.COM return (0); 319*10696SDavid.Hollister@Sun.COM return (1); 320*10696SDavid.Hollister@Sun.COM } 321*10696SDavid.Hollister@Sun.COM 322*10696SDavid.Hollister@Sun.COM /* 323*10696SDavid.Hollister@Sun.COM * Zero a bitset_t 324*10696SDavid.Hollister@Sun.COM */ 325*10696SDavid.Hollister@Sun.COM void 326*10696SDavid.Hollister@Sun.COM bitset_zero(bitset_t *b) 327*10696SDavid.Hollister@Sun.COM { 328*10696SDavid.Hollister@Sun.COM bzero(b->bs_set, sizeof (ulong_t) * b->bs_words); 329*10696SDavid.Hollister@Sun.COM } 330*10696SDavid.Hollister@Sun.COM 331*10696SDavid.Hollister@Sun.COM 332*10696SDavid.Hollister@Sun.COM /* 333*10696SDavid.Hollister@Sun.COM * Copy a bitset_t 334*10696SDavid.Hollister@Sun.COM */ 335*10696SDavid.Hollister@Sun.COM void 336*10696SDavid.Hollister@Sun.COM bitset_copy(bitset_t *src, bitset_t *dest) 337*10696SDavid.Hollister@Sun.COM { 338*10696SDavid.Hollister@Sun.COM bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words); 339*10696SDavid.Hollister@Sun.COM } 340