build: silence lex(1) statistics output
[unleashed.git] / kernel / os / bitset.c
blob382d69d03f3eb6accf885a54e7a63f3c49cc0d5a
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/bitset.h>
26 #include <sys/kmem.h>
27 #include <sys/systm.h>
28 #include <sys/cpuvar.h>
29 #include <sys/cmn_err.h>
30 #include <sys/sysmacros.h>
33 * Initialize a bitset_t.
34 * After bitset_init(), the bitset will be zero sized.
36 void
37 bitset_init(bitset_t *b)
39 bzero(b, sizeof (bitset_t));
43 * Initialize a bitset_t using a fanout. The fanout factor is platform
44 * specific and passed in as a power of two.
46 void
47 bitset_init_fanout(bitset_t *b, uint_t fanout)
49 bzero(b, sizeof (bitset_t));
50 b->bs_fanout = fanout;
54 * Uninitialize a bitset_t.
55 * This will free the bitset's data, leaving it zero sized.
57 void
58 bitset_fini(bitset_t *b)
60 if (b->bs_words > 0)
61 kmem_free(b->bs_set, b->bs_words * sizeof (ulong_t));
65 * Resize a bitset to where it can hold els number of elements.
66 * This can either grow or shrink the bitset holding capacity.
67 * In the case of shrinkage, elements that reside outside the new
68 * holding capacity of the bitset are lost.
70 void
71 bitset_resize(bitset_t *b, uint_t els)
73 uint_t nwords;
74 ulong_t *bset_new, *bset_tmp;
76 nwords = BT_BITOUL(els << b->bs_fanout);
77 if (b->bs_words == nwords)
78 return; /* already properly sized */
81 * Allocate the new ulong_t array, and copy the old one, if there
82 * was an old one.
84 if (nwords > 0) {
85 bset_new = kmem_zalloc(nwords * sizeof (ulong_t), KM_SLEEP);
86 if (b->bs_words > 0)
87 bcopy(b->bs_set, bset_new,
88 MIN(b->bs_words, nwords) * sizeof (ulong_t));
89 } else {
90 bset_new = NULL;
93 /* swap out the old ulong_t array for new one */
94 bset_tmp = b->bs_set;
95 b->bs_set = bset_new;
97 /* free up the old array */
98 if (b->bs_words > 0)
99 kmem_free(bset_tmp, b->bs_words * sizeof (ulong_t));
101 b->bs_words = nwords;
105 * Returns the current holding capacity of the bitset.
107 uint_t
108 bitset_capacity(bitset_t *b)
110 return (b->bs_words * BT_NBIPUL);
114 * Add (set) and delete (clear) bits in the bitset.
116 * Adding a bit that is already set, or removing a bit that's already clear
117 * is legal.
119 * Adding or deleting an element that falls outside the bitset's current
120 * holding capacity is illegal.
122 void
123 bitset_add(bitset_t *b, uint_t elt)
125 uint_t pos = (elt << b->bs_fanout);
127 ASSERT(b->bs_words * BT_NBIPUL > pos);
128 BT_SET(b->bs_set, pos);
132 * Set a bit in an atomically safe way.
134 void
135 bitset_atomic_add(bitset_t *b, uint_t elt)
137 uint_t pos = (elt << b->bs_fanout);
139 ASSERT(b->bs_words * BT_NBIPUL > pos);
140 BT_ATOMIC_SET(b->bs_set, pos);
144 * Atomically test that a given bit isn't set, and set it.
145 * Returns -1 if the bit was already set.
148 bitset_atomic_test_and_add(bitset_t *b, uint_t elt)
150 uint_t pos = (elt << b->bs_fanout);
151 int ret;
153 ASSERT(b->bs_words * BT_NBIPUL > pos);
154 BT_ATOMIC_SET_EXCL(b->bs_set, pos, ret);
156 return (ret);
160 * Clear a bit.
162 void
163 bitset_del(bitset_t *b, uint_t elt)
165 uint_t pos = (elt << b->bs_fanout);
167 ASSERT(b->bs_words * BT_NBIPUL > pos);
168 BT_CLEAR(b->bs_set, pos);
172 * Clear a bit in an atomically safe way.
174 void
175 bitset_atomic_del(bitset_t *b, uint_t elt)
177 uint_t pos = (elt << b->bs_fanout);
179 ASSERT(b->bs_words * BT_NBIPUL > pos);
180 BT_ATOMIC_CLEAR(b->bs_set, pos);
184 * Atomically test that a bit is set, and clear it.
185 * Returns -1 if the bit was already clear.
188 bitset_atomic_test_and_del(bitset_t *b, uint_t elt)
190 uint_t pos = (elt << b->bs_fanout);
191 int ret;
193 ASSERT(b->bs_words * BT_NBIPUL > pos);
194 BT_ATOMIC_CLEAR_EXCL(b->bs_set, pos, ret);
196 return (ret);
200 * Return non-zero if the bit is present in the set.
203 bitset_in_set(bitset_t *b, uint_t elt)
205 uint_t pos = (elt << b->bs_fanout);
207 if (pos >= b->bs_words * BT_NBIPUL)
208 return (0);
210 return (BT_TEST(b->bs_set, pos));
214 * Return non-zero if the bitset is empty.
217 bitset_is_null(bitset_t *b)
219 int i;
221 for (i = 0; i < b->bs_words; i++)
222 if (b->bs_set[i] != 0)
223 return (0);
224 return (1);
228 * Perform a non-victimizing search for a set bit in a word.
229 * A "seed" is passed to pseudo-randomize the search.
230 * Return -1 if no set bit was found.
232 static uint_t
233 bitset_find_in_word(ulong_t w, uint_t seed)
235 uint_t rotate_bit, elt = (uint_t)-1;
236 ulong_t rotated_word;
238 if (w == (ulong_t)0)
239 return (elt);
241 rotate_bit = seed % BT_NBIPUL;
242 rotated_word = (w >> rotate_bit) | (w << (BT_NBIPUL - rotate_bit));
243 elt = (uint_t)(lowbit(rotated_word) - 1);
244 if (elt != (uint_t)-1)
245 elt = ((elt + rotate_bit) % BT_NBIPUL);
247 return (elt);
251 * Select a bit that is set in the bitset in a non-victimizing fashion
252 * (e.g. doesn't bias the low/high order bits/words).
253 * Return -1 if no set bit was found
255 uint_t
256 bitset_find(bitset_t *b)
258 uint_t start, i;
259 uint_t elt = (uint_t)-1;
260 uint_t seed;
262 seed = CPU_PSEUDO_RANDOM();
264 ASSERT(b->bs_words > 0);
265 start = seed % b->bs_words;
267 i = start;
268 do {
269 elt = bitset_find_in_word(b->bs_set[i], seed);
270 if (elt != (uint_t)-1) {
271 elt += i * BT_NBIPUL;
272 return (elt >> b->bs_fanout);
274 if (++i == b->bs_words)
275 i = 0;
276 } while (i != start);
278 return (elt);
282 * AND, OR, and XOR bitset computations, returns 1 if resulting bitset has any
283 * set bits. Operands must have the same fanout, if any.
286 bitset_and(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
288 int i, anyset;
290 ASSERT(bs1->bs_fanout == bs2->bs_fanout);
291 ASSERT(bs1->bs_fanout == res->bs_fanout);
293 for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
294 if ((res->bs_set[i] = (bs1->bs_set[i] & bs2->bs_set[i])) != 0)
295 anyset = 1;
297 return (anyset);
301 bitset_or(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
303 int i, anyset;
305 ASSERT(bs1->bs_fanout == bs2->bs_fanout);
306 ASSERT(bs1->bs_fanout == res->bs_fanout);
308 for (anyset = 0, i = 0; i < bs1->bs_words; i++) {
309 if ((res->bs_set[i] = (bs1->bs_set[i] | bs2->bs_set[i])) != 0)
310 anyset = 1;
312 return (anyset);
316 bitset_xor(bitset_t *bs1, bitset_t *bs2, bitset_t *res)
318 int i, anyset = 0;
320 ASSERT(bs1->bs_fanout == bs2->bs_fanout);
321 ASSERT(bs1->bs_fanout == res->bs_fanout);
323 for (i = 0; i < bs1->bs_words; i++) {
324 if ((res->bs_set[i] = (bs1->bs_set[i] ^ bs2->bs_set[i])) != 0)
325 anyset = 1;
327 return (anyset);
331 * Return 1 if bitmaps are identical.
334 bitset_match(bitset_t *bs1, bitset_t *bs2)
336 int i;
338 if (bs1->bs_words != bs2->bs_words)
339 return (0);
341 for (i = 0; i < bs1->bs_words; i++)
342 if (bs1->bs_set[i] != bs2->bs_set[i])
343 return (0);
344 return (1);
348 * Zero a bitset_t.
350 void
351 bitset_zero(bitset_t *b)
353 bzero(b->bs_set, sizeof (ulong_t) * b->bs_words);
357 * Copy a bitset_t.
359 void
360 bitset_copy(bitset_t *src, bitset_t *dest)
362 ASSERT(src->bs_fanout == dest->bs_fanout);
363 bcopy(src->bs_set, dest->bs_set, sizeof (ulong_t) * src->bs_words);