]> git.mdlowis.com Git - archive/atc.git/commitdiff
Added segment module for allocation of fixed size blocks
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 31 Mar 2015 02:12:45 +0000 (22:12 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 31 Mar 2015 02:12:45 +0000 (22:12 -0400)
source/runtime/segment.c [new file with mode: 0644]
source/runtime/segment.h [new file with mode: 0644]
tests/main.c
tests/test_segment.c [new file with mode: 0644]

diff --git a/source/runtime/segment.c b/source/runtime/segment.c
new file mode 100644 (file)
index 0000000..429bcf9
--- /dev/null
@@ -0,0 +1,49 @@
+/**
+  @file segment.c
+  @brief See header for details
+*/
+#include "segment.h"
+#include <stdlib.h>
+#include <string.h>
+
+static uint8_t get_free_index(int32_t bitmap) {
+    static const uint8_t lookup[32] = {
+        0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+        31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+    };
+    return lookup[((uint32_t)((bitmap & -bitmap) * 0x077CB531U)) >> 27];
+}
+
+segment_t* segment_create(uintptr_t blocksize)
+{
+    segment_t* seg = (segment_t*)malloc(sizeof(segment_t));
+    seg->blocksize = blocksize;
+    seg->start = (uintptr_t*)malloc(sizeof(uintptr_t) * blocksize * NUM_BLOCKS);
+    seg->end = (seg->start + (blocksize * NUM_BLOCKS));
+    memset(seg->blockmap, 0xFFu, sizeof(seg->blockmap));
+    return seg;
+}
+
+void segment_destroy(segment_t* seg)
+{
+    free(seg->start);
+    free(seg);
+}
+
+void* segment_alloc(segment_t* seg) {
+    void* obj = NULL;
+    /* Check if the segment has any free blocks */
+    if (0u != seg->blockmap[0]) {
+        /* Find the free block */
+        uint8_t root_idx   = get_free_index(seg->blockmap[0]);
+        uint8_t submap_idx = get_free_index(seg->blockmap[root_idx + 1]);
+        /* Calculate it's address */
+        uintptr_t offset = seg->blocksize * ((root_idx * 16u) + submap_idx);
+        obj = seg->start + offset;
+        /* Mark it allocated */
+        seg->blockmap[root_idx + 1] &= ~(1u << submap_idx);
+        if (0u == seg->blockmap[root_idx + 1])
+            seg->blockmap[0] &= ~(1u << root_idx);
+    }
+    return obj;
+}
diff --git a/source/runtime/segment.h b/source/runtime/segment.h
new file mode 100644 (file)
index 0000000..3b82e24
--- /dev/null
@@ -0,0 +1,28 @@
+/**
+  @file segment.h
+  @brief TODO: Describe this file
+*/
+#ifndef SEGMENT_H
+#define SEGMENT_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define NUM_BLOCKS    (256u)
+
+#define BLOCKMAP_SIZE (sizeof(uint16_t) + (NUM_BLOCKS / sizeof(uint16_t)))
+
+typedef struct {
+    uintptr_t blocksize;
+    uintptr_t* start;
+    uintptr_t* end;
+    uint16_t blockmap[BLOCKMAP_SIZE];
+} segment_t;
+
+segment_t* segment_create(uintptr_t blocksize);
+
+void segment_destroy(segment_t* seg);
+
+void* segment_alloc(segment_t* seg);
+
+#endif /* SEGMENT_H */
index 630952a6e6e07f085f98a88fb6081cf539cd0f43..1a33e6e9fbfba2d3a0f1f4b9acb0684f6e89f946 100644 (file)
@@ -4,5 +4,6 @@ int ATC_Main(int argc, char** argv) {
     (void)argc;
     (void)argv;
     RUN_EXTERN_TEST_SUITE(SplayTree);
+    RUN_EXTERN_TEST_SUITE(Segment);
     return PRINT_TEST_RESULTS();
 }
diff --git a/tests/test_segment.c b/tests/test_segment.c
new file mode 100644 (file)
index 0000000..b1fbbe5
--- /dev/null
@@ -0,0 +1,77 @@
+#include "atf.h"
+#include "segment.h"
+
+TEST_SUITE(Segment) {
+    /* Verify: segment_create
+     *************************************************************************/
+    TEST(Verify_Create_allocates_and_initializes_a_segment) {
+        int i;
+        segment_t* seg = segment_create(2u);
+        CHECK(seg->blocksize == 2u);
+        CHECK(seg->start != NULL);
+        CHECK(seg->end == (seg->start + (NUM_BLOCKS * 2u)));
+        for (i = 0; i < BLOCKMAP_SIZE; i++)
+            CHECK(seg->blockmap[i] == UINT16_MAX);
+        segment_destroy(seg);
+    }
+
+    /* Verify: segment_alloc
+     *************************************************************************/
+    TEST(Verify_alloc_allocates_the_first_block) {
+        segment_t* seg = segment_create(2u);
+        void* obj = segment_alloc(seg);
+        CHECK(obj == seg->start);
+        segment_destroy(seg);
+    }
+
+    TEST(Verify_alloc_allocates_the_second_block) {
+        segment_t* seg = segment_create(2u);
+        seg->blockmap[1] = UINT16_MAX-1;
+        void* obj = segment_alloc(seg);
+        CHECK(obj == &seg->start[2]);
+        segment_destroy(seg);
+    }
+
+    TEST(Verify_alloc_allocates_the_sixteenth_block) {
+        segment_t* seg = segment_create(2u);
+        seg->blockmap[0] = UINT16_MAX-1;
+        seg->blockmap[1] = 0u;
+        void* obj = segment_alloc(seg);
+        CHECK(obj == &seg->start[16*2]);
+        segment_destroy(seg);
+    }
+
+    TEST(Verify_alloc_allocates_blocks_consecutively) {
+        segment_t* seg = segment_create(2u);
+        void* obj1 = segment_alloc(seg);
+        void* obj2 = segment_alloc(seg);
+        void* obj3 = segment_alloc(seg);
+        CHECK(obj1 == &seg->start[0]);
+        CHECK(obj2 == &seg->start[2]);
+        CHECK(obj3 == &seg->start[4]);
+        CHECK(seg->blockmap[0] == UINT16_MAX);
+        CHECK(seg->blockmap[1] == UINT16_MAX-7u);
+        segment_destroy(seg);
+    }
+
+    TEST(Verify_alloc_allocates_blocks_consecutively_across_bitmap_boundaries) {
+        segment_t* seg = segment_create(2u);
+        seg->blockmap[1] = 1 << 15;
+        void* obj1 = segment_alloc(seg);
+        void* obj2 = segment_alloc(seg);
+        CHECK(obj1 == &seg->start[2*15]);
+        CHECK(obj2 == &seg->start[2*16]);
+        CHECK(seg->blockmap[0] == UINT16_MAX-1);
+        CHECK(seg->blockmap[1] == 0u);
+        CHECK(seg->blockmap[2] == UINT16_MAX-1);
+        segment_destroy(seg);
+    }
+
+    TEST(Verify_alloc_returns_NULL_if_no_blocks_available) {
+        segment_t* seg = segment_create(2u);
+        seg->blockmap[0] = 0;
+        void* obj = segment_alloc(seg);
+        CHECK(obj == NULL);
+        segment_destroy(seg);
+    }
+}