summaryrefslogtreecommitdiff
path: root/mem/framer.c
diff options
context:
space:
mode:
Diffstat (limited to 'mem/framer.c')
-rw-r--r--mem/framer.c63
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