source: mainline/kernel/generic/src/adt/bitmap.c@ 705ca2b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 705ca2b was 174156fd, checked in by Jakub Jermar <jakub@…>, 7 years ago

Disambiguate doxygroup generic*

  • 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
[174156fd]29/** @addtogroup kernel_generic_adt
[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>
[63e27ef]45#include <typedefs.h>
[97a7eff]46
[7de18418]47#define ALL_ONES 0xff
48#define ALL_ZEROES 0x00
[97a7eff]49
[64f3d3b]50/** Unchecked version of bitmap_get()
51 *
52 * This version of bitmap_get() does not do any boundary checks.
53 *
54 * @param bitmap Bitmap to access.
55 * @param element Element to access.
56 *
57 * @return Bit value of the element in the bitmap.
58 *
59 */
60static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
61{
[c5396c1]62 size_t byte = element / BITMAP_ELEMENT;
63 uint8_t mask = 1 << (element & BITMAP_REMAINER);
[a35b458]64
[c5396c1]65 return !!((bitmap->bits)[byte] & mask);
[64f3d3b]66}
67
[7de18418]68/** Get bitmap size
[97a7eff]69 *
[7de18418]70 * Return the size (in bytes) required for the bitmap.
71 *
72 * @param elements Number bits stored in bitmap.
73 *
74 * @return Size (in bytes) required for the bitmap.
[97a7eff]75 *
76 */
[c5396c1]77size_t bitmap_size(size_t elements)
[97a7eff]78{
[c5396c1]79 size_t size = elements / BITMAP_ELEMENT;
[a35b458]80
[c5396c1]81 if ((elements % BITMAP_ELEMENT) != 0)
82 size++;
[a35b458]83
[c5396c1]84 return size;
[97a7eff]85}
86
[7de18418]87/** Initialize bitmap.
88 *
89 * No portion of the bitmap is set or cleared by this function.
90 *
91 * @param bitmap Bitmap structure.
92 * @param elements Number of bits stored in bitmap.
93 * @param data Address of the memory used to hold the map.
94 * The optional 2nd level bitmap follows the 1st
95 * level bitmap.
[97a7eff]96 *
97 */
[c5396c1]98void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
[97a7eff]99{
[7de18418]100 bitmap->elements = elements;
101 bitmap->bits = (uint8_t *) data;
[6e75f2d]102 bitmap->next_fit = 0;
[7de18418]103}
104
[c5396c1]105/** Set range of bits.
106 *
107 * @param bitmap Bitmap structure.
108 * @param start Starting bit.
109 * @param count Number of bits to set.
110 *
111 */
112void bitmap_set_range(bitmap_t *bitmap, size_t start, size_t count)
[7de18418]113{
[63e27ef]114 assert(start + count <= bitmap->elements);
[a35b458]115
[7de18418]116 if (count == 0)
117 return;
[a35b458]118
[6e75f2d]119 size_t start_byte = start / BITMAP_ELEMENT;
[7de18418]120 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
[a35b458]121
[7de18418]122 /* Leading unaligned bits */
123 size_t lub = min(aligned_start - start, count);
[a35b458]124
[7de18418]125 /* Aligned middle bits */
126 size_t amb = (count > lub) ? (count - lub) : 0;
[a35b458]127
[7de18418]128 /* Trailing aligned bits */
129 size_t tab = amb % BITMAP_ELEMENT;
[a35b458]130
[7de18418]131 if (start + count < aligned_start) {
[10285ad]132 /* Set bits in the middle of byte. */
[6e75f2d]133 bitmap->bits[start_byte] |=
[7de18418]134 ((1 << lub) - 1) << (start & BITMAP_REMAINER);
[10285ad]135 return;
136 }
[a35b458]137
[97a7eff]138 if (lub) {
[da88a079]139 /* Make sure to set any leading unaligned bits. */
[6e75f2d]140 bitmap->bits[start_byte] |=
[7de18418]141 ~((1 << (BITMAP_ELEMENT - lub)) - 1);
[97a7eff]142 }
[a35b458]143
[7de18418]144 size_t i;
[a35b458]145
[7de18418]146 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]147 /* The middle bits can be set byte by byte. */
[c5396c1]148 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
149 ALL_ONES;
[97a7eff]150 }
[a35b458]151
[4fd61ba]152 if (tab) {
[da88a079]153 /* Make sure to set any trailing aligned bits. */
[c5396c1]154 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
155 (1 << tab) - 1;
[97a7eff]156 }
157}
158
[c5396c1]159/** Clear range of bits.
[7de18418]160 *
161 * @param bitmap Bitmap structure.
162 * @param start Starting bit.
[c5396c1]163 * @param count Number of bits to clear.
[97a7eff]164 *
165 */
[c5396c1]166void bitmap_clear_range(bitmap_t *bitmap, size_t start, size_t count)
[97a7eff]167{
[63e27ef]168 assert(start + count <= bitmap->elements);
[a35b458]169
[7de18418]170 if (count == 0)
[4fe18151]171 return;
[a35b458]172
[6e75f2d]173 size_t start_byte = start / BITMAP_ELEMENT;
[7de18418]174 size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
[a35b458]175
[7de18418]176 /* Leading unaligned bits */
177 size_t lub = min(aligned_start - start, count);
[a35b458]178
[7de18418]179 /* Aligned middle bits */
180 size_t amb = (count > lub) ? (count - lub) : 0;
[a35b458]181
[7de18418]182 /* Trailing aligned bits */
183 size_t tab = amb % BITMAP_ELEMENT;
[a35b458]184
[7de18418]185 if (start + count < aligned_start) {
[10285ad]186 /* Set bits in the middle of byte */
[6e75f2d]187 bitmap->bits[start_byte] &=
[7de18418]188 ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
[10285ad]189 return;
190 }
[a35b458]191
[97a7eff]192 if (lub) {
[da88a079]193 /* Make sure to clear any leading unaligned bits. */
[6e75f2d]194 bitmap->bits[start_byte] &=
[7de18418]195 (1 << (BITMAP_ELEMENT - lub)) - 1;
[97a7eff]196 }
[a35b458]197
[7de18418]198 size_t i;
[a35b458]199
[7de18418]200 for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
[da88a079]201 /* The middle bits can be cleared byte by byte. */
[c5396c1]202 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
203 ALL_ZEROES;
[97a7eff]204 }
[a35b458]205
[4fd61ba]206 if (tab) {
[da88a079]207 /* Make sure to clear any trailing aligned bits. */
[c5396c1]208 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] &=
209 ~((1 << tab) - 1);
[7de18418]210 }
[a35b458]211
[6e75f2d]212 bitmap->next_fit = start_byte;
[97a7eff]213}
214
215/** Copy portion of one bitmap into another bitmap.
216 *
[7de18418]217 * @param dst Destination bitmap.
218 * @param src Source bitmap.
219 * @param count Number of bits to copy.
220 *
[97a7eff]221 */
[7de18418]222void bitmap_copy(bitmap_t *dst, bitmap_t *src, size_t count)
[97a7eff]223{
[63e27ef]224 assert(count <= dst->elements);
225 assert(count <= src->elements);
[a35b458]226
[7de18418]227 size_t i;
[a35b458]228
[7de18418]229 for (i = 0; i < count / BITMAP_ELEMENT; i++)
230 dst->bits[i] = src->bits[i];
[a35b458]231
[7de18418]232 if (count % BITMAP_ELEMENT) {
233 bitmap_clear_range(dst, i * BITMAP_ELEMENT,
234 count % BITMAP_ELEMENT);
235 dst->bits[i] |= src->bits[i] &
236 ((1 << (count % BITMAP_ELEMENT)) - 1);
[97a7eff]237 }
238}
[b45c443]239
[86733f3]240static int constraint_satisfy(size_t index, size_t base, size_t constraint)
241{
242 return (((base + index) & constraint) == 0);
243}
244
245/** Find a continuous zero bit range
246 *
247 * Find a continuous zero bit range in the bitmap. The address
248 * computed as the sum of the index of the first zero bit and
249 * the base argument needs to be compliant with the constraint
250 * (those bits that are set in the constraint cannot be set in
251 * the address).
252 *
253 * If the index argument is non-NULL, the continuous zero range
254 * is set and the index of the first bit is stored to index.
255 * Otherwise the bitmap stays untouched.
256 *
257 * @param bitmap Bitmap structure.
258 * @param count Number of continuous zero bits to find.
259 * @param base Address of the first bit in the bitmap.
[f72906c]260 * @param prefered Prefered address to start searching from.
[86733f3]261 * @param constraint Constraint for the address of the first zero bit.
262 * @param index Place to store the index of the first zero
263 * bit. Can be NULL (in which case the bitmap
264 * is not modified).
265 *
266 * @return Non-zero if a continuous range of zero bits satisfying
267 * the constraint has been found.
268 * @return Zero otherwise.
269 *
270 */
[89ea2dc]271bool bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
[f72906c]272 size_t prefered, size_t constraint, size_t *index)
[86733f3]273{
[d5f774f6]274 if (count == 0)
[86733f3]275 return false;
[a35b458]276
[6e75f2d]277 size_t size = bitmap_size(bitmap->elements);
[f72906c]278 size_t next_fit = bitmap->next_fit;
[a35b458]279
[f72906c]280 /*
281 * Adjust the next-fit value according to the address
282 * the caller prefers to start the search at.
283 */
284 if ((prefered > base) && (prefered < base + bitmap->elements)) {
285 size_t prefered_fit = (prefered - base) / BITMAP_ELEMENT;
[a35b458]286
[f72906c]287 if (prefered_fit > next_fit)
288 next_fit = prefered_fit;
289 }
[a35b458]290
[6e75f2d]291 for (size_t pos = 0; pos < size; pos++) {
[f72906c]292 size_t byte = (next_fit + pos) % size;
[a35b458]293
[64f3d3b]294 /* Skip if the current byte has all bits set */
295 if (bitmap->bits[byte] == ALL_ONES)
[86733f3]296 continue;
[a35b458]297
[64f3d3b]298 size_t byte_bit = byte * BITMAP_ELEMENT;
[a35b458]299
[64f3d3b]300 for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
301 size_t i = byte_bit + bit;
[a35b458]302
[64f3d3b]303 if (i >= bitmap->elements)
304 break;
[a35b458]305
[64f3d3b]306 if (!constraint_satisfy(i, base, constraint))
307 continue;
[a35b458]308
[64f3d3b]309 if (!bitmap_get_fast(bitmap, i)) {
[6e75f2d]310 size_t continuous = 1;
[a35b458]311
[64f3d3b]312 for (size_t j = 1; j < count; j++) {
[6e75f2d]313 if ((i + j < bitmap->elements) &&
314 (!bitmap_get_fast(bitmap, i + j)))
315 continuous++;
316 else
[64f3d3b]317 break;
[86733f3]318 }
[a35b458]319
[6e75f2d]320 if (continuous == count) {
[64f3d3b]321 if (index != NULL) {
322 bitmap_set_range(bitmap, i, count);
[6e75f2d]323 bitmap->next_fit = i / BITMAP_ELEMENT;
[64f3d3b]324 *index = i;
325 }
[a35b458]326
[64f3d3b]327 return true;
[6e75f2d]328 } else
329 i += continuous;
[86733f3]330 }
331 }
332 }
[a35b458]333
[86733f3]334 return false;
335}
336
[cc73a8a1]337/** @}
[b45c443]338 */
Note: See TracBrowser for help on using the repository browser.