xref: /illumos-gate/usr/src/uts/common/os/bitset.c (revision 0542eecf)
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
bitset_init(bitset_t * b)37fb2f18f8Sesaxe bitset_init(bitset_t *b)
38fb2f18f8Sesaxe {
39fb2f18f8Sesaxe 	bzero(b, sizeof (bitset_t));
40fb2f18f8Sesaxe }
41fb2f18f8Sesaxe 
42*0542eecfSRafael Vanoni /*
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
bitset_init_fanout(bitset_t * b,uint_t fanout)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 
53fb2f18f8Sesaxe /*
54fb2f18f8Sesaxe  * Uninitialize a bitset_t.
55fb2f18f8Sesaxe  * This will free the bitset's data, leaving it zero sized.
56fb2f18f8Sesaxe  */
57fb2f18f8Sesaxe void
bitset_fini(bitset_t * b)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
bitset_resize(bitset_t * b,uint_t els)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)
876890d023SEric Saxe 			bcopy(b->bs_set, bset_new,
886890d023SEric Saxe 			    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)
996890d023SEric Saxe 		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
bitset_capacity(bitset_t * b)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
bitset_add(bitset_t * b,uint_t elt)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
bitset_atomic_add(bitset_t * b,uint_t elt)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
bitset_atomic_test_and_add(bitset_t * b,uint_t elt)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
bitset_del(bitset_t * b,uint_t elt)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 
1716890d023SEric Saxe /*
172*0542eecfSRafael Vanoni  * Clear a bit in an atomically safe way.
1736890d023SEric Saxe  */
1746890d023SEric Saxe void
bitset_atomic_del(bitset_t * b,uint_t elt)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
bitset_atomic_test_and_del(bitset_t * b,uint_t elt)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 
199fb2f18f8Sesaxe /*
200*0542eecfSRafael Vanoni  * Return non-zero if the bit is present in the set.
201fb2f18f8Sesaxe  */
202fb2f18f8Sesaxe int
bitset_in_set(bitset_t * b,uint_t elt)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
bitset_is_null(bitset_t * b)217fb2f18f8Sesaxe bitset_is_null(bitset_t *b)
218fb2f18f8Sesaxe {
219*0542eecfSRafael Vanoni 	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
bitset_find_in_word(ulong_t w,uint_t seed)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
bitset_find(bitset_t * b)256fb2f18f8Sesaxe bitset_find(bitset_t *b)
257fb2f18f8Sesaxe {
2586890d023SEric Saxe 	uint_t start, i;
2596890d023SEric Saxe 	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 }
2804c06356bSdh 
2814c06356bSdh /*
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.
2844c06356bSdh  */
2854c06356bSdh int
bitset_and(bitset_t * bs1,bitset_t * bs2,bitset_t * res)2864c06356bSdh bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
2874c06356bSdh {
2884c06356bSdh 	int i, anyset;
2894c06356bSdh 
290*0542eecfSRafael Vanoni 	ASSERT(bs1->bs_fanout == bs2->bs_fanout);
291*0542eecfSRafael Vanoni 	ASSERT(bs1->bs_fanout == res->bs_fanout);
292*0542eecfSRafael Vanoni 
2934c06356bSdh 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
2944c06356bSdh 		if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0)
2954c06356bSdh 			anyset = 1;
2964c06356bSdh 	}
2974c06356bSdh 	return (anyset);
2984c06356bSdh }
2994c06356bSdh 
3004c06356bSdh int
bitset_or(bitset_t * bs1,bitset_t * bs2,bitset_t * res)3014c06356bSdh bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
3024c06356bSdh {
3034c06356bSdh 	int i, anyset;
3044c06356bSdh 
305*0542eecfSRafael Vanoni 	ASSERT(bs1->bs_fanout == bs2->bs_fanout);
306*0542eecfSRafael Vanoni 	ASSERT(bs1->bs_fanout == res->bs_fanout);
307*0542eecfSRafael Vanoni 
3084c06356bSdh 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
3094c06356bSdh 		if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0)
3104c06356bSdh 			anyset = 1;
3114c06356bSdh 	}
3124c06356bSdh 	return (anyset);
3134c06356bSdh }
3144c06356bSdh 
3154c06356bSdh int
bitset_xor(bitset_t * bs1,bitset_t * bs2,bitset_t * res)3164c06356bSdh bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
3174c06356bSdh {
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);
3224c06356bSdh 
3234c06356bSdh 	for (i = 0; i < bs1->bs_words; i++) {
3244c06356bSdh 		if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0)
3254c06356bSdh 			anyset = 1;
3264c06356bSdh 	}
3274c06356bSdh 	return (anyset);
3284c06356bSdh }
3294c06356bSdh 
3304c06356bSdh /*
331*0542eecfSRafael Vanoni  * Return 1 if bitmaps are identical.
3324c06356bSdh  */
3334c06356bSdh int
bitset_match(bitset_t * bs1,bitset_t * bs2)3344c06356bSdh bitset_match(bitset_t *bs1, bitset_t *bs2)
3354c06356bSdh {
3364c06356bSdh 	int i;
3374c06356bSdh 
3384c06356bSdh 	if (bs1->bs_words != bs2->bs_words)
3394c06356bSdh 		return (0);
3404c06356bSdh 
3414c06356bSdh 	for (i = 0; i < bs1->bs_words; i++)
3424c06356bSdh 		if (bs1->bs_set[i] != bs2->bs_set[i])
3434c06356bSdh 			return (0);
3444c06356bSdh 	return (1);
3454c06356bSdh }
3464c06356bSdh 
3474c06356bSdh /*
348*0542eecfSRafael Vanoni  * Zero a bitset_t.
3494c06356bSdh  */
3504c06356bSdh void
bitset_zero(bitset_t * b)3514c06356bSdh bitset_zero(bitset_t *b)
3524c06356bSdh {
3534c06356bSdh 	bzero(b->bs_set, sizeof (ulong_t) * b->bs_words);
3544c06356bSdh }
3554c06356bSdh 
3564c06356bSdh /*
357*0542eecfSRafael Vanoni  * Copy a bitset_t.
3584c06356bSdh  */
3594c06356bSdh void
bitset_copy(bitset_t * src,bitset_t * dest)3604c06356bSdh bitset_copy(bitset_t *src, bitset_t *dest)
3614c06356bSdh {
362*0542eecfSRafael Vanoni 	ASSERT(src->bs_fanout == dest->bs_fanout);
3634c06356bSdh 	bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words);
3644c06356bSdh }
365