From: Michael D. Lowis Date: Tue, 31 Mar 2015 02:12:45 +0000 (-0400) Subject: Added segment module for allocation of fixed size blocks X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=19fc982b0a91b6a3afee2f7087f3e37bc49b40ce;p=archive%2Fatc.git Added segment module for allocation of fixed size blocks --- diff --git a/source/runtime/segment.c b/source/runtime/segment.c new file mode 100644 index 0000000..429bcf9 --- /dev/null +++ b/source/runtime/segment.c @@ -0,0 +1,49 @@ +/** + @file segment.c + @brief See header for details +*/ +#include "segment.h" +#include +#include + +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 index 0000000..3b82e24 --- /dev/null +++ b/source/runtime/segment.h @@ -0,0 +1,28 @@ +/** + @file segment.h + @brief TODO: Describe this file +*/ +#ifndef SEGMENT_H +#define SEGMENT_H + +#include +#include + +#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 */ diff --git a/tests/main.c b/tests/main.c index 630952a..1a33e6e 100644 --- a/tests/main.c +++ b/tests/main.c @@ -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 index 0000000..b1fbbe5 --- /dev/null +++ b/tests/test_segment.c @@ -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); + } +}