Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/src/adt/bitmap.c

    rf72906c r64f3d3b  
    3737 * setting and clearing ranges of bits and for finding ranges
    3838 * of unset bits.
     39 *
     40 * The bitmap ADT can optionally implement a two-level hierarchy
     41 * for faster range searches. The second level bitmap (of blocks)
     42 * is not precise, but conservative. This means that if the block
     43 * bit is set, it guarantees that all bits in the block are set.
     44 * But if the block bit is unset, nothing can be said about the
     45 * bits in the block.
     46 *
    3947 */
    4048
     
    4856#define ALL_ZEROES  0x00
    4957
     58/** Compute the size of a bitmap
     59 *
     60 * Compute the size of a bitmap that can store given number
     61 * of elements.
     62 *
     63 * @param elements Number of elements to store.
     64 *
     65 * @return Size of the bitmap (in units of BITMAP_ELEMENT bits).
     66 *
     67 */
     68static size_t bitmap_bytes(size_t elements)
     69{
     70        size_t bytes = elements / BITMAP_ELEMENT;
     71       
     72        if ((elements % BITMAP_ELEMENT) != 0)
     73                bytes++;
     74       
     75        return bytes;
     76}
     77
     78/** Compute the number of 2nd level blocks
     79 *
     80 * Compute the number of 2nd level blocks for a given number
     81 * of elements.
     82 *
     83 * @param elements   Number of elements.
     84 * @param block_size Number of elements in one block.
     85 *
     86 * @return Number of 2nd level blocks.
     87 * @return Zero if block_size is zero.
     88 *
     89 */
     90static size_t bitmap_blocks(size_t elements, size_t block_size)
     91{
     92        if (block_size == 0)
     93                return 0;
     94       
     95        size_t blocks = elements / block_size;
     96       
     97        if ((elements % block_size) != 0)
     98                blocks++;
     99       
     100        return blocks;
     101}
     102
    50103/** Unchecked version of bitmap_get()
    51104 *
     
    60113static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
    61114{
    62         size_t byte = element / BITMAP_ELEMENT;
    63         uint8_t mask = 1 << (element & BITMAP_REMAINER);
    64        
    65         return !!((bitmap->bits)[byte] & mask);
     115        return !!((bitmap->bits)[element / BITMAP_ELEMENT] &
     116            (1 << (element & BITMAP_REMAINER)));
    66117}
    67118
     
    71122 *
    72123 * @param elements   Number bits stored in bitmap.
     124 * @param block_size Block size of the 2nd level bitmap.
     125 *                   If set to zero, no 2nd level is used.
    73126 *
    74127 * @return Size (in bytes) required for the bitmap.
    75128 *
    76129 */
    77 size_t bitmap_size(size_t elements)
    78 {
    79         size_t size = elements / BITMAP_ELEMENT;
    80        
    81         if ((elements % BITMAP_ELEMENT) != 0)
    82                 size++;
    83        
    84         return size;
     130size_t bitmap_size(size_t elements, size_t block_size)
     131{
     132        size_t blocks = bitmap_blocks(elements, block_size);
     133       
     134        return (bitmap_bytes(elements) + bitmap_bytes(blocks));
    85135}
    86136
     
    91141 * @param bitmap     Bitmap structure.
    92142 * @param elements   Number of bits stored in bitmap.
     143 * @param block_size Block size of the 2nd level bitmap.
     144 *                   If set to zero, no 2nd level is used.
    93145 * @param data       Address of the memory used to hold the map.
    94146 *                   The optional 2nd level bitmap follows the 1st
     
    96148 *
    97149 */
    98 void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
     150void bitmap_initialize(bitmap_t *bitmap, size_t elements, size_t block_size,
     151    void *data)
    99152{
    100153        bitmap->elements = elements;
    101154        bitmap->bits = (uint8_t *) data;
    102         bitmap->next_fit = 0;
     155       
     156        if (block_size > 0) {
     157                bitmap->block_size = block_size;
     158                bitmap->blocks = bitmap->bits +
     159                    bitmap_size(elements, 0);
     160        } else {
     161                bitmap->block_size = 0;
     162                bitmap->blocks = NULL;
     163        }
     164}
     165
     166static void bitmap_set_range_internal(uint8_t *bits, size_t start, size_t count)
     167{
     168        if (count == 0)
     169                return;
     170       
     171        size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
     172       
     173        /* Leading unaligned bits */
     174        size_t lub = min(aligned_start - start, count);
     175       
     176        /* Aligned middle bits */
     177        size_t amb = (count > lub) ? (count - lub) : 0;
     178       
     179        /* Trailing aligned bits */
     180        size_t tab = amb % BITMAP_ELEMENT;
     181       
     182        if (start + count < aligned_start) {
     183                /* Set bits in the middle of byte. */
     184                bits[start / BITMAP_ELEMENT] |=
     185                    ((1 << lub) - 1) << (start & BITMAP_REMAINER);
     186                return;
     187        }
     188       
     189        if (lub) {
     190                /* Make sure to set any leading unaligned bits. */
     191                bits[start / BITMAP_ELEMENT] |=
     192                    ~((1 << (BITMAP_ELEMENT - lub)) - 1);
     193        }
     194       
     195        size_t i;
     196       
     197        for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
     198                /* The middle bits can be set byte by byte. */
     199                bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ONES;
     200        }
     201       
     202        if (tab) {
     203                /* Make sure to set any trailing aligned bits. */
     204                bits[aligned_start / BITMAP_ELEMENT + i] |= (1 << tab) - 1;
     205        }
    103206}
    104207
     
    114217        ASSERT(start + count <= bitmap->elements);
    115218       
     219        bitmap_set_range_internal(bitmap->bits, start, count);
     220       
     221        if (bitmap->block_size > 0) {
     222                size_t aligned_start = ALIGN_UP(start, bitmap->block_size);
     223               
     224                /* Leading unaligned bits */
     225                size_t lub = min(aligned_start - start, count);
     226               
     227                /* Aligned middle bits */
     228                size_t amb = (count > lub) ? (count - lub) : 0;
     229               
     230                size_t aligned_size = amb / bitmap->block_size;
     231               
     232                bitmap_set_range_internal(bitmap->blocks, aligned_start,
     233                    aligned_size);
     234        }
     235}
     236
     237static void bitmap_clear_range_internal(uint8_t *bits, size_t start,
     238    size_t count)
     239{
    116240        if (count == 0)
    117241                return;
    118242       
    119         size_t start_byte = start / BITMAP_ELEMENT;
    120243        size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
    121244       
     
    130253       
    131254        if (start + count < aligned_start) {
    132                 /* Set bits in the middle of byte. */
    133                 bitmap->bits[start_byte] |=
    134                     ((1 << lub) - 1) << (start & BITMAP_REMAINER);
     255                /* Set bits in the middle of byte */
     256                bits[start / BITMAP_ELEMENT] &=
     257                    ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
    135258                return;
    136259        }
    137260       
    138261        if (lub) {
    139                 /* Make sure to set any leading unaligned bits. */
    140                 bitmap->bits[start_byte] |=
    141                     ~((1 << (BITMAP_ELEMENT - lub)) - 1);
     262                /* Make sure to clear any leading unaligned bits. */
     263                bits[start / BITMAP_ELEMENT] &=
     264                    (1 << (BITMAP_ELEMENT - lub)) - 1;
    142265        }
    143266       
     
    145268       
    146269        for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
    147                 /* The middle bits can be set byte by byte. */
    148                 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
    149                     ALL_ONES;
     270                /* The middle bits can be cleared byte by byte. */
     271                bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ZEROES;
    150272        }
    151273       
    152274        if (tab) {
    153                 /* Make sure to set any trailing aligned bits. */
    154                 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
    155                     (1 << tab) - 1;
     275                /* Make sure to clear any trailing aligned bits. */
     276                bits[aligned_start / BITMAP_ELEMENT + i] &= ~((1 << tab) - 1);
    156277        }
    157278}
     
    168289        ASSERT(start + count <= bitmap->elements);
    169290       
    170         if (count == 0)
    171                 return;
    172        
    173         size_t start_byte = start / BITMAP_ELEMENT;
    174         size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
    175        
    176         /* Leading unaligned bits */
    177         size_t lub = min(aligned_start - start, count);
    178        
    179         /* Aligned middle bits */
    180         size_t amb = (count > lub) ? (count - lub) : 0;
    181        
    182         /* Trailing aligned bits */
    183         size_t tab = amb % BITMAP_ELEMENT;
    184        
    185         if (start + count < aligned_start) {
    186                 /* Set bits in the middle of byte */
    187                 bitmap->bits[start_byte] &=
    188                     ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
    189                 return;
    190         }
    191        
    192         if (lub) {
    193                 /* Make sure to clear any leading unaligned bits. */
    194                 bitmap->bits[start_byte] &=
    195                     (1 << (BITMAP_ELEMENT - lub)) - 1;
    196         }
    197        
    198         size_t i;
    199        
    200         for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
    201                 /* The middle bits can be cleared byte by byte. */
    202                 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] =
    203                     ALL_ZEROES;
    204         }
    205        
    206         if (tab) {
    207                 /* Make sure to clear any trailing aligned bits. */
    208                 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] &=
    209                     ~((1 << tab) - 1);
    210         }
    211        
    212         bitmap->next_fit = start_byte;
     291        bitmap_clear_range_internal(bitmap->bits, start, count);
     292       
     293        if (bitmap->block_size > 0) {
     294                size_t aligned_start = start / bitmap->block_size;
     295               
     296                size_t aligned_end = (start + count) / bitmap->block_size;
     297               
     298                if (((start + count) % bitmap->block_size) != 0)
     299                        aligned_end++;
     300               
     301                size_t aligned_size = aligned_end - aligned_start;
     302               
     303                bitmap_clear_range_internal(bitmap->blocks, aligned_start,
     304                    aligned_size);
     305        }
    213306}
    214307
     
    258351 * @param count      Number of continuous zero bits to find.
    259352 * @param base       Address of the first bit in the bitmap.
    260  * @param prefered   Prefered address to start searching from.
    261353 * @param constraint Constraint for the address of the first zero bit.
    262354 * @param index      Place to store the index of the first zero
     
    270362 */
    271363int bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
    272     size_t prefered, size_t constraint, size_t *index)
     364    size_t constraint, size_t *index)
    273365{
    274366        if (count == 0)
    275367                return false;
    276368       
    277         size_t size = bitmap_size(bitmap->elements);
    278         size_t next_fit = bitmap->next_fit;
    279        
    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;
    286                
    287                 if (prefered_fit > next_fit)
    288                         next_fit = prefered_fit;
    289         }
    290        
    291         for (size_t pos = 0; pos < size; pos++) {
    292                 size_t byte = (next_fit + pos) % size;
    293                
     369        size_t bytes = bitmap_bytes(bitmap->elements);
     370       
     371        for (size_t byte = 0; byte < bytes; byte++) {
    294372                /* Skip if the current byte has all bits set */
    295373                if (bitmap->bits[byte] == ALL_ONES)
     
    308386                       
    309387                        if (!bitmap_get_fast(bitmap, i)) {
    310                                 size_t continuous = 1;
     388                                bool continuous = true;
    311389                               
    312390                                for (size_t j = 1; j < count; j++) {
    313                                         if ((i + j < bitmap->elements) &&
    314                                             (!bitmap_get_fast(bitmap, i + j)))
    315                                                 continuous++;
    316                                         else
     391                                        if ((i + j >= bitmap->elements) ||
     392                                            (bitmap_get_fast(bitmap, i + j))) {
     393                                                continuous = false;
    317394                                                break;
     395                                        }
    318396                                }
    319397                               
    320                                 if (continuous == count) {
     398                                if (continuous) {
    321399                                        if (index != NULL) {
    322400                                                bitmap_set_range(bitmap, i, count);
    323                                                 bitmap->next_fit = i / BITMAP_ELEMENT;
    324401                                                *index = i;
    325402                                        }
    326403                                       
    327404                                        return true;
    328                                 } else
    329                                         i += continuous;
     405                                }
    330406                        }
    331407                }
Note: See TracChangeset for help on using the changeset viewer.