Add slot allocator
This commit is contained in:
Vendored
+3
-6
@@ -1,14 +1,11 @@
|
|||||||
{
|
{
|
||||||
"files.associations": {
|
"files.associations": {
|
||||||
"ringbuf.h": "c",
|
"*.h": "c",
|
||||||
"seq.h": "c",
|
|
||||||
"stdint.h": "c",
|
|
||||||
"stdio.h": "c"
|
|
||||||
},
|
},
|
||||||
"C_Cpp.default.includePath": [
|
"C_Cpp.default.includePath": [
|
||||||
"/opt/homebrew/include/",
|
"/opt/homebrew/include/",
|
||||||
"$(workspaceFolder)/include/",
|
"$(workspaceFolder)/include/",
|
||||||
|
|
||||||
|
],
|
||||||
]
|
"C_Cpp.default.cStandard": "gnu99"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ struct UCBitVec {
|
|||||||
* Use as
|
* Use as
|
||||||
* @code
|
* @code
|
||||||
* uc_bv_integer v[10];
|
* uc_bv_integer v[10];
|
||||||
* struct UCBitVec v = BITVEC_STATIC_INIT(v);
|
* struct UCBitVec v = UC_BV_STATIC_INIT(v);
|
||||||
* @endcode
|
* @endcode
|
||||||
*/
|
*/
|
||||||
#define UC_BV_STATIC_INIT(vec_data)\
|
#define UC_BV_STATIC_INIT(vec_data)\
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
#ifndef UC_SLOT_ALLOCATOR_H_
|
||||||
|
#define UC_SLOT_ALLOCATOR_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "ucore/bitvec.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/** @file
|
||||||
|
* Fixed size slot memory allocator
|
||||||
|
*
|
||||||
|
* UCSlotAlloc is used to allocate fixed slots of memory from a pre-allocated
|
||||||
|
* piece of memory.
|
||||||
|
*
|
||||||
|
* The main use case is to keep allocated memory in a contiguous block for use
|
||||||
|
* maximum number of objects(slots) is known and relatively small. More than 131072 slots
|
||||||
|
* is not recommended.
|
||||||
|
*
|
||||||
|
* Note that this allocator is not thread safe.
|
||||||
|
*
|
||||||
|
* A bitmap is used to track which slots are allocated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct UCSlotAlloc UCSlotAlloc;
|
||||||
|
struct UCSlotAlloc {
|
||||||
|
const uint32_t slot_size;
|
||||||
|
const uint32_t num_slots;
|
||||||
|
struct UCBitVec bitmap;
|
||||||
|
uint8_t *slots;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialize a UCSlotAlloc with an array as the backing memory to allocate slots from.
|
||||||
|
* The macro can be used at local scope to allocate memory automatic (stack) storage,
|
||||||
|
* or at global scope where the backin array will have static storage duration
|
||||||
|
*
|
||||||
|
* Use as:
|
||||||
|
* @code
|
||||||
|
* UC_SLOT_ALLOC_DEF(my_allocator, sizeof foo, 1024)
|
||||||
|
* struct foo *foo = uc_slot_alloc(&my_allocator);
|
||||||
|
* if (foo == NULL) {
|
||||||
|
* // out of memory
|
||||||
|
* } else {
|
||||||
|
* .. use foo
|
||||||
|
* uc_slot_free(&my_allocator, foo);
|
||||||
|
* }
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* @param var_name Variable name for the allocator
|
||||||
|
* @param v slot_size Memory size allocated for each slot
|
||||||
|
* @param v num_slots Number of slots to reserve memory for
|
||||||
|
*/
|
||||||
|
#define UC_SLOT_ALLOC_DEF(var_name, slot_size_, num_slots_) \
|
||||||
|
struct {\
|
||||||
|
uc_bv_integer bitmap[UC_BV_LEN(num_slots_)]; \
|
||||||
|
uint8_t memory[num_slots_ * slot_size_] __attribute__((aligned)); \
|
||||||
|
} var_name ## _memory = { \
|
||||||
|
}; \
|
||||||
|
UCSlotAlloc var_name = { \
|
||||||
|
.slot_size = slot_size_, \
|
||||||
|
.num_slots = num_slots_, \
|
||||||
|
.bitmap = UC_BV_STATIC_INIT(var_name ## _memory.bitmap), \
|
||||||
|
.slots = var_name ## _memory.memory \
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Similar to UC_SLOT_ALLOC_DEF but allows you to specify the backing memory that must
|
||||||
|
* be atleast as large as num_slots * slot_size. Note that an array of num_slots * slot_size
|
||||||
|
* bits is also allocated for the bitmap with this definition
|
||||||
|
*/
|
||||||
|
#define UC_SLOT_ALLOC_DEF_EX(var_name, slot_size_, num_slots_, memory) \
|
||||||
|
uc_bv_integer var_name ## _bitmap[UC_BV_LEN(num_slots_)] = {}; \
|
||||||
|
UCSlotAlloc var_name = { \
|
||||||
|
.slot_size = slot_size_, \
|
||||||
|
.num_slots = num_slots_, \
|
||||||
|
.bitmap = UC_BV_STATIC_INIT(var_name ## _bitmap), \
|
||||||
|
.slots = memory \
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Allocate a memory slot
|
||||||
|
*
|
||||||
|
* @param sa The allocator to allocate from
|
||||||
|
* @return A pointer to the memory slot that's sa.slot_size big, or NULL if
|
||||||
|
* all slots are allocated
|
||||||
|
*/
|
||||||
|
void *uc_slot_alloc(UCSlotAlloc *sa);
|
||||||
|
|
||||||
|
|
||||||
|
/** Free a memory slot previously returned from uc_slot_alloc()
|
||||||
|
*
|
||||||
|
* @param sa The allocator to free from.
|
||||||
|
* @param slot The memory slot to free. Passing a NULL pointer is undefined behavior
|
||||||
|
*/
|
||||||
|
void uc_slot_free(UCSlotAlloc *restrict sa, void *restrict slot);
|
||||||
|
|
||||||
|
/** uc_slot_free() where the slot can be a NULL pointer */
|
||||||
|
#define uc_slot_free_safe(sa, slot) \
|
||||||
|
do { \
|
||||||
|
if (slot != NULL) { \
|
||||||
|
uc_slot_free(sa, slot); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
// int i;
|
// int i;
|
||||||
// struct bar zap;
|
// struct bar zap;
|
||||||
//};
|
//};
|
||||||
// ...
|
// ...
|
||||||
//struct bar *p = ..; //the local p is a pointer to
|
//struct bar *p = ..; //the local p is a pointer to
|
||||||
//a 'zap' member inside a struct foo.
|
//a 'zap' member inside a struct foo.
|
||||||
//give us the struct foo*:
|
//give us the struct foo*:
|
||||||
@@ -55,7 +55,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if x is a power of 2
|
* Test if x is a power of 2
|
||||||
*
|
*
|
||||||
* @param x value, must be an unsigned type
|
* @param x value, must be an unsigned type
|
||||||
* @return 1 if x is a power of 20, 0 if it is not
|
* @return 1 if x is a power of 20, 0 if it is not
|
||||||
*/
|
*/
|
||||||
@@ -90,7 +90,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
|||||||
*
|
*
|
||||||
* @param x numerator, must be positive
|
* @param x numerator, must be positive
|
||||||
* @param y denominator
|
* @param y denominator
|
||||||
* @return x/y rounded up
|
* @return x/y rounded up
|
||||||
*/
|
*/
|
||||||
#define UC_DIV_ROUND_UP(x, y) (((x) + ((y) - 1))/(y))
|
#define UC_DIV_ROUND_UP(x, y) (((x) + ((y) - 1))/(y))
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \
|
|||||||
* @param y denominator
|
* @param y denominator
|
||||||
* @return x rounded up to nearest multiple of y
|
* @return x rounded up to nearest multiple of y
|
||||||
*/
|
*/
|
||||||
#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP((x), (y)) * (y))
|
#define UC_ROUND_UP(x, y) (UC_DIV_ROUND_UP((x), (y)) * (y))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Round x down to nearest multiple of y
|
* Round x down to nearest multiple of y
|
||||||
|
|||||||
+1
-1
@@ -44,7 +44,7 @@ struct UCBitVec *uc_bv_new(size_t nbits)
|
|||||||
|
|
||||||
void uc_bv_free(struct UCBitVec *v)
|
void uc_bv_free(struct UCBitVec *v)
|
||||||
{
|
{
|
||||||
if (v) {
|
if (likely(v != NULL)) {
|
||||||
free(v);
|
free(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ucore/bitvec.h"
|
||||||
|
#include "ucore/slot_allocator.h"
|
||||||
|
|
||||||
|
void *uc_slot_alloc(UCSlotAlloc *sa)
|
||||||
|
{
|
||||||
|
int free_slot = uc_bv_find_first_zero(&sa->bitmap);
|
||||||
|
if (free_slot < 0) {
|
||||||
|
return NULL;
|
||||||
|
} else if ((size_t)free_slot >= sa->num_slots) { // bit vector may have more bits than slots
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uc_bv_set_bit(&sa->bitmap, free_slot);
|
||||||
|
|
||||||
|
return sa->slots + free_slot * sa->slot_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uc_slot_free(UCSlotAlloc *restrict sa, void *restrict slot)
|
||||||
|
{
|
||||||
|
assert((uint8_t *)slot >= sa->slots);
|
||||||
|
int slot_index = ((uint8_t *)slot - sa->slots) / sa->slot_size;
|
||||||
|
assert((size_t)slot_index < sa->num_slots);
|
||||||
|
uc_bv_clr_bit(&sa->bitmap, slot_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
|
||||||
|
UC_SLOT_ALLOC_DEF(sa, 24, 1)
|
||||||
|
|
||||||
|
void *p1 = uc_slot_alloc(&sa);
|
||||||
|
printf("%p\n", &sa_memory.memory[0]);
|
||||||
|
printf("%p\n", p1);
|
||||||
|
|
||||||
|
void *p2 = uc_slot_alloc(&sa);
|
||||||
|
printf("%p\n", p2);
|
||||||
|
uc_slot_free(&sa, p1);
|
||||||
|
|
||||||
|
p2 = uc_slot_alloc(&sa);
|
||||||
|
printf("%p\n", p2);
|
||||||
|
|
||||||
|
printf("__malloc__\n");
|
||||||
|
void *v = malloc(24 * (1<<16));
|
||||||
|
UC_SLOT_ALLOC_DEF_EX(sa2, 24, (1<<16), v)
|
||||||
|
char *v2 = NULL;
|
||||||
|
for (int i = 0; i < 1<<16; i++) {
|
||||||
|
char *c = uc_slot_alloc(&sa2);
|
||||||
|
if (c == NULL) {
|
||||||
|
printf("uc_slot_alloc failed at %d\n", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*c = i;
|
||||||
|
if (i == 0) {
|
||||||
|
v2 = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = (1<<16) -1 ; i >= 0; i--) {
|
||||||
|
uc_slot_free(&sa2, v2 + 24*i);
|
||||||
|
}
|
||||||
|
free(v);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user