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]
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <sys/bitset.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.
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.
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.
58 bitset_fini(bitset_t
*b
)
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.
71 bitset_resize(bitset_t
*b
, uint_t els
)
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
85 bset_new
= kmem_zalloc(nwords
* sizeof (ulong_t
), KM_SLEEP
);
87 bcopy(b
->bs_set
, bset_new
,
88 MIN(b
->bs_words
, nwords
) * sizeof (ulong_t
));
93 /* swap out the old ulong_t array for new one */
97 /* free up the old array */
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.
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
119 * Adding or deleting an element that falls outside the bitset's current
120 * holding capacity is illegal.
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.
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
);
153 ASSERT(b
->bs_words
* BT_NBIPUL
> pos
);
154 BT_ATOMIC_SET_EXCL(b
->bs_set
, pos
, ret
);
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.
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
);
193 ASSERT(b
->bs_words
* BT_NBIPUL
> pos
);
194 BT_ATOMIC_CLEAR_EXCL(b
->bs_set
, pos
, 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
)
210 return (BT_TEST(b
->bs_set
, pos
));
214 * Return non-zero if the bitset is empty.
217 bitset_is_null(bitset_t
*b
)
221 for (i
= 0; i
< b
->bs_words
; i
++)
222 if (b
->bs_set
[i
] != 0)
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.
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
;
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
);
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
256 bitset_find(bitset_t
*b
)
259 uint_t elt
= (uint_t
)-1;
262 seed
= CPU_PSEUDO_RANDOM();
264 ASSERT(b
->bs_words
> 0);
265 start
= seed
% b
->bs_words
;
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
)
276 } while (i
!= start
);
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
)
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)
301 bitset_or(bitset_t
*bs1
, bitset_t
*bs2
, bitset_t
*res
)
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)
316 bitset_xor(bitset_t
*bs1
, bitset_t
*bs2
, bitset_t
*res
)
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)
331 * Return 1 if bitmaps are identical.
334 bitset_match(bitset_t
*bs1
, bitset_t
*bs2
)
338 if (bs1
->bs_words
!= bs2
->bs_words
)
341 for (i
= 0; i
< bs1
->bs_words
; i
++)
342 if (bs1
->bs_set
[i
] != bs2
->bs_set
[i
])
351 bitset_zero(bitset_t
*b
)
353 bzero(b
->bs_set
, sizeof (ulong_t
) * b
->bs_words
);
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
);