ae2f_docs
c89atomic_bitmap_allocator.c
1#ifndef c89atomic_bitmap_allocator_c
2#define c89atomic_bitmap_allocator_c
3
5
6#include <assert.h>
7
8/* Just a naive implementation just to get things working. A proper implementation would probably want to use a hardware instruction for this. */
9static c89atomic_uint32 c89atomic_clz_32(c89atomic_uint32 x)
10{
11 c89atomic_uint32 i;
12
13 for (i = 0; i < 32; i += 1) {
14 if ((x & (0x80000000 >> i)) != 0) {
15 return i;
16 }
17 }
18
19 return i;
20}
21
22
23/* BEG c89atomic_bitmap_allocator.c */
24C89ATOMIC_BITMAP_ALLOCATOR_API c89atomic_bitmap_allocator_result c89atomic_bitmap_allocator_init(void* pBitmap, size_t sizeInBits, c89atomic_bitmap_allocator* pAllocator)
25{
26 size_t i;
27
28 if (pAllocator == NULL || pBitmap == NULL) {
29 return C89ATOMIC_BITMAP_ALLOCATOR_INVALID_ARGS;
30 }
31
32 /* The size in bits must be a multiple of 31. */
33 if ((sizeInBits & 31) != 0) {
34 return C89ATOMIC_BITMAP_ALLOCATOR_INVALID_ARGS;
35 }
36
37 pAllocator->sizeInWords = sizeInBits / (sizeof(pAllocator->bitmap[0]) * 8);
38 pAllocator->bitmap = (c89atomic_uint32*)pBitmap;
39
40 /* Initialize the bitmap to zero. */
41 for (i = 0; i < pAllocator->sizeInWords; i += 1) {
42 pAllocator->bitmap[i] = 0;
43 }
44
45 return C89ATOMIC_BITMAP_ALLOCATOR_SUCCESS;
46}
47
48C89ATOMIC_BITMAP_ALLOCATOR_API c89atomic_bitmap_allocator_result c89atomic_bitmap_allocator_alloc(c89atomic_bitmap_allocator* pAllocator, size_t* pIndex)
49{
50 size_t i;
51
52 /* All we need to do is find the first set bit and return it's index. */
53 for (i = 0; i < pAllocator->sizeInWords; i += 1) {
54 c89atomic_uint32 oldWord;
55 c89atomic_uint32 newWord;
56 c89atomic_uint32 bitIndex;
57
58 for (;;) {
59 oldWord = c89atomic_load_explicit_32(&pAllocator->bitmap[i], c89atomic_memory_order_relaxed);
60 if (oldWord == 0xFFFFFFFF) {
61 break; /* All bits are set, so continue to the next word. */
62 }
63
64 bitIndex = c89atomic_clz_32(~oldWord);
65 assert(bitIndex < 32);
66
67 newWord = oldWord | (0x80000000UL >> bitIndex);
68
69 if (c89atomic_compare_exchange_strong_explicit_32(&pAllocator->bitmap[i], &oldWord, newWord, c89atomic_memory_order_acq_rel, c89atomic_memory_order_relaxed)) {
70 *pIndex = (i * sizeof(pAllocator->bitmap[0]) * 8) + bitIndex;
71 return C89ATOMIC_BITMAP_ALLOCATOR_SUCCESS;
72 }
73 }
74 }
75
76 /* If we reach here, it means we couldn't find a free bit. */
77 return C89ATOMIC_BITMAP_ALLOCATOR_OUT_OF_MEMORY;
78}
79
80C89ATOMIC_BITMAP_ALLOCATOR_API void c89atomic_bitmap_allocator_free(c89atomic_bitmap_allocator* pAllocator, size_t index)
81{
82 c89atomic_uint32 wordIndex;
83 c89atomic_uint32 bitIndex;
84 c89atomic_uint32 oldWord;
85 c89atomic_uint32 newWord;
86
87 wordIndex = (c89atomic_uint32)((index & 0xFFFFFFFF) >> 5); /* slot / 32 */
88 bitIndex = (c89atomic_uint32)((index & 0xFFFFFFFF) & 31); /* slot % 32 */
89
90 if (wordIndex >= pAllocator->sizeInWords) {
91 assert(!"Index out of bounds in c89atomic_bitmap_allocator_free().");
92 return; /* Index out of bounds. */
93 }
94
95 do
96 {
97 oldWord = c89atomic_load_explicit_32(&pAllocator->bitmap[wordIndex], c89atomic_memory_order_relaxed);
98 newWord = oldWord & ~(0x80000000UL >> bitIndex);
99
100 /* Assert to catch a double free. */
101 if ((oldWord & (0x80000000UL >> bitIndex)) == 0) {
102 assert(!"Double free detected in c89atomic_bitmap_allocator_free().");
103 }
104 } while (!c89atomic_compare_exchange_strong_explicit_32(&pAllocator->bitmap[wordIndex], &oldWord, newWord, c89atomic_memory_order_acq_rel, c89atomic_memory_order_relaxed));
105}
106/* END c89atomic_bitmap_allocator.c */
107
108#endif /* c89atomic_bitmap_allocator_c */
#define c89atomic_memory_order_relaxed
Definition c89atomic.h:580
#define c89atomic_memory_order_acq_rel
Definition c89atomic.h:584
#define C89ATOMIC_BITMAP_ALLOCATOR_API