xref: /titanic_53/usr/src/uts/common/os/bitset.c (revision 6890d023cce317bfcb74d7e43a813d060ebd2e47)
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*6890d023SEric Saxe  * Copyright 2008 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>
29*6890d023SEric 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 	/*
71*6890d023SEric Saxe 	 * Allocate the new ulong_t array, and copy the old one, if there
72*6890d023SEric Saxe 	 * was an old one.
73fb2f18f8Sesaxe 	 */
74fb2f18f8Sesaxe 	if (nwords > 0) {
75fb2f18f8Sesaxe 		bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP);
76*6890d023SEric 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 */
88*6890d023SEric 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  */
111*6890d023SEric Saxe 
112*6890d023SEric Saxe /*
113*6890d023SEric Saxe  * Set a bit
114*6890d023SEric 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 
123*6890d023SEric Saxe /*
124*6890d023SEric Saxe  * Set a bit in an atomically safe way
125*6890d023SEric Saxe  */
126*6890d023SEric Saxe void
127*6890d023SEric Saxe bitset_atomic_add(bitset_t *b, uint_t elt)
128*6890d023SEric Saxe {
129*6890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
130*6890d023SEric Saxe 
131*6890d023SEric Saxe 	BT_ATOMIC_SET(b->bs_set, elt);
132*6890d023SEric Saxe }
133*6890d023SEric Saxe 
134*6890d023SEric Saxe /*
135*6890d023SEric Saxe  * Atomically test that a given bit isn't set, and set it.
136*6890d023SEric Saxe  * Returns -1 if the bit was already set.
137*6890d023SEric Saxe  */
138*6890d023SEric Saxe int
139*6890d023SEric Saxe bitset_atomic_test_and_add(bitset_t *b, uint_t elt)
140*6890d023SEric Saxe {
141*6890d023SEric Saxe 	int r;
142*6890d023SEric Saxe 
143*6890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
144*6890d023SEric Saxe 	BT_ATOMIC_SET_EXCL(b->bs_set, elt, r);
145*6890d023SEric Saxe 
146*6890d023SEric Saxe 	return (r);
147*6890d023SEric Saxe }
148*6890d023SEric Saxe 
149*6890d023SEric Saxe /*
150*6890d023SEric Saxe  * Clear a bit
151*6890d023SEric 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 /*
161*6890d023SEric Saxe  * Clear a bit in an atomically safe way
162*6890d023SEric Saxe  */
163*6890d023SEric Saxe void
164*6890d023SEric Saxe bitset_atomic_del(bitset_t *b, uint_t elt)
165*6890d023SEric Saxe {
166*6890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
167*6890d023SEric Saxe 
168*6890d023SEric Saxe 	BT_ATOMIC_CLEAR(b->bs_set, elt);
169*6890d023SEric Saxe }
170*6890d023SEric Saxe 
171*6890d023SEric Saxe /*
172*6890d023SEric Saxe  * Atomically test that a bit is set, and clear it.
173*6890d023SEric Saxe  * Returns -1 if the bit was already clear.
174*6890d023SEric Saxe  */
175*6890d023SEric Saxe int
176*6890d023SEric Saxe bitset_atomic_test_and_del(bitset_t *b, uint_t elt)
177*6890d023SEric Saxe {
178*6890d023SEric Saxe 	int r;
179*6890d023SEric Saxe 
180*6890d023SEric Saxe 	ASSERT(b->bs_words * BT_NBIPUL > elt);
181*6890d023SEric Saxe 	BT_ATOMIC_CLEAR_EXCL(b->bs_set, elt, r);
182*6890d023SEric Saxe 
183*6890d023SEric Saxe 	return (r);
184*6890d023SEric Saxe }
185*6890d023SEric Saxe 
186*6890d023SEric 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 /*
213*6890d023SEric Saxe  * Perform a non-victimizing search for a set bit in a word
214*6890d023SEric Saxe  * A "seed" is passed to pseudo-randomize the search.
215*6890d023SEric Saxe  * Return -1 if no set bit was found
216*6890d023SEric Saxe  */
217*6890d023SEric Saxe static uint_t
218*6890d023SEric Saxe bitset_find_in_word(ulong_t w, uint_t seed)
219*6890d023SEric Saxe {
220*6890d023SEric Saxe 	uint_t rotate_bit, elt = (uint_t)-1;
221*6890d023SEric Saxe 	ulong_t rotated_word;
222*6890d023SEric Saxe 
223*6890d023SEric Saxe 	if (w == (ulong_t)0)
224*6890d023SEric Saxe 		return (elt);
225*6890d023SEric Saxe 
226*6890d023SEric Saxe 	rotate_bit = seed % BT_NBIPUL;
227*6890d023SEric Saxe 	rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit));
228*6890d023SEric Saxe 	elt = (uint_t)(lowbit(rotated_word) - 1);
229*6890d023SEric Saxe 	if (elt != (uint_t)-1)
230*6890d023SEric Saxe 		elt = ((elt + rotate_bit) % BT_NBIPUL);
231*6890d023SEric Saxe 
232*6890d023SEric Saxe 	return (elt);
233*6890d023SEric Saxe }
234*6890d023SEric Saxe 
235*6890d023SEric Saxe /*
236*6890d023SEric Saxe  * Select a bit that is set in the bitset in a non-victimizing fashion
237*6890d023SEric Saxe  * (e.g. doesn't bias the low/high order bits/words).
238*6890d023SEric Saxe  * Return -1 if no set bit was found
239fb2f18f8Sesaxe  */
240fb2f18f8Sesaxe uint_t
241fb2f18f8Sesaxe bitset_find(bitset_t *b)
242fb2f18f8Sesaxe {
243*6890d023SEric Saxe 	uint_t start, i;
244fb2f18f8Sesaxe 	uint_t elt = (uint_t)-1;
245*6890d023SEric Saxe 	uint_t seed;
246fb2f18f8Sesaxe 
247*6890d023SEric Saxe 	seed = CPU_PSEUDO_RANDOM();
248*6890d023SEric Saxe 	start = seed % b->bs_words;
249*6890d023SEric Saxe 
250*6890d023SEric Saxe 	i = start;
251*6890d023SEric Saxe 	do {
252*6890d023SEric 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 		}
257*6890d023SEric Saxe 		if (++i == b->bs_words)
258*6890d023SEric Saxe 			i = 0;
259*6890d023SEric Saxe 	} while (i != start);
260*6890d023SEric Saxe 
261fb2f18f8Sesaxe 	return (elt);
262fb2f18f8Sesaxe }
263