source: mainline/common/adt/bitmap.c@ 0437dd5

Last change on this file since 0437dd5 was 64c8132, checked in by Miroslav Cimerman <mc@…>, 6 months ago

Allow bitmap to be used in userspace

  • Property mode set to 100644
File size: 8.8 KB
RevLine 
[97a7eff]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Jermar
[97a7eff]3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
[64c8132]29/** @addtogroup libc
[b45c443]30 * @{
31 */
[9179d0a]32/**
[7257021e]33 * @file
[da88a079]34 * @brief Implementation of bitmap ADT.
[9179d0a]35 *
36 * This file implements bitmap ADT and provides functions for
[7de18418]37 * setting and clearing ranges of bits and for finding ranges
38 * of unset bits.
[9179d0a]39 */
40
[97a7eff]41#include <adt/bitmap.h>
42#include <align.h>
[63e27ef]43#include <assert.h>
[4fd61ba]44#include <macros.h>
[97a7eff]45
[7de18418]46#define ALL_ONES 0xff
47#define ALL_ZEROES 0x00
[97a7eff]48
[64f3d3b]49/** Unchecked version of bitmap_get()
50 *
51 * This version of bitmap_get() does not do any boundary checks.
52 *
53 * @param bitmap Bitmap to access.
54 * @param element Element to access.
55 *
56 * @return Bit value of the element in the bitmap.
57 *
58 */
59static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
60{
[c5396c1]61 size_t byte = element / BITMAP_ELEMENT;
62 uint8_t mask = 1 << (element & BITMAP_REMAINER);
[a35b458]63
[c5396c1]64 return !!((bitmap->bits)[byte] & mask);
[64f3d3b]65}
66
[7de18418]67/** Get bitmap size
[97a7eff]68 *
[7de18418]69 * Return the size (in bytes) required for the bitmap.
70 *
71 * @param elements Number bits stored in bitmap.
72 *
73 * @return Size (in bytes) required for the bitmap.
[97a7eff]74 *
75 */
[c5396c1]76size_t bitmap_size(size_t elements)
[97a7eff]77{
[c5396c1]78 size_t size = elements / BITMAP_ELEMENT;
[a35b458]79
[c5396c1]80 if ((elements % BITMAP_ELEMENT) != 0)
81 size++;
[a35b458]82
[c5396c1]83 return size;
[97a7eff]84}
85
[7de18418]86/** Initialize bitmap.
87 *
88 * No portion of the bitmap is set or cleared by this function.
89 *
90 * @param bitmap Bitmap structure.
91 * @param elements Number of bits stored in bitmap.
92 * @param data Address of the memory used to hold the map.
93 * The optional 2nd level bitmap follows the 1st
94 * level bitmap.
[97a7eff]95 *
96 */
[c5396c1]97void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
[97a7eff]98{
[7de18418]99 bitmap->elements = elements;
100 bitmap->bits = (uint8_t *) data;
[6e75f2d]101 bitmap->next_fit = 0;
[7de18418]102}
103
[c5396c1]104/** Set range of bits.
105 *
106 * @param bitmap Bitmap structure.
107 * @param start Starting bit.
108 * @param count Number of bits to set.
109 *
110 */
111void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t count)
[7de18418]112{
[63e27ef]113 assert(start + count <= bitmap->elements);
[a35b458]114
[7de18418]115 if (count == 0)
116 return;
[a35b458]117
[6e75f2d]118 size_t start_byte = start / BITMAP_ELEMENT;
[7de18418]119 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
[a35b458]120
[7de18418]121 /* Leading unaligned bits */
122 size_t lub = min(aligned_start - start, count);
[a35b458]123
[7de18418]124 /* Aligned middle bits */
125 size_t amb = (count > lub) ? (count - lub) : 0;
[a35b458]126
[7de18418]127 /* Trailing aligned bits */
128 size_t tab = amb % BITMAP_ELEMENT;
[a35b458]129
[7de18418]130 if (start + count < aligned_start) {
[10285ad]131 /* Set bits in the middle of byte. */
[6e75f2d]132 bitmap->bits[start_byte] |=
[7de18418]133 ((1 << lub) - 1) << (start & BITMAP_REMAINER);
[10285ad]134 return;
135 }
[a35b458]136
[97a7eff]137 if (lub) {
[da88a079]138 /* Make sure to set any leading unaligned bits. */
[6e75f2d]139 bitmap->bits[start_byte] |=
[7de18418]140 ~((1 << (BITMAP_ELEMENT - lub)) - 1);
[97a7eff]141 }
[a35b458]142
[7de18418]143 size_t i;
[a35b458]144
[7de18418]145 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]146 /* The middle bits can be set byte by byte. */
[c5396c1]147 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
148 ALL_ONES;
[97a7eff]149 }
[a35b458]150
[4fd61ba]151 if (tab) {
[da88a079]152 /* Make sure to set any trailing aligned bits. */
[c5396c1]153 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
154 (1 << tab) - 1;
[97a7eff]155 }
156}
157
[c5396c1]158/** Clear range of bits.
[7de18418]159 *
160 * @param bitmap Bitmap structure.
161 * @param start Starting bit.
[c5396c1]162 * @param count Number of bits to clear.
[97a7eff]163 *
164 */
[c5396c1]165void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t count)
[97a7eff]166{
[63e27ef]167 assert(start + count <= bitmap->elements);
[a35b458]168
[7de18418]169 if (count == 0)
[4fe18151]170 return;
[a35b458]171
[6e75f2d]172 size_t start_byte = start / BITMAP_ELEMENT;
[7de18418]173 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
[a35b458]174
[7de18418]175 /* Leading unaligned bits */
176 size_t lub = min(aligned_start - start, count);
[a35b458]177
[7de18418]178 /* Aligned middle bits */
179 size_t amb = (count > lub) ? (count - lub) : 0;
[a35b458]180
[7de18418]181 /* Trailing aligned bits */
182 size_t tab = amb % BITMAP_ELEMENT;
[a35b458]183
[7de18418]184 if (start + count < aligned_start) {
[10285ad]185 /* Set bits in the middle of byte */
[6e75f2d]186 bitmap->bits[start_byte] &=
[7de18418]187 ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
[10285ad]188 return;
189 }
[a35b458]190
[97a7eff]191 if (lub) {
[da88a079]192 /* Make sure to clear any leading unaligned bits. */
[6e75f2d]193 bitmap->bits[start_byte] &=
[7de18418]194 (1 << (BITMAP_ELEMENT - lub)) - 1;
[97a7eff]195 }
[a35b458]196
[7de18418]197 size_t i;
[a35b458]198
[7de18418]199 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]200 /* The middle bits can be cleared byte by byte. */
[c5396c1]201 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
202 ALL_ZEROES;
[97a7eff]203 }
[a35b458]204
[4fd61ba]205 if (tab) {
[da88a079]206 /* Make sure to clear any trailing aligned bits. */
[c5396c1]207 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] &=
208 ~((1 << tab) - 1);
[7de18418]209 }
[a35b458]210
[6e75f2d]211 bitmap->next_fit = start_byte;
[97a7eff]212}
213
214/** Copy portion of one bitmap into another bitmap.
215 *
[7de18418]216 * @param dst Destination bitmap.
217 * @param src Source bitmap.
218 * @param count Number of bits to copy.
219 *
[97a7eff]220 */
[7de18418]221void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t count)
[97a7eff]222{
[63e27ef]223 assert(count <= dst->elements);
224 assert(count <= src->elements);
[a35b458]225
[7de18418]226 size_t i;
[a35b458]227
[7de18418]228 for (i = 0; i < count / BITMAP_ELEMENT; i++)
229 dst->bits[i] = src->bits[i];
[a35b458]230
[7de18418]231 if (count % BITMAP_ELEMENT) {
232 bitmap_clear_range(dst, i * BITMAP_ELEMENT,
233 count % BITMAP_ELEMENT);
234 dst->bits[i] |= src->bits[i] &
235 ((1 << (count % BITMAP_ELEMENT)) - 1);
[97a7eff]236 }
237}
[b45c443]238
[86733f3]239static int constraint_satisfy(size_t index, size_t base, size_t constraint)
240{
241 return (((base + index) & constraint) == 0);
242}
243
244/** Find a continuous zero bit range
245 *
246 * Find a continuous zero bit range in the bitmap. The address
247 * computed as the sum of the index of the first zero bit and
248 * the base argument needs to be compliant with the constraint
249 * (those bits that are set in the constraint cannot be set in
250 * the address).
251 *
252 * If the index argument is non-NULL, the continuous zero range
253 * is set and the index of the first bit is stored to index.
254 * Otherwise the bitmap stays untouched.
255 *
256 * @param bitmap Bitmap structure.
257 * @param count Number of continuous zero bits to find.
258 * @param base Address of the first bit in the bitmap.
[f72906c]259 * @param prefered Prefered address to start searching from.
[86733f3]260 * @param constraint Constraint for the address of the first zero bit.
261 * @param index Place to store the index of the first zero
262 * bit. Can be NULL (in which case the bitmap
263 * is not modified).
264 *
265 * @return Non-zero if a continuous range of zero bits satisfying
266 * the constraint has been found.
267 * @return Zero otherwise.
268 *
269 */
[89ea2dc]270bool bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
[f72906c]271 size_t prefered, size_t constraint, size_t *index)
[86733f3]272{
[d5f774f6]273 if (count == 0)
[86733f3]274 return false;
[a35b458]275
[6e75f2d]276 size_t size = bitmap_size(bitmap->elements);
[f72906c]277 size_t next_fit = bitmap->next_fit;
[a35b458]278
[f72906c]279 /*
280 * Adjust the next-fit value according to the address
281 * the caller prefers to start the search at.
282 */
283 if ((prefered > base) && (prefered < base + bitmap->elements)) {
284 size_t prefered_fit = (prefered - base) / BITMAP_ELEMENT;
[a35b458]285
[f72906c]286 if (prefered_fit > next_fit)
287 next_fit = prefered_fit;
288 }
[a35b458]289
[6e75f2d]290 for (size_t pos = 0; pos < size; pos++) {
[f72906c]291 size_t byte = (next_fit + pos) % size;
[a35b458]292
[64f3d3b]293 /* Skip if the current byte has all bits set */
294 if (bitmap->bits[byte] == ALL_ONES)
[86733f3]295 continue;
[a35b458]296
[64f3d3b]297 size_t byte_bit = byte * BITMAP_ELEMENT;
[a35b458]298
[64f3d3b]299 for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
300 size_t i = byte_bit + bit;
[a35b458]301
[64f3d3b]302 if (i >= bitmap->elements)
303 break;
[a35b458]304
[64f3d3b]305 if (!constraint_satisfy(i, base, constraint))
306 continue;
[a35b458]307
[64f3d3b]308 if (!bitmap_get_fast(bitmap, i)) {
[6e75f2d]309 size_t continuous = 1;
[a35b458]310
[64f3d3b]311 for (size_t j = 1; j < count; j++) {
[6e75f2d]312 if ((i + j < bitmap->elements) &&
313 (!bitmap_get_fast(bitmap, i + j)))
314 continuous++;
315 else
[64f3d3b]316 break;
[86733f3]317 }
[a35b458]318
[6e75f2d]319 if (continuous == count) {
[64f3d3b]320 if (index != NULL) {
321 bitmap_set_range(bitmap, i, count);
[6e75f2d]322 bitmap->next_fit = i / BITMAP_ELEMENT;
[64f3d3b]323 *index = i;
324 }
[a35b458]325
[64f3d3b]326 return true;
[6e75f2d]327 } else
328 i += continuous;
[86733f3]329 }
330 }
331 }
[a35b458]332
[86733f3]333 return false;
334}
335
[cc73a8a1]336/** @}
[b45c443]337 */
Note: See TracBrowser for help on using the repository browser.