Ignore:
File:
1 edited

Legend:

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

    r6e75f2d r7de18418  
    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
    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  */
    60 static unsigned int bitmap_get_fast(bitmap_t *bitmap, size_t element)
    61 {
    62         size_t byte = element / BITMAP_ELEMENT;
    63         uint8_t mask = 1 << (element & BITMAP_REMAINER);
    64        
    65         return !!((bitmap->bits)[byte] & mask);
    66 }
    67 
    6858/** Get bitmap size
    6959 *
     
    7161 *
    7262 * @param elements   Number bits stored in bitmap.
     63 * @param block_size Block size of the 2nd level bitmap.
     64 *                   If set to zero, no 2nd level is used.
    7365 *
    7466 * @return Size (in bytes) required for the bitmap.
    7567 *
    7668 */
    77 size_t bitmap_size(size_t elements)
     69size_t bitmap_size(size_t elements, size_t block_size)
    7870{
    7971        size_t size = elements / BITMAP_ELEMENT;
     
    8274                size++;
    8375       
     76        if (block_size > 0) {
     77                size += elements / block_size;
     78               
     79                if ((elements % block_size) != 0)
     80                        size++;
     81        }
     82       
    8483        return size;
    8584}
     
    9190 * @param bitmap     Bitmap structure.
    9291 * @param elements   Number of bits stored in bitmap.
     92 * @param block_size Block size of the 2nd level bitmap.
     93 *                   If set to zero, no 2nd level is used.
    9394 * @param data       Address of the memory used to hold the map.
    9495 *                   The optional 2nd level bitmap follows the 1st
     
    9697 *
    9798 */
    98 void bitmap_initialize(bitmap_t *bitmap, size_t elements, void *data)
     99void bitmap_initialize(bitmap_t *bitmap, size_t elements, size_t block_size,
     100    void *data)
    99101{
    100102        bitmap->elements = elements;
    101103        bitmap->bits = (uint8_t *) data;
    102         bitmap->next_fit = 0;
     104       
     105        if (block_size > 0) {
     106                bitmap->block_size = block_size;
     107                bitmap->blocks = bitmap->bits +
     108                    bitmap_size(elements, 0);
     109        } else {
     110                bitmap->block_size = 0;
     111                bitmap->blocks = NULL;
     112        }
     113}
     114
     115static void bitmap_set_range_internal(uint8_t *bits, size_t start, size_t count)
     116{
     117        if (count == 0)
     118                return;
     119       
     120        size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
     121       
     122        /* Leading unaligned bits */
     123        size_t lub = min(aligned_start - start, count);
     124       
     125        /* Aligned middle bits */
     126        size_t amb = (count > lub) ? (count - lub) : 0;
     127       
     128        /* Trailing aligned bits */
     129        size_t tab = amb % BITMAP_ELEMENT;
     130       
     131        if (start + count < aligned_start) {
     132                /* Set bits in the middle of byte. */
     133                bits[start / BITMAP_ELEMENT] |=
     134                    ((1 << lub) - 1) << (start & BITMAP_REMAINER);
     135                return;
     136        }
     137       
     138        if (lub) {
     139                /* Make sure to set any leading unaligned bits. */
     140                bits[start / BITMAP_ELEMENT] |=
     141                    ~((1 << (BITMAP_ELEMENT - lub)) - 1);
     142        }
     143       
     144        size_t i;
     145       
     146        for (i = 0; i < amb / BITMAP_ELEMENT; i++) {
     147                /* The middle bits can be set byte by byte. */
     148                bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ONES;
     149        }
     150       
     151        if (tab) {
     152                /* Make sure to set any trailing aligned bits. */
     153                bits[aligned_start / BITMAP_ELEMENT + i] |= (1 << tab) - 1;
     154        }
    103155}
    104156
     
    114166        ASSERT(start + count <= bitmap->elements);
    115167       
     168        bitmap_set_range_internal(bitmap->bits, start, count);
     169       
     170        if (bitmap->block_size > 0) {
     171                size_t aligned_start = ALIGN_UP(start, bitmap->block_size);
     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                size_t aligned_size = amb / bitmap->block_size;
     180               
     181                bitmap_set_range_internal(bitmap->blocks, aligned_start,
     182                    aligned_size);
     183        }
     184}
     185
     186static void bitmap_clear_range_internal(uint8_t *bits, size_t start,
     187    size_t count)
     188{
    116189        if (count == 0)
    117190                return;
    118191       
    119         size_t start_byte = start / BITMAP_ELEMENT;
    120192        size_t aligned_start = ALIGN_UP(start, BITMAP_ELEMENT);
    121193       
     
    130202       
    131203        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);
     204                /* Set bits in the middle of byte */
     205                bits[start / BITMAP_ELEMENT] &=
     206                    ~(((1 << lub) - 1) << (start & BITMAP_REMAINER));
    135207                return;
    136208        }
    137209       
    138210        if (lub) {
    139                 /* Make sure to set any leading unaligned bits. */
    140                 bitmap->bits[start_byte] |=
    141                     ~((1 << (BITMAP_ELEMENT - lub)) - 1);
     211                /* Make sure to clear any leading unaligned bits. */
     212                bits[start / BITMAP_ELEMENT] &=
     213                    (1 << (BITMAP_ELEMENT - lub)) - 1;
    142214        }
    143215       
     
    145217       
    146218        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;
     219                /* The middle bits can be cleared byte by byte. */
     220                bits[aligned_start / BITMAP_ELEMENT + i] = ALL_ZEROES;
    150221        }
    151222       
    152223        if (tab) {
    153                 /* Make sure to set any trailing aligned bits. */
    154                 bitmap->bits[aligned_start / BITMAP_ELEMENT + i] |=
    155                     (1 << tab) - 1;
     224                /* Make sure to clear any trailing aligned bits. */
     225                bits[aligned_start / BITMAP_ELEMENT + i] &= ~((1 << tab) - 1);
    156226        }
    157227}
     
    168238        ASSERT(start + count <= bitmap->elements);
    169239       
    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;
     240        bitmap_clear_range_internal(bitmap->bits, start, count);
     241       
     242        if (bitmap->block_size > 0) {
     243                size_t aligned_start = start / bitmap->block_size;
     244               
     245                size_t aligned_end = (start + count) / bitmap->block_size;
     246               
     247                if (((start + count) % bitmap->block_size) != 0)
     248                        aligned_end++;
     249               
     250                size_t aligned_size = aligned_end - aligned_start;
     251               
     252                bitmap_clear_range_internal(bitmap->blocks, aligned_start,
     253                    aligned_size);
     254        }
    213255}
    214256
     
    238280}
    239281
    240 static 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.
    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  */
    270 int bitmap_allocate_range(bitmap_t *bitmap, size_t count, size_t base,
    271     size_t constraint, size_t *index)
    272 {
    273         if (count == 0)
    274                 return false;
    275        
    276         size_t size = bitmap_size(bitmap->elements);
    277        
    278         for (size_t pos = 0; pos < size; pos++) {
    279                 size_t byte = (bitmap->next_fit + pos) % size;
    280                
    281                 /* Skip if the current byte has all bits set */
    282                 if (bitmap->bits[byte] == ALL_ONES)
    283                         continue;
    284                
    285                 size_t byte_bit = byte * BITMAP_ELEMENT;
    286                
    287                 for (size_t bit = 0; bit < BITMAP_ELEMENT; bit++) {
    288                         size_t i = byte_bit + bit;
    289                        
    290                         if (i >= bitmap->elements)
    291                                 break;
    292                        
    293                         if (!constraint_satisfy(i, base, constraint))
    294                                 continue;
    295                        
    296                         if (!bitmap_get_fast(bitmap, i)) {
    297                                 size_t continuous = 1;
    298                                
    299                                 for (size_t j = 1; j < count; j++) {
    300                                         if ((i + j < bitmap->elements) &&
    301                                             (!bitmap_get_fast(bitmap, i + j)))
    302                                                 continuous++;
    303                                         else
    304                                                 break;
    305                                 }
    306                                
    307                                 if (continuous == count) {
    308                                         if (index != NULL) {
    309                                                 bitmap_set_range(bitmap, i, count);
    310                                                 bitmap->next_fit = i / BITMAP_ELEMENT;
    311                                                 *index = i;
    312                                         }
    313                                        
    314                                         return true;
    315                                 } else
    316                                         i += continuous;
    317                         }
    318                 }
    319         }
    320        
    321         return false;
    322 }
    323 
    324282/** @}
    325283 */
Note: See TracChangeset for help on using the changeset viewer.