xref: /onnv-gate/usr/src/uts/common/os/bitset.c (revision 10696:cd0f390dd9e2)
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