xref: /onnv-gate/usr/src/uts/common/os/bitset.c (revision 12149:607008ac563e)
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*12149Srafael.vanoni@sun.com  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
233434Sesaxe  */
243434Sesaxe 
253434Sesaxe #include <sys/bitset.h>
263434Sesaxe #include <sys/kmem.h>
273434Sesaxe #include <sys/systm.h>
288408SEric.Saxe@Sun.COM #include <sys/cpuvar.h>
293434Sesaxe #include <sys/cmn_err.h>
303434Sesaxe #include <sys/sysmacros.h>
313434Sesaxe 
323434Sesaxe /*
333434Sesaxe  * Initialize a bitset_t.
343434Sesaxe  * After bitset_init(), the bitset will be zero sized.
353434Sesaxe  */
363434Sesaxe void
bitset_init(bitset_t * b)373434Sesaxe bitset_init(bitset_t *b)
383434Sesaxe {
393434Sesaxe 	bzero(b, sizeof (bitset_t));
403434Sesaxe }
413434Sesaxe 
423434Sesaxe /*
43*12149Srafael.vanoni@sun.com  * Initialize a bitset_t using a fanout. The fanout factor is platform
44*12149Srafael.vanoni@sun.com  * specific and passed in as a power of two.
45*12149Srafael.vanoni@sun.com  */
46*12149Srafael.vanoni@sun.com void
bitset_init_fanout(bitset_t * b,uint_t fanout)47*12149Srafael.vanoni@sun.com bitset_init_fanout(bitset_t *b, uint_t fanout)
48*12149Srafael.vanoni@sun.com {
49*12149Srafael.vanoni@sun.com 	bzero(b, sizeof (bitset_t));
50*12149Srafael.vanoni@sun.com 	b->bs_fanout = fanout;
51*12149Srafael.vanoni@sun.com }
52*12149Srafael.vanoni@sun.com 
53*12149Srafael.vanoni@sun.com /*
543434Sesaxe  * Uninitialize a bitset_t.
553434Sesaxe  * This will free the bitset's data, leaving it zero sized.
563434Sesaxe  */
573434Sesaxe void
bitset_fini(bitset_t * b)583434Sesaxe bitset_fini(bitset_t *b)
593434Sesaxe {
603434Sesaxe 	if (b->bs_words > 0)
613434Sesaxe 		kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t));
623434Sesaxe }
633434Sesaxe 
643434Sesaxe /*
65*12149Srafael.vanoni@sun.com  * Resize a bitset to where it can hold els number of elements.
663434Sesaxe  * This can either grow or shrink the bitset holding capacity.
673434Sesaxe  * In the case of shrinkage, elements that reside outside the new
683434Sesaxe  * holding capacity of the bitset are lost.
693434Sesaxe  */
703434Sesaxe void
bitset_resize(bitset_t * b,uint_t els)71*12149Srafael.vanoni@sun.com bitset_resize(bitset_t *b, uint_t els)
723434Sesaxe {
733434Sesaxe 	uint_t	nwords;
743434Sesaxe 	ulong_t	*bset_new, *bset_tmp;
753434Sesaxe 
76*12149Srafael.vanoni@sun.com 	nwords = BT_BITOUL(els << b->bs_fanout);
773434Sesaxe 	if (b->bs_words == nwords)
783434Sesaxe 		return;	/* already properly sized */
793434Sesaxe 
803434Sesaxe 	/*
818408SEric.Saxe@Sun.COM 	 * Allocate the new ulong_t array, and copy the old one, if there
828408SEric.Saxe@Sun.COM 	 * was an old one.
833434Sesaxe 	 */
843434Sesaxe 	if (nwords > 0) {
853434Sesaxe 		bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP);
868408SEric.Saxe@Sun.COM 		if (b->bs_words > 0)
878408SEric.Saxe@Sun.COM 			bcopy(b->bs_set, bset_new,
888408SEric.Saxe@Sun.COM 			    MIN(b->bs_words, nwords) * sizeof (ulong_t));
893434Sesaxe 	} else {
903434Sesaxe 		bset_new = NULL;
913434Sesaxe 	}
923434Sesaxe 
933434Sesaxe 	/* swap out the old ulong_t array for new one */
943434Sesaxe 	bset_tmp = b->bs_set;
953434Sesaxe 	b->bs_set = bset_new;
963434Sesaxe 
973434Sesaxe 	/* free up the old array */
988408SEric.Saxe@Sun.COM 	if (b->bs_words > 0)
998408SEric.Saxe@Sun.COM 		kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t));
100*12149Srafael.vanoni@sun.com 
1013434Sesaxe 	b->bs_words = nwords;
1023434Sesaxe }
1033434Sesaxe 
1043434Sesaxe /*
105*12149Srafael.vanoni@sun.com  * Returns the current holding capacity of the bitset.
1063434Sesaxe  */
1073434Sesaxe uint_t
bitset_capacity(bitset_t * b)1083434Sesaxe bitset_capacity(bitset_t *b)
1093434Sesaxe {
1103434Sesaxe 	return (b->bs_words * BT_NBIPUL);
1113434Sesaxe }
1123434Sesaxe 
1133434Sesaxe /*
114*12149Srafael.vanoni@sun.com  * Add (set) and delete (clear) bits in the bitset.
1153434Sesaxe  *
116*12149Srafael.vanoni@sun.com  * Adding a bit that is already set, or removing a bit that's already clear
1173434Sesaxe  * is legal.
1183434Sesaxe  *
1193434Sesaxe  * Adding or deleting an element that falls outside the bitset's current
1203434Sesaxe  * holding capacity is illegal.
1213434Sesaxe  */
1223434Sesaxe void
bitset_add(bitset_t * b,uint_t elt)1233434Sesaxe bitset_add(bitset_t *b, uint_t elt)
1243434Sesaxe {
125*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
1263434Sesaxe 
127*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
128*12149Srafael.vanoni@sun.com 	BT_SET(b->bs_set, pos);
1293434Sesaxe }
1303434Sesaxe 
1318408SEric.Saxe@Sun.COM /*
132*12149Srafael.vanoni@sun.com  * Set a bit in an atomically safe way.
1338408SEric.Saxe@Sun.COM  */
1348408SEric.Saxe@Sun.COM void
bitset_atomic_add(bitset_t * b,uint_t elt)1358408SEric.Saxe@Sun.COM bitset_atomic_add(bitset_t *b, uint_t elt)
1368408SEric.Saxe@Sun.COM {
137*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
1388408SEric.Saxe@Sun.COM 
139*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
140*12149Srafael.vanoni@sun.com 	BT_ATOMIC_SET(b->bs_set, pos);
1418408SEric.Saxe@Sun.COM }
1428408SEric.Saxe@Sun.COM 
1438408SEric.Saxe@Sun.COM /*
1448408SEric.Saxe@Sun.COM  * Atomically test that a given bit isn't set, and set it.
1458408SEric.Saxe@Sun.COM  * Returns -1 if the bit was already set.
1468408SEric.Saxe@Sun.COM  */
1478408SEric.Saxe@Sun.COM int
bitset_atomic_test_and_add(bitset_t * b,uint_t elt)1488408SEric.Saxe@Sun.COM bitset_atomic_test_and_add(bitset_t *b, uint_t elt)
1498408SEric.Saxe@Sun.COM {
150*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
151*12149Srafael.vanoni@sun.com 	int ret;
1528408SEric.Saxe@Sun.COM 
153*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
154*12149Srafael.vanoni@sun.com 	BT_ATOMIC_SET_EXCL(b->bs_set, pos, ret);
1558408SEric.Saxe@Sun.COM 
156*12149Srafael.vanoni@sun.com 	return (ret);
1578408SEric.Saxe@Sun.COM }
1588408SEric.Saxe@Sun.COM 
1598408SEric.Saxe@Sun.COM /*
160*12149Srafael.vanoni@sun.com  * Clear a bit.
1618408SEric.Saxe@Sun.COM  */
1623434Sesaxe void
bitset_del(bitset_t * b,uint_t elt)1633434Sesaxe bitset_del(bitset_t *b, uint_t elt)
1643434Sesaxe {
165*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
1663434Sesaxe 
167*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
168*12149Srafael.vanoni@sun.com 	BT_CLEAR(b->bs_set, pos);
1693434Sesaxe }
1703434Sesaxe 
1713434Sesaxe /*
172*12149Srafael.vanoni@sun.com  * Clear a bit in an atomically safe way.
1738408SEric.Saxe@Sun.COM  */
1748408SEric.Saxe@Sun.COM void
bitset_atomic_del(bitset_t * b,uint_t elt)1758408SEric.Saxe@Sun.COM bitset_atomic_del(bitset_t *b, uint_t elt)
1768408SEric.Saxe@Sun.COM {
177*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
1788408SEric.Saxe@Sun.COM 
179*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
180*12149Srafael.vanoni@sun.com 	BT_ATOMIC_CLEAR(b->bs_set, pos);
1818408SEric.Saxe@Sun.COM }
1828408SEric.Saxe@Sun.COM 
1838408SEric.Saxe@Sun.COM /*
1848408SEric.Saxe@Sun.COM  * Atomically test that a bit is set, and clear it.
1858408SEric.Saxe@Sun.COM  * Returns -1 if the bit was already clear.
1868408SEric.Saxe@Sun.COM  */
1878408SEric.Saxe@Sun.COM int
bitset_atomic_test_and_del(bitset_t * b,uint_t elt)1888408SEric.Saxe@Sun.COM bitset_atomic_test_and_del(bitset_t *b, uint_t elt)
1898408SEric.Saxe@Sun.COM {
190*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
191*12149Srafael.vanoni@sun.com 	int ret;
1928408SEric.Saxe@Sun.COM 
193*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words * BT_NBIPUL > pos);
194*12149Srafael.vanoni@sun.com 	BT_ATOMIC_CLEAR_EXCL(b->bs_set, pos, ret);
1958408SEric.Saxe@Sun.COM 
196*12149Srafael.vanoni@sun.com 	return (ret);
1978408SEric.Saxe@Sun.COM }
1988408SEric.Saxe@Sun.COM 
1998408SEric.Saxe@Sun.COM /*
200*12149Srafael.vanoni@sun.com  * Return non-zero if the bit is present in the set.
2013434Sesaxe  */
2023434Sesaxe int
bitset_in_set(bitset_t * b,uint_t elt)2033434Sesaxe bitset_in_set(bitset_t *b, uint_t elt)
2043434Sesaxe {
205*12149Srafael.vanoni@sun.com 	uint_t pos = (elt << b->bs_fanout);
206*12149Srafael.vanoni@sun.com 
207*12149Srafael.vanoni@sun.com 	if (pos >= b->bs_words * BT_NBIPUL)
2083693Sesaxe 		return (0);
2093434Sesaxe 
210*12149Srafael.vanoni@sun.com 	return (BT_TEST(b->bs_set, pos));
2113434Sesaxe }
2123434Sesaxe 
2133434Sesaxe /*
214*12149Srafael.vanoni@sun.com  * Return non-zero if the bitset is empty.
2153434Sesaxe  */
2163434Sesaxe int
bitset_is_null(bitset_t * b)2173434Sesaxe bitset_is_null(bitset_t *b)
2183434Sesaxe {
219*12149Srafael.vanoni@sun.com 	int i;
2203434Sesaxe 
2213434Sesaxe 	for (i = 0; i < b->bs_words; i++)
2223434Sesaxe 		if (b->bs_set[i] != 0)
2233434Sesaxe 			return (0);
2243434Sesaxe 	return (1);
2253434Sesaxe }
2263434Sesaxe 
2273434Sesaxe /*
228*12149Srafael.vanoni@sun.com  * Perform a non-victimizing search for a set bit in a word.
2298408SEric.Saxe@Sun.COM  * A "seed" is passed to pseudo-randomize the search.
230*12149Srafael.vanoni@sun.com  * Return -1 if no set bit was found.
2318408SEric.Saxe@Sun.COM  */
2328408SEric.Saxe@Sun.COM static uint_t
bitset_find_in_word(ulong_t w,uint_t seed)2338408SEric.Saxe@Sun.COM bitset_find_in_word(ulong_t w, uint_t seed)
2348408SEric.Saxe@Sun.COM {
2358408SEric.Saxe@Sun.COM 	uint_t rotate_bit, elt = (uint_t)-1;
2368408SEric.Saxe@Sun.COM 	ulong_t rotated_word;
2378408SEric.Saxe@Sun.COM 
2388408SEric.Saxe@Sun.COM 	if (w == (ulong_t)0)
2398408SEric.Saxe@Sun.COM 		return (elt);
2408408SEric.Saxe@Sun.COM 
2418408SEric.Saxe@Sun.COM 	rotate_bit = seed % BT_NBIPUL;
2428408SEric.Saxe@Sun.COM 	rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit));
2438408SEric.Saxe@Sun.COM 	elt = (uint_t)(lowbit(rotated_word) - 1);
2448408SEric.Saxe@Sun.COM 	if (elt != (uint_t)-1)
2458408SEric.Saxe@Sun.COM 		elt = ((elt + rotate_bit) % BT_NBIPUL);
2468408SEric.Saxe@Sun.COM 
2478408SEric.Saxe@Sun.COM 	return (elt);
2488408SEric.Saxe@Sun.COM }
2498408SEric.Saxe@Sun.COM 
2508408SEric.Saxe@Sun.COM /*
2518408SEric.Saxe@Sun.COM  * Select a bit that is set in the bitset in a non-victimizing fashion
2528408SEric.Saxe@Sun.COM  * (e.g. doesn't bias the low/high order bits/words).
2538408SEric.Saxe@Sun.COM  * Return -1 if no set bit was found
2543434Sesaxe  */
2553434Sesaxe uint_t
bitset_find(bitset_t * b)2563434Sesaxe bitset_find(bitset_t *b)
2573434Sesaxe {
2588408SEric.Saxe@Sun.COM 	uint_t start, i;
2598408SEric.Saxe@Sun.COM 	uint_t elt = (uint_t)-1;
2608408SEric.Saxe@Sun.COM 	uint_t seed;
2613434Sesaxe 
2628408SEric.Saxe@Sun.COM 	seed = CPU_PSEUDO_RANDOM();
263*12149Srafael.vanoni@sun.com 
264*12149Srafael.vanoni@sun.com 	ASSERT(b->bs_words > 0);
2658408SEric.Saxe@Sun.COM 	start = seed % b->bs_words;
2668408SEric.Saxe@Sun.COM 
2678408SEric.Saxe@Sun.COM 	i = start;
2688408SEric.Saxe@Sun.COM 	do {
2698408SEric.Saxe@Sun.COM 		elt = bitset_find_in_word(b->bs_set[i], seed);
2703434Sesaxe 		if (elt != (uint_t)-1) {
2713434Sesaxe 			elt += i * BT_NBIPUL;
272*12149Srafael.vanoni@sun.com 			return (elt >> b->bs_fanout);
2733434Sesaxe 		}
2748408SEric.Saxe@Sun.COM 		if (++i == b->bs_words)
2758408SEric.Saxe@Sun.COM 			i = 0;
2768408SEric.Saxe@Sun.COM 	} while (i != start);
2778408SEric.Saxe@Sun.COM 
2783434Sesaxe 	return (elt);
2793434Sesaxe }
28010696SDavid.Hollister@Sun.COM 
28110696SDavid.Hollister@Sun.COM /*
282*12149Srafael.vanoni@sun.com  * AND, OR, and XOR bitset computations, returns 1 if resulting bitset has any
283*12149Srafael.vanoni@sun.com  * set bits. Operands must have the same fanout, if any.
28410696SDavid.Hollister@Sun.COM  */
28510696SDavid.Hollister@Sun.COM int
bitset_and(bitset_t * bs1,bitset_t * bs2,bitset_t * res)28610696SDavid.Hollister@Sun.COM bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
28710696SDavid.Hollister@Sun.COM {
28810696SDavid.Hollister@Sun.COM 	int i, anyset;
28910696SDavid.Hollister@Sun.COM 
290*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == bs2->bs_fanout);
291*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == res->bs_fanout);
292*12149Srafael.vanoni@sun.com 
29310696SDavid.Hollister@Sun.COM 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
29410696SDavid.Hollister@Sun.COM 		if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0)
29510696SDavid.Hollister@Sun.COM 			anyset = 1;
29610696SDavid.Hollister@Sun.COM 	}
29710696SDavid.Hollister@Sun.COM 	return (anyset);
29810696SDavid.Hollister@Sun.COM }
29910696SDavid.Hollister@Sun.COM 
30010696SDavid.Hollister@Sun.COM int
bitset_or(bitset_t * bs1,bitset_t * bs2,bitset_t * res)30110696SDavid.Hollister@Sun.COM bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
30210696SDavid.Hollister@Sun.COM {
30310696SDavid.Hollister@Sun.COM 	int i, anyset;
30410696SDavid.Hollister@Sun.COM 
305*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == bs2->bs_fanout);
306*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == res->bs_fanout);
307*12149Srafael.vanoni@sun.com 
30810696SDavid.Hollister@Sun.COM 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
30910696SDavid.Hollister@Sun.COM 		if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0)
31010696SDavid.Hollister@Sun.COM 			anyset = 1;
31110696SDavid.Hollister@Sun.COM 	}
31210696SDavid.Hollister@Sun.COM 	return (anyset);
31310696SDavid.Hollister@Sun.COM }
31410696SDavid.Hollister@Sun.COM 
31510696SDavid.Hollister@Sun.COM int
bitset_xor(bitset_t * bs1,bitset_t * bs2,bitset_t * res)31610696SDavid.Hollister@Sun.COM bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
31710696SDavid.Hollister@Sun.COM {
318*12149Srafael.vanoni@sun.com 	int i, anyset = 0;
319*12149Srafael.vanoni@sun.com 
320*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == bs2->bs_fanout);
321*12149Srafael.vanoni@sun.com 	ASSERT(bs1->bs_fanout == res->bs_fanout);
32210696SDavid.Hollister@Sun.COM 
32310696SDavid.Hollister@Sun.COM 	for (i = 0; i < bs1->bs_words; i++) {
32410696SDavid.Hollister@Sun.COM 		if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0)
32510696SDavid.Hollister@Sun.COM 			anyset = 1;
32610696SDavid.Hollister@Sun.COM 	}
32710696SDavid.Hollister@Sun.COM 	return (anyset);
32810696SDavid.Hollister@Sun.COM }
32910696SDavid.Hollister@Sun.COM 
33010696SDavid.Hollister@Sun.COM /*
331*12149Srafael.vanoni@sun.com  * Return 1 if bitmaps are identical.
33210696SDavid.Hollister@Sun.COM  */
33310696SDavid.Hollister@Sun.COM int
bitset_match(bitset_t * bs1,bitset_t * bs2)33410696SDavid.Hollister@Sun.COM bitset_match(bitset_t *bs1, bitset_t *bs2)
33510696SDavid.Hollister@Sun.COM {
33610696SDavid.Hollister@Sun.COM 	int i;
33710696SDavid.Hollister@Sun.COM 
33810696SDavid.Hollister@Sun.COM 	if (bs1->bs_words != bs2->bs_words)
33910696SDavid.Hollister@Sun.COM 		return (0);
34010696SDavid.Hollister@Sun.COM 
34110696SDavid.Hollister@Sun.COM 	for (i = 0; i < bs1->bs_words; i++)
34210696SDavid.Hollister@Sun.COM 		if (bs1->bs_set[i] != bs2->bs_set[i])
34310696SDavid.Hollister@Sun.COM 			return (0);
34410696SDavid.Hollister@Sun.COM 	return (1);
34510696SDavid.Hollister@Sun.COM }
34610696SDavid.Hollister@Sun.COM 
34710696SDavid.Hollister@Sun.COM /*
348*12149Srafael.vanoni@sun.com  * Zero a bitset_t.
34910696SDavid.Hollister@Sun.COM  */
35010696SDavid.Hollister@Sun.COM void
bitset_zero(bitset_t * b)35110696SDavid.Hollister@Sun.COM bitset_zero(bitset_t *b)
35210696SDavid.Hollister@Sun.COM {
35310696SDavid.Hollister@Sun.COM 	bzero(b->bs_set, sizeof (ulong_t) * b->bs_words);
35410696SDavid.Hollister@Sun.COM }
35510696SDavid.Hollister@Sun.COM 
35610696SDavid.Hollister@Sun.COM /*
357*12149Srafael.vanoni@sun.com  * Copy a bitset_t.
35810696SDavid.Hollister@Sun.COM  */
35910696SDavid.Hollister@Sun.COM void
bitset_copy(bitset_t * src,bitset_t * dest)36010696SDavid.Hollister@Sun.COM bitset_copy(bitset_t *src, bitset_t *dest)
36110696SDavid.Hollister@Sun.COM {
362*12149Srafael.vanoni@sun.com 	ASSERT(src->bs_fanout == dest->bs_fanout);
36310696SDavid.Hollister@Sun.COM 	bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words);
36410696SDavid.Hollister@Sun.COM }
365