diff --git a/include/ck_bitmap.h b/include/ck_bitmap.h index 96ab630..559c1d2 100644 --- a/include/ck_bitmap.h +++ b/include/ck_bitmap.h @@ -54,94 +54,151 @@ #define CK_BITMAP_AND(x, y) ck_pr_and_32(x, y) #else #error "ck_bitmap is not supported on your platform." -#endif +#endif /* These are all internal functions. */ #define CK_BITMAP_PTR(x, i) ((x) + ((i) >> CK_BITMAP_SHIFT)) -#define CK_BITMAP_MASK (sizeof(CK_BITMAP_TYPE) * CHAR_BIT - 1) +#define CK_BITMAP_BLOCK (sizeof(CK_BITMAP_TYPE) * CHAR_BIT) +#define CK_BITMAP_MASK (CK_BITMAP_BLOCK - 1) +#define CK_BITMAP_BLOCKS(n) \ + (((n) + (CK_BITMAP_BLOCK - 1)) / CK_BITMAP_BLOCK) + +#define CK_BITMAP_INSTANCE(n_entries) \ + struct { \ + unsigned int n_bits; \ + unsigned int n_buckets; \ + CK_BITMAP_TYPE map[CK_BITMAP_BLOCKS(n_entries)];\ + } + +#define CK_BITMAP_INIT(a, b, c) \ + ck_bitmap_init((struct ck_bitmap *)(a), (b), (c)) + +#define CK_BITMAP_SET_MPMC(a, b) \ + ck_bitmap_set_mpmc((struct ck_bitmap *)(a), (b)) + +#define CK_BITMAP_RESET_MPMC(a, b) \ + ck_bitmap_reset_mpmc((struct ck_bitmap *)(a), (b)) + +#define CK_BITMAP_CLEAR(a) \ + ck_bitmap_clear((struct ck_bitmap *)(a)) + +#define CK_BITMAP_TEST(a, b) \ + ck_bitmap_test((struct ck_bitmap *)(a), (b)) + +#define CK_BITMAP_BITS(a, b) \ + ck_bitmap_bits((struct ck_bitmap *)(a)) + +#define CK_BITMAP_BUFFER(a) \ + ck_bitmap_buffer((struct ck_bitmap *)(a)) + +#define CK_BITMAP(a) \ + ((struct ck_bitmap *)(a)) struct ck_bitmap { - unsigned int length; + unsigned int n_bits; unsigned int n_buckets; - CK_BITMAP_TYPE *map; + CK_BITMAP_TYPE map[]; }; typedef struct ck_bitmap ck_bitmap_t; -/* - * Returns the number of bytes that must be allocated for a bitmap - * with the specified number of entries. - */ CK_CC_INLINE static unsigned int -ck_bitmap_size(unsigned int entries) +ck_bitmap_base(unsigned int n_bits) { - size_t s = sizeof(CK_BITMAP_TYPE) * CHAR_BIT; - return ((entries + (s - 1)) / s) * sizeof(CK_BITMAP_TYPE); + return CK_BITMAP_BLOCKS(n_bits) * sizeof(CK_BITMAP_TYPE); } -CK_CC_INLINE static void +CK_CC_INLINE static unsigned int +ck_bitmap_size(unsigned int n_bits) +{ + + return ck_bitmap_base(n_bits) + sizeof(struct ck_bitmap); +} + +/* + * Initializes a ck_bitmap pointing to a region of memory with + * ck_bitmap_size(n_bits) bytes. Third argument determines whether + * default bit value is 1 (true) or 0 (false). + */ +static void ck_bitmap_init(struct ck_bitmap *bitmap, - void *buffer, - unsigned int length, + unsigned int n_bits, bool set) { + unsigned int base = ck_bitmap_base(n_bits); - bitmap->map = buffer; - bitmap->length = length; - bitmap->n_buckets = ck_bitmap_size(length) / sizeof(CK_BITMAP_TYPE); - memset(bitmap->map, -(int)set, ck_bitmap_size(length)); + bitmap->n_bits = n_bits; + bitmap->n_buckets = base / sizeof(CK_BITMAP_TYPE); + memset(bitmap->map, -(int)set, base); return; } +/* + * Sets the bit at the offset specified in the second argument. + */ CK_CC_INLINE static void ck_bitmap_set_mpmc(struct ck_bitmap *bitmap, unsigned int n) { CK_BITMAP_TYPE mask = 0x1ULL << (n & CK_BITMAP_MASK); - CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); - CK_BITMAP_OR(CK_BITMAP_PTR(map, n), mask); + CK_BITMAP_OR(CK_BITMAP_PTR(bitmap->map, n), mask); return; } +/* + * Resets the bit at the offset specified in the second argument. + */ CK_CC_INLINE static void ck_bitmap_reset_mpmc(struct ck_bitmap *bitmap, unsigned int n) { CK_BITMAP_TYPE mask = ~(0x1ULL << (n & CK_BITMAP_MASK)); - CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); - CK_BITMAP_AND(CK_BITMAP_PTR(map, n), mask); + CK_BITMAP_AND(CK_BITMAP_PTR(bitmap->map, n), mask); return; } -CK_CC_INLINE static void * -ck_bitmap_clear_mpmc(struct ck_bitmap *bitmap, void *buffer) +/* + * Resets all bits in the provided bitmap. This is not a linearized + * operation in ck_bitmap. + */ +CK_CC_INLINE static void +ck_bitmap_clear(struct ck_bitmap *bitmap) { - CK_BITMAP_TYPE *pointer = ck_pr_load_ptr(&bitmap->map); unsigned int i; - if (buffer != NULL) { - if (ck_pr_cas_ptr(&bitmap->map, pointer, buffer) == true) - return pointer; - - return buffer; - } - for (i = 0; i < bitmap->n_buckets; i++) - CK_BITMAP_STORE(&pointer[i], 0); + CK_BITMAP_STORE(&bitmap->map[i], 0); - return NULL; + return; } +/* + * Determines whether the bit at offset specified in the + * second argument is set. + */ CK_CC_INLINE static bool ck_bitmap_test(struct ck_bitmap *bitmap, unsigned int n) { CK_BITMAP_TYPE mask = 0x1ULL << (n & CK_BITMAP_MASK); - CK_BITMAP_TYPE *map = ck_pr_load_ptr(&bitmap->map); CK_BITMAP_TYPE block; - block = CK_BITMAP_LOAD(CK_BITMAP_PTR(map, n)); + block = CK_BITMAP_LOAD(CK_BITMAP_PTR(bitmap->map, n)); return block & mask; } +/* + * Returns total number of bits in specified bitmap. + */ +CK_CC_INLINE static unsigned int +ck_bitmap_bits(struct ck_bitmap *bitmap) +{ + + return bitmap->n_bits; +} + +/* + * Returns a pointer to the bit buffer associated + * with the specified bitmap. + */ CK_CC_INLINE static void * ck_bitmap_buffer(struct ck_bitmap *bitmap) { diff --git a/regressions/ck_bitmap/validate/Makefile b/regressions/ck_bitmap/validate/Makefile index 6f28020..2af2293 100644 --- a/regressions/ck_bitmap/validate/Makefile +++ b/regressions/ck_bitmap/validate/Makefile @@ -4,7 +4,7 @@ OBJECTS=serial all: $(OBJECTS) -serial: serial.c +serial: serial.c ../../../include/ck_bitmap.h $(CC) $(CFLAGS) -o serial serial.c clean: diff --git a/regressions/ck_bitmap/validate/serial.c b/regressions/ck_bitmap/validate/serial.c index 3b7ad26..e217f75 100644 --- a/regressions/ck_bitmap/validate/serial.c +++ b/regressions/ck_bitmap/validate/serial.c @@ -30,21 +30,25 @@ #include #include +#ifndef STATIC_LENGTH +#define STATIC_LENGTH 256 +#endif + static unsigned int length = 256; static void test(ck_bitmap_t *bits, bool initial) { - unsigned int i; + unsigned int i, n_length = bits->n_bits; - for (i = 0; i < length; i++) { + for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == !initial) { - fprintf(stderr, "[4] ERROR: Expected bit to not be set: %u\n", i); + fprintf(stderr, "[0] ERROR: Expected bit to not be set: %u\n", i); exit(EXIT_FAILURE); } } - for (i = 0; i < length; i++) { + for (i = 0; i < n_length; i++) { ck_bitmap_set_mpmc(bits, i); if (ck_bitmap_test(bits, i) == false) { fprintf(stderr, "[1] ERROR: Expected bit to be set: %u\n", i); @@ -64,41 +68,78 @@ test(ck_bitmap_t *bits, bool initial) } } - for (i = 0; i < length; i++) { + for (i = 0; i < n_length; i++) { if (ck_bitmap_test(bits, i) == false) { fprintf(stderr, "[4] ERROR: Expected bit to be set: %u\n", i); exit(EXIT_FAILURE); } } + ck_bitmap_clear(bits); + + for (i = 0; i < n_length; i++) { + if (ck_bitmap_test(bits, i) == true) { + fprintf(stderr, "[4] ERROR: Expected bit to be reset: %u\n", i); + exit(EXIT_FAILURE); + } + } + return; } int main(int argc, char *argv[]) { - unsigned int bytes; - ck_bitmap_t bits; - void *buffer; + unsigned int bytes, base; + ck_bitmap_t *bits; if (argc >= 2) { length = atoi(argv[1]); } + base = ck_bitmap_base(length); bytes = ck_bitmap_size(length); - fprintf(stderr, "Configuration: %u bytes\n\n", + fprintf(stderr, "Configuration: %u bytes\n", bytes); - buffer = malloc(bytes); - memset(buffer, 0xFF, bytes); - ck_bitmap_init(&bits, buffer, length, false); - test(&bits, false); + bits = malloc(bytes); + memset(bits->map, 0xFF, base); + ck_bitmap_init(bits, length, false); + test(bits, false); + + memset(bits->map, 0x00, base); + ck_bitmap_init(bits, length, true); + test(bits, true); + + ck_bitmap_test(bits, length - 1); + + CK_BITMAP_INSTANCE(STATIC_LENGTH) sb; + fprintf(stderr, "Static configuration: %zu bytes\n", + sizeof(sb)); + memset(CK_BITMAP_BUFFER(&sb), 0xFF, ck_bitmap_base(STATIC_LENGTH)); + CK_BITMAP_INIT(&sb, STATIC_LENGTH, false); + test(CK_BITMAP(&sb), false); + memset(CK_BITMAP_BUFFER(&sb), 0x00, ck_bitmap_base(STATIC_LENGTH)); + CK_BITMAP_INIT(&sb, STATIC_LENGTH, true); + test(CK_BITMAP(&sb), true); + + CK_BITMAP_CLEAR(&sb); + if (CK_BITMAP_TEST(&sb, 1) == true) { + fprintf(stderr, "ERROR: Expected bit to be reset.\n"); + exit(EXIT_FAILURE); + } - memset(buffer, 0xFF, bytes); - ck_bitmap_init(&bits, buffer, length, true); - test(&bits, true); + CK_BITMAP_SET_MPMC(&sb, 1); + if (CK_BITMAP_TEST(&sb, 1) == false) { + fprintf(stderr, "ERROR: Expected bit to be set.\n"); + exit(EXIT_FAILURE); + } - ck_bitmap_test(&bits, length - 1); + CK_BITMAP_RESET_MPMC(&sb, 1); + if (CK_BITMAP_TEST(&sb, 1) == true) { + fprintf(stderr, "ERROR: Expected bit to be reset.\n"); + exit(EXIT_FAILURE); + } return 0; }