spaceship: add defragmentation and make sub-allocations optional

This commit is contained in:
Shiz 2020-04-14 03:31:40 +02:00
parent f7c6de4679
commit c0973f37c5
2 changed files with 93 additions and 5 deletions

View File

@ -1,12 +1,15 @@
#include <string.h>
#include "spaceship.h"
void spaceship_init(void *p, size_t size)
{
struct spaceship_chunk *chunk = p;
chunk->ssc_base = size;
chunk->ssc_size = size;
chunk->ssc_flags = SPACESHIP_FLAG_LAST;
#if SPACESHIP_WITH_SUB
chunk->ssc_base = size;
#endif
#if SPACESHIP_WITH_PARENT
chunk->ssc_parent = 0;
#endif
@ -55,7 +58,9 @@ void *spaceship_alloc(void *p, size_t size)
}
}
/* this chunk is now in use */
#if SPACESHIP_WITH_SUB
chunk->ssc_base = chunk->ssc_size;
#endif
chunk->ssc_flags |= SPACESHIP_FLAG_USED;
return chunk;
}
@ -86,6 +91,7 @@ void spaceship_free(struct spaceship_chunk *chunk)
}
}
#if SPACESHIP_WITH_SUB
int spaceship_init_sub(struct spaceship_chunk *chunk, size_t base_size)
{
size_t div_size = chunk->ssc_size - base_size;
@ -101,3 +107,65 @@ int spaceship_init_sub(struct spaceship_chunk *chunk, size_t base_size)
#endif
return 1;
}
#endif
void spaceship_defrag(struct spaceship_chunk *unused)
{
#if SPACESHIP_WITH_PREV
size_t prev_size = 0;
#endif
for (;;) {
/* find first unused chunk */
while (unused && unused->ssc_flags & SPACESHIP_FLAG_USED) {
unused = spaceship_get_next(unused);
}
if (!unused) {
break;
}
#if SPACESHIP_WITH_PREV
prev_size = unused->ssc_prev;
#endif
/* find used chunk after */
struct spaceship_chunk *used = spaceship_get_next_sibling(unused);
if (!used) {
break;
}
size_t unused_size = (uintptr_t)used - (uintptr_t)unused;
/* find chain length of used chunks */
struct spaceship_chunk *last, *end = used;
do {
last = end;
end = spaceship_get_next(end);
} while (end && end->ssc_flags & SPACESHIP_FLAG_USED);
/* move used chunk up front */
end = (struct spaceship_chunk *)((uintptr_t)last + spaceship_get_size(last));
size_t used_size = (uintptr_t)end - (uintptr_t)used;
memmove(unused, used, used_size);
/* fixup and defrag children */
#if SPACESHIP_WITH_PREV
unused->ssc_prev = prev_size;
#endif
uint8_t flags;
end = (struct spaceship_chunk *)((intptr_t)unused + used_size);
for (last = unused; last != end; last = spaceship_get_next(last)) {
flags = last->ssc_flags;
last->ssc_flags &= ~SPACESHIP_FLAG_LAST;
#if SPACESHIP_WITH_SUB
spaceship_defrag(spaceship_get_sub(last));
#endif
#if SPACESHIP_WITH_PARENT
last->ssc_parent -= unused_size;
#endif
}
/* create unused chunk at end */
spaceship_init(end, unused_size);
end->ssc_flags = flags;
unused = end;
}
}

View File

@ -7,7 +7,8 @@
#include <stdint.h>
#include <stddef.h>
#define SPACESHIP_WITH_PARENT 1
#define SPACESHIP_WITH_SUB 1
#define SPACESHIP_WITH_PARENT 1 && SPACESHIP_WITH_SUB
#define SPACESHIP_WITH_PREV 1
@ -19,7 +20,10 @@ enum spaceship_flag
struct spaceship_chunk
{
size_t ssc_base, ssc_size;
size_t ssc_size;
#if SPACESHIP_WITH_SUB
size_t ssc_base;
#endif
#if SPACESHIP_WITH_PARENT
ptrdiff_t ssc_parent;
#endif
@ -36,12 +40,12 @@ struct spaceship_chunk
/* init spaceship static memory chunk */
void spaceship_init(void *chunk, size_t size);
/* init sub-allocation space, leaving `base_size` bytes for the base structure */
int spaceship_init_sub(struct spaceship_chunk *chunk, size_t base_size);
/* allocate `size` bytes in chunk */
void *spaceship_alloc(void *chunk, size_t size);
/* free previously-allocated bytes */
void spaceship_free(struct spaceship_chunk *chunk);
/* defragment chunk. only do this if there are no active pointers. */
void spaceship_defrag(struct spaceship_chunk *chunk);
static inline size_t spaceship_get_size(struct spaceship_chunk *chunk)
{
@ -51,6 +55,19 @@ static inline size_t spaceship_get_size(struct spaceship_chunk *chunk)
return chunk->ssc_size;
}
#if SPACESHIP_WITH_SUB
/* init sub-allocation space, leaving `base_size` bytes for the base structure */
int spaceship_init_sub(struct spaceship_chunk *chunk, size_t base_size);
static inline size_t spaceship_get_sub_size(struct spaceship_chunk *chunk)
{
if (!chunk || !(chunk->ssc_flags & SPACESHIP_FLAG_USED)) {
return 0;
}
return chunk->ssc_size - chunk->ssc_base;
}
#endif
/*
* tree features
@ -92,6 +109,8 @@ static inline void *spaceship_get_next_sibling(struct spaceship_chunk *chunk)
return spaceship_get_first_used(spaceship_get_next(chunk));
}
#if SPACESHIP_WITH_SUB
/* get sub-allocation chunk */
static inline struct spaceship_chunk *spaceship_get_sub(struct spaceship_chunk *chunk)
{
@ -112,6 +131,7 @@ static inline void *spaceship_get_last_child(struct spaceship_chunk *chunk)
{
return spaceship_get_last_used(spaceship_get_sub(chunk));
}
#endif
#if SPACESHIP_WITH_PARENT