diff options
Diffstat (limited to 'mem/framer.c')
| -rw-r--r-- | mem/framer.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/mem/framer.c b/mem/framer.c new file mode 100644 index 0000000..9a66feb --- /dev/null +++ b/mem/framer.c @@ -0,0 +1,63 @@ +#include "framer.h" + +/* Installs a MemFramer at the specified address */ +MemFramer *mem_framer_install(void *addr, usize end, uint blksz) { + MemFramer *self = addr; + usize selfend = (usize)(self + 1); + usize next = ALIGN_UP(selfend, blksz); + + *self = (MemFramer) { + .allocator = (MemAllocator) { + .alloc = mem_framer_alloc, + .free = mem_framer_free + }, + .next = next, + .end = end, + .blksz = blksz + }; + + return self; +} + +/* Allocates a frame */ +void *mem_framer_alloc(MemAllocator *inner, usize n) { + /* When allocating a frame, we have two paths: + 1. The freelist is not empty: give away + the last freed frame + 2. The freelist is empty: bump away the next + frame (pointed at by the next member) + The alloc must fail the freelist is empty and that + the next is beyond the end of the region */ + + MemFramer *self = (MemFramer*)inner; + + /* The implementation does not support more than + one frame */ + if (n == 0 || n > self->blksz) + return nil; + + void *ptr = nil; + + if (self->free) { + ptr = self->free; + self->free = self->free->next; + } else if (self->next + self->blksz <= self->end) { + ptr = (void*)self->next; + self->next += self->blksz; + } + + return ptr; +} + +/* Frees a frame */ +void mem_framer_free(MemAllocator *inner, void *ptr) { + /* NOTE: this implementation does make the assumption + that the given pointer is the base of the allocated + region without correction */ + + MemFramer *self = (MemFramer*)inner; + + MemFramerFreed *freed = ptr; + freed->next = self->free; + self->free = freed; +}
\ No newline at end of file |
