xref: /titanic_54/usr/src/uts/common/os/bitset.c (revision 4c06356b0f0fffb4fc1b6eccc8e5d8e2254a84d6)
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*4c06356bSdh142964  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23fb2f18f8Sesaxe  * Use is subject to license terms.
24fb2f18f8Sesaxe  */
25fb2f18f8Sesaxe 
26fb2f18f8Sesaxe #include <sys/bitset.h>
27fb2f18f8Sesaxe #include <sys/kmem.h>
28fb2f18f8Sesaxe #include <sys/systm.h>
296890d023SEric Saxe #include <sys/cpuvar.h>
30fb2f18f8Sesaxe #include <sys/cmn_err.h>
31fb2f18f8Sesaxe #include <sys/sysmacros.h>
32fb2f18f8Sesaxe 
33fb2f18f8Sesaxe /*
34fb2f18f8Sesaxe  * Initialize a bitset_t.
35fb2f18f8Sesaxe  * After bitset_init(), the bitset will be zero sized.
36fb2f18f8Sesaxe  */
37fb2f18f8Sesaxe void
38fb2f18f8Sesaxe bitset_init(bitset_t *b)
39fb2f18f8Sesaxe {
40fb2f18f8Sesaxe 	bzero(b, sizeof (bitset_t));
41fb2f18f8Sesaxe }
42fb2f18f8Sesaxe 
43fb2f18f8Sesaxe /*
44fb2f18f8Sesaxe  * Uninitialize a bitset_t.
45fb2f18f8Sesaxe  * This will free the bitset's data, leaving it zero sized.
46fb2f18f8Sesaxe  */
47fb2f18f8Sesaxe void
48fb2f18f8Sesaxe bitset_fini(bitset_t *b)
49fb2f18f8Sesaxe {
50fb2f18f8Sesaxe 	if (b->bs_words > 0)
51fb2f18f8Sesaxe 		kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t));
52fb2f18f8Sesaxe }
53fb2f18f8Sesaxe 
54fb2f18f8Sesaxe /*
55fb2f18f8Sesaxe  * Resize a bitset to where it can hold sz number of bits.
56fb2f18f8Sesaxe  * This can either grow or shrink the bitset holding capacity.
57fb2f18f8Sesaxe  * In the case of shrinkage, elements that reside outside the new
58fb2f18f8Sesaxe  * holding capacity of the bitset are lost.
59fb2f18f8Sesaxe  */
60fb2f18f8Sesaxe void
61fb2f18f8Sesaxe bitset_resize(bitset_t *b, uint_t sz)
62fb2f18f8Sesaxe {
63fb2f18f8Sesaxe 	uint_t	nwords;
64fb2f18f8Sesaxe 	ulong_t	*bset_new, *bset_tmp;
65fb2f18f8Sesaxe 
66fb2f18f8Sesaxe 	nwords = BT_BITOUL(sz);
67fb2f18f8Sesaxe 	if (b->bs_words == nwords)
68fb2f18f8Sesaxe 		return;	/* already properly sized */
69fb2f18f8Sesaxe 
70fb2f18f8Sesaxe 	/*
716890d023SEric Saxe 	 * Allocate the new ulong_t array, and copy the old one, if there
726890d023SEric Saxe 	 * was an old one.
73fb2f18f8Sesaxe 	 */
74fb2f18f8Sesaxe 	if (nwords > 0) {
75fb2f18f8Sesaxe 		bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP);
766890d023SEric Saxe 		if (b->bs_words > 0)
77fb2f18f8Sesaxe 			bcopy(b->bs_set, bset_new,
78fb2f18f8Sesaxe 			    MIN(b->bs_words, nwords) * sizeof (ulong_t));
79fb2f18f8Sesaxe 	} else {
80fb2f18f8Sesaxe 		bset_new = NULL;
81fb2f18f8Sesaxe 	}
82fb2f18f8Sesaxe 
83fb2f18f8Sesaxe 	/* swap out the old ulong_t array for new one */
84fb2f18f8Sesaxe 	bset_tmp = b->bs_set;
85fb2f18f8Sesaxe 	b->bs_set = bset_new;
86fb2f18f8Sesaxe 
87fb2f18f8Sesaxe 	/* free up the old array */
886890d023SEric Saxe 	if (b->bs_words > 0)
89fb2f18f8Sesaxe 		kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t));
90fb2f18f8Sesaxe 	b->bs_words = nwords;
91fb2f18f8Sesaxe }
92fb2f18f8Sesaxe 
93fb2f18f8Sesaxe /*
94fb2f18f8Sesaxe  * Returns the current holding capacity of the bitset
95fb2f18f8Sesaxe  */
96fb2f18f8Sesaxe uint_t
97fb2f18f8Sesaxe bitset_capacity(bitset_t *b)
98fb2f18f8Sesaxe {
99fb2f18f8Sesaxe 	return (b->bs_words * BT_NBIPUL);
100fb2f18f8Sesaxe }
101fb2f18f8Sesaxe 
102fb2f18f8Sesaxe /*
103fb2f18f8Sesaxe  * Add and delete bits in the bitset.
104fb2f18f8Sesaxe  *
105fb2f18f8Sesaxe  * Adding a bit that is already set, and clearing a bit that's already clear
106fb2f18f8Sesaxe  * is legal.
107fb2f18f8Sesaxe  *
108fb2f18f8Sesaxe  * Adding or deleting an element that falls outside the bitset's current
109fb2f18f8Sesaxe  * holding capacity is illegal.
110fb2f18f8Sesaxe  */
1116890d023SEric Saxe 
1126890d023SEric Saxe /*
1136890d023SEric Saxe  * Set a bit
1146890d023SEric Saxe  */
115fb2f18f8Sesaxe void
116fb2f18f8Sesaxe bitset_add(bitset_t *b, uint_t elt)
117fb2f18f8Sesaxe {
118fb2f18f8Sesaxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
119fb2f18f8Sesaxe 
120fb2f18f8Sesaxe 	BT_SET(b->bs_set, elt);
121fb2f18f8Sesaxe }
122fb2f18f8Sesaxe 
1236890d023SEric Saxe /*
1246890d023SEric Saxe  * Set a bit in an atomically safe way
1256890d023SEric Saxe  */
1266890d023SEric Saxe void
1276890d023SEric Saxe bitset_atomic_add(bitset_t *b, uint_t elt)
1286890d023SEric Saxe {
1296890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
1306890d023SEric Saxe 
1316890d023SEric Saxe 	BT_ATOMIC_SET(b->bs_set, elt);
1326890d023SEric Saxe }
1336890d023SEric Saxe 
1346890d023SEric Saxe /*
1356890d023SEric Saxe  * Atomically test that a given bit isn't set, and set it.
1366890d023SEric Saxe  * Returns -1 if the bit was already set.
1376890d023SEric Saxe  */
1386890d023SEric Saxe int
1396890d023SEric Saxe bitset_atomic_test_and_add(bitset_t *b, uint_t elt)
1406890d023SEric Saxe {
1416890d023SEric Saxe 	int r;
1426890d023SEric Saxe 
1436890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
1446890d023SEric Saxe 	BT_ATOMIC_SET_EXCL(b->bs_set, elt, r);
1456890d023SEric Saxe 
1466890d023SEric Saxe 	return (r);
1476890d023SEric Saxe }
1486890d023SEric Saxe 
1496890d023SEric Saxe /*
1506890d023SEric Saxe  * Clear a bit
1516890d023SEric Saxe  */
152fb2f18f8Sesaxe void
153fb2f18f8Sesaxe bitset_del(bitset_t *b, uint_t elt)
154fb2f18f8Sesaxe {
155fb2f18f8Sesaxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
156fb2f18f8Sesaxe 
157fb2f18f8Sesaxe 	BT_CLEAR(b->bs_set, elt);
158fb2f18f8Sesaxe }
159fb2f18f8Sesaxe 
160fb2f18f8Sesaxe /*
1616890d023SEric Saxe  * Clear a bit in an atomically safe way
1626890d023SEric Saxe  */
1636890d023SEric Saxe void
1646890d023SEric Saxe bitset_atomic_del(bitset_t *b, uint_t elt)
1656890d023SEric Saxe {
1666890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
1676890d023SEric Saxe 
1686890d023SEric Saxe 	BT_ATOMIC_CLEAR(b->bs_set, elt);
1696890d023SEric Saxe }
1706890d023SEric Saxe 
1716890d023SEric Saxe /*
1726890d023SEric Saxe  * Atomically test that a bit is set, and clear it.
1736890d023SEric Saxe  * Returns -1 if the bit was already clear.
1746890d023SEric Saxe  */
1756890d023SEric Saxe int
1766890d023SEric Saxe bitset_atomic_test_and_del(bitset_t *b, uint_t elt)
1776890d023SEric Saxe {
1786890d023SEric Saxe 	int r;
1796890d023SEric Saxe 
1806890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
1816890d023SEric Saxe 	BT_ATOMIC_CLEAR_EXCL(b->bs_set, elt, r);
1826890d023SEric Saxe 
1836890d023SEric Saxe 	return (r);
1846890d023SEric Saxe }
1856890d023SEric Saxe 
1866890d023SEric Saxe /*
187fb2f18f8Sesaxe  * Return non-zero if the bit is present in the set
188fb2f18f8Sesaxe  */
189fb2f18f8Sesaxe int
190fb2f18f8Sesaxe bitset_in_set(bitset_t *b, uint_t elt)
191fb2f18f8Sesaxe {
1920f424180Sesaxe 	if (elt >= b->bs_words * BT_NBIPUL)
1930f424180Sesaxe 		return (0);
194fb2f18f8Sesaxe 
195fb2f18f8Sesaxe 	return (BT_TEST(b->bs_set, elt));
196fb2f18f8Sesaxe }
197fb2f18f8Sesaxe 
198fb2f18f8Sesaxe /*
199fb2f18f8Sesaxe  * Return non-zero if the bitset is empty
200fb2f18f8Sesaxe  */
201fb2f18f8Sesaxe int
202fb2f18f8Sesaxe bitset_is_null(bitset_t *b)
203fb2f18f8Sesaxe {
204fb2f18f8Sesaxe 	int	i;
205fb2f18f8Sesaxe 
206fb2f18f8Sesaxe 	for (i = 0; i < b->bs_words; i++)
207fb2f18f8Sesaxe 		if (b->bs_set[i] != 0)
208fb2f18f8Sesaxe 			return (0);
209fb2f18f8Sesaxe 	return (1);
210fb2f18f8Sesaxe }
211fb2f18f8Sesaxe 
212fb2f18f8Sesaxe /*
2136890d023SEric Saxe  * Perform a non-victimizing search for a set bit in a word
2146890d023SEric Saxe  * A "seed" is passed to pseudo-randomize the search.
2156890d023SEric Saxe  * Return -1 if no set bit was found
2166890d023SEric Saxe  */
2176890d023SEric Saxe static uint_t
2186890d023SEric Saxe bitset_find_in_word(ulong_t w, uint_t seed)
2196890d023SEric Saxe {
2206890d023SEric Saxe 	uint_t rotate_bit, elt = (uint_t)-1;
2216890d023SEric Saxe 	ulong_t rotated_word;
2226890d023SEric Saxe 
2236890d023SEric Saxe 	if (w == (ulong_t)0)
2246890d023SEric Saxe 		return (elt);
2256890d023SEric Saxe 
2266890d023SEric Saxe 	rotate_bit = seed % BT_NBIPUL;
2276890d023SEric Saxe 	rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit));
2286890d023SEric Saxe 	elt = (uint_t)(lowbit(rotated_word) - 1);
2296890d023SEric Saxe 	if (elt != (uint_t)-1)
2306890d023SEric Saxe 		elt = ((elt + rotate_bit) % BT_NBIPUL);
2316890d023SEric Saxe 
2326890d023SEric Saxe 	return (elt);
2336890d023SEric Saxe }
2346890d023SEric Saxe 
2356890d023SEric Saxe /*
2366890d023SEric Saxe  * Select a bit that is set in the bitset in a non-victimizing fashion
2376890d023SEric Saxe  * (e.g. doesn't bias the low/high order bits/words).
2386890d023SEric Saxe  * Return -1 if no set bit was found
239fb2f18f8Sesaxe  */
240fb2f18f8Sesaxe uint_t
241fb2f18f8Sesaxe bitset_find(bitset_t *b)
242fb2f18f8Sesaxe {
2436890d023SEric Saxe 	uint_t start, i;
244fb2f18f8Sesaxe 	uint_t elt = (uint_t)-1;
2456890d023SEric Saxe 	uint_t seed;
246fb2f18f8Sesaxe 
2476890d023SEric Saxe 	seed = CPU_PSEUDO_RANDOM();
2486890d023SEric Saxe 	start = seed % b->bs_words;
2496890d023SEric Saxe 
2506890d023SEric Saxe 	i = start;
2516890d023SEric Saxe 	do {
2526890d023SEric Saxe 		elt = bitset_find_in_word(b->bs_set[i], seed);
253fb2f18f8Sesaxe 		if (elt != (uint_t)-1) {
254fb2f18f8Sesaxe 			elt += i * BT_NBIPUL;
255fb2f18f8Sesaxe 			break;
256fb2f18f8Sesaxe 		}
2576890d023SEric Saxe 		if (++i == b->bs_words)
2586890d023SEric Saxe 			i = 0;
2596890d023SEric Saxe 	} while (i != start);
2606890d023SEric Saxe 
261fb2f18f8Sesaxe 	return (elt);
262fb2f18f8Sesaxe }
263*4c06356bSdh142964 
264*4c06356bSdh142964 /*
265*4c06356bSdh142964  * AND, OR, and XOR bitset computations
266*4c06356bSdh142964  * Returns 1 if resulting bitset has any set bits
267*4c06356bSdh142964  */
268*4c06356bSdh142964 int
269*4c06356bSdh142964 bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
270*4c06356bSdh142964 {
271*4c06356bSdh142964 	int i, anyset;
272*4c06356bSdh142964 
273*4c06356bSdh142964 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
274*4c06356bSdh142964 		if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0)
275*4c06356bSdh142964 			anyset = 1;
276*4c06356bSdh142964 	}
277*4c06356bSdh142964 	return (anyset);
278*4c06356bSdh142964 }
279*4c06356bSdh142964 
280*4c06356bSdh142964 int
281*4c06356bSdh142964 bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
282*4c06356bSdh142964 {
283*4c06356bSdh142964 	int i, anyset;
284*4c06356bSdh142964 
285*4c06356bSdh142964 	for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
286*4c06356bSdh142964 		if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0)
287*4c06356bSdh142964 			anyset = 1;
288*4c06356bSdh142964 	}
289*4c06356bSdh142964 	return (anyset);
290*4c06356bSdh142964 }
291*4c06356bSdh142964 
292*4c06356bSdh142964 int
293*4c06356bSdh142964 bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
294*4c06356bSdh142964 {
295*4c06356bSdh142964 	int i;
296*4c06356bSdh142964 	int anyset = 0;
297*4c06356bSdh142964 
298*4c06356bSdh142964 	for (i = 0; i < bs1->bs_words; i++) {
299*4c06356bSdh142964 		if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0)
300*4c06356bSdh142964 			anyset = 1;
301*4c06356bSdh142964 	}
302*4c06356bSdh142964 	return (anyset);
303*4c06356bSdh142964 }
304*4c06356bSdh142964 
305*4c06356bSdh142964 /*
306*4c06356bSdh142964  * return 1 if bitmaps are identical
307*4c06356bSdh142964  */
308*4c06356bSdh142964 int
309*4c06356bSdh142964 bitset_match(bitset_t *bs1, bitset_t *bs2)
310*4c06356bSdh142964 {
311*4c06356bSdh142964 	int i;
312*4c06356bSdh142964 
313*4c06356bSdh142964 	if (bs1->bs_words != bs2->bs_words)
314*4c06356bSdh142964 		return (0);
315*4c06356bSdh142964 
316*4c06356bSdh142964 	for (i = 0; i < bs1->bs_words; i++)
317*4c06356bSdh142964 		if (bs1->bs_set[i] != bs2->bs_set[i])
318*4c06356bSdh142964 			return (0);
319*4c06356bSdh142964 	return (1);
320*4c06356bSdh142964 }
321*4c06356bSdh142964 
322*4c06356bSdh142964 /*
323*4c06356bSdh142964  * Zero a bitset_t
324*4c06356bSdh142964  */
325*4c06356bSdh142964 void
326*4c06356bSdh142964 bitset_zero(bitset_t *b)
327*4c06356bSdh142964 {
328*4c06356bSdh142964 	bzero(b->bs_set, sizeof (ulong_t) * b->bs_words);
329*4c06356bSdh142964 }
330*4c06356bSdh142964 
331*4c06356bSdh142964 
332*4c06356bSdh142964 /*
333*4c06356bSdh142964  * Copy a bitset_t
334*4c06356bSdh142964  */
335*4c06356bSdh142964 void
336*4c06356bSdh142964 bitset_copy(bitset_t *src, bitset_t *dest)
337*4c06356bSdh142964 {
338*4c06356bSdh142964 	bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words);
339*4c06356bSdh142964 }
340