futhark-0.9.1: rts/c/free_list.h
/* Free list management */
/* An entry in the free list. May be invalid, to avoid having to
deallocate entries as soon as they are removed. There is also a
tag, to help with memory reuse. */
struct free_list_entry {
size_t size;
fl_mem_t mem;
const char *tag;
unsigned char valid;
};
struct free_list {
struct free_list_entry *entries; // Pointer to entries.
int capacity; // Number of entries.
int used; // Number of valid entries.
};
void free_list_init(struct free_list *l) {
l->capacity = 30; // Picked arbitrarily.
l->used = 0;
l->entries = malloc(sizeof(struct free_list_entry) * l->capacity);
for (int i = 0; i < l->capacity; i++) {
l->entries[i].valid = 0;
}
}
/* Remove invalid entries from the free list. */
void free_list_pack(struct free_list *l) {
int p = 0;
for (int i = 0; i < l->capacity; i++) {
if (l->entries[i].valid) {
l->entries[p] = l->entries[i];
p++;
}
}
// Now p == l->used.
l->entries = realloc(l->entries, l->used * sizeof(struct free_list_entry));
l->capacity = l->used;
}
void free_list_destroy(struct free_list *l) {
assert(l->used == 0);
free(l->entries);
}
int free_list_find_invalid(struct free_list *l) {
int i;
for (i = 0; i < l->capacity; i++) {
if (!l->entries[i].valid) {
break;
}
}
return i;
}
void free_list_insert(struct free_list *l, size_t size, fl_mem_t mem, const char *tag) {
int i = free_list_find_invalid(l);
if (i == l->capacity) {
// List is full; so we have to grow it.
int new_capacity = l->capacity * 2 * sizeof(struct free_list_entry);
l->entries = realloc(l->entries, new_capacity);
for (int j = 0; j < l->capacity; j++) {
l->entries[j+l->capacity].valid = 0;
}
l->capacity *= 2;
}
// Now 'i' points to the first invalid entry.
l->entries[i].valid = 1;
l->entries[i].size = size;
l->entries[i].mem = mem;
l->entries[i].tag = tag;
l->used++;
}
/* Find and remove a memory block of at least the desired size and
tag. Returns 0 on success. */
int free_list_find(struct free_list *l, const char *tag, size_t *size_out, fl_mem_t *mem_out) {
int i;
for (i = 0; i < l->capacity; i++) {
if (l->entries[i].valid && l->entries[i].tag == tag) {
l->entries[i].valid = 0;
*size_out = l->entries[i].size;
*mem_out = l->entries[i].mem;
l->used--;
return 0;
}
}
return 1;
}
/* Remove the first block in the free list. Returns 0 if a block was
removed, and nonzero if the free list was already empty. */
int free_list_first(struct free_list *l, fl_mem_t *mem_out) {
for (int i = 0; i < l->capacity; i++) {
if (l->entries[i].valid) {
l->entries[i].valid = 0;
*mem_out = l->entries[i].mem;
l->used--;
return 0;
}
}
return 1;
}