#include <defs.h>
|
|
#include <string.h>
|
|
#include <bitmap.h>
|
|
#include <kmalloc.h>
|
|
#include <error.h>
|
|
#include <assert.h>
|
|
|
|
#define WORD_TYPE uint32_t
|
|
#define WORD_BITS (sizeof(WORD_TYPE) * CHAR_BIT)
|
|
|
|
struct bitmap {
|
|
uint32_t nbits;
|
|
uint32_t nwords;
|
|
WORD_TYPE *map;
|
|
};
|
|
|
|
// bitmap_create - allocate a new bitmap object.
|
|
struct bitmap *
|
|
bitmap_create(uint32_t nbits) {
|
|
static_assert(WORD_BITS != 0);
|
|
assert(nbits != 0 && nbits + WORD_BITS > nbits);
|
|
|
|
struct bitmap *bitmap;
|
|
if ((bitmap = kmalloc(sizeof(struct bitmap))) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t nwords = ROUNDUP_DIV(nbits, WORD_BITS);
|
|
WORD_TYPE *map;
|
|
if ((map = kmalloc(sizeof(WORD_TYPE) * nwords)) == NULL) {
|
|
kfree(bitmap);
|
|
return NULL;
|
|
}
|
|
|
|
bitmap->nbits = nbits, bitmap->nwords = nwords;
|
|
bitmap->map = memset(map, 0xFF, sizeof(WORD_TYPE) * nwords);
|
|
|
|
/* mark any leftover bits at the end in use(0) */
|
|
if (nbits != nwords * WORD_BITS) {
|
|
uint32_t ix = nwords - 1, overbits = nbits - ix * WORD_BITS;
|
|
|
|
assert(nbits / WORD_BITS == ix);
|
|
assert(overbits > 0 && overbits < WORD_BITS);
|
|
|
|
for (; overbits < WORD_BITS; overbits ++) {
|
|
bitmap->map[ix] ^= (1 << overbits);
|
|
}
|
|
}
|
|
return bitmap;
|
|
}
|
|
|
|
// bitmap_alloc - locate a cleared bit, set it, and return its index.
|
|
int
|
|
bitmap_alloc(struct bitmap *bitmap, uint32_t *index_store) {
|
|
WORD_TYPE *map = bitmap->map;
|
|
uint32_t ix, offset, nwords = bitmap->nwords;
|
|
for (ix = 0; ix < nwords; ix ++) {
|
|
if (map[ix] != 0) {
|
|
for (offset = 0; offset < WORD_BITS; offset ++) {
|
|
WORD_TYPE mask = (1 << offset);
|
|
if (map[ix] & mask) {
|
|
map[ix] ^= mask;
|
|
*index_store = ix * WORD_BITS + offset;
|
|
return 0;
|
|
}
|
|
}
|
|
assert(0);
|
|
}
|
|
}
|
|
return -E_NO_MEM;
|
|
}
|
|
|
|
// bitmap_translate - according index, get the related word and mask
|
|
static void
|
|
bitmap_translate(struct bitmap *bitmap, uint32_t index, WORD_TYPE **word, WORD_TYPE *mask) {
|
|
assert(index < bitmap->nbits);
|
|
uint32_t ix = index / WORD_BITS, offset = index % WORD_BITS;
|
|
*word = bitmap->map + ix;
|
|
*mask = (1 << offset);
|
|
}
|
|
|
|
// bitmap_test - according index, get the related value (0 OR 1) in the bitmap
|
|
bool
|
|
bitmap_test(struct bitmap *bitmap, uint32_t index) {
|
|
WORD_TYPE *word, mask;
|
|
bitmap_translate(bitmap, index, &word, &mask);
|
|
return (*word & mask);
|
|
}
|
|
|
|
// bitmap_free - according index, set related bit to 1
|
|
void
|
|
bitmap_free(struct bitmap *bitmap, uint32_t index) {
|
|
WORD_TYPE *word, mask;
|
|
bitmap_translate(bitmap, index, &word, &mask);
|
|
assert(!(*word & mask));
|
|
*word |= mask;
|
|
}
|
|
|
|
// bitmap_destroy - free memory contains bitmap
|
|
void
|
|
bitmap_destroy(struct bitmap *bitmap) {
|
|
kfree(bitmap->map);
|
|
kfree(bitmap);
|
|
}
|
|
|
|
// bitmap_getdata - return bitmap->map, return the length of bits to len_store
|
|
void *
|
|
bitmap_getdata(struct bitmap *bitmap, size_t *len_store) {
|
|
if (len_store != NULL) {
|
|
*len_store = sizeof(WORD_TYPE) * bitmap->nwords;
|
|
}
|
|
return bitmap->map;
|
|
}
|
|
|