diff options
Diffstat (limited to 'examples/c_files/memmgr.c')
-rw-r--r-- | examples/c_files/memmgr.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/examples/c_files/memmgr.c b/examples/c_files/memmgr.c new file mode 100644 index 0000000..d9bc290 --- /dev/null +++ b/examples/c_files/memmgr.c @@ -0,0 +1,206 @@ +//---------------------------------------------------------------- +// Statically-allocated memory manager +// +// by Eli Bendersky (eliben@gmail.com) +// +// This code is in the public domain. +//---------------------------------------------------------------- +#include "memmgr.h" + +typedef ulong Align; + +union mem_header_union +{ + struct + { + // Pointer to the next block in the free list + // + union mem_header_union* next; + + // Size of the block (in quantas of sizeof(mem_header_t)) + // + ulong size; + } s; + + // Used to align headers in memory to a boundary + // + Align align_dummy; +}; + +typedef union mem_header_union mem_header_t; + +// Initial empty list +// +static mem_header_t base; + +// Start of free list +// +static mem_header_t* freep = 0; + +// Static pool for new allocations +// +static byte pool[POOL_SIZE] = {0}; +static ulong pool_free_pos = 0; + + +void memmgr_init() +{ + base.s.next = 0; + base.s.size = 0; + freep = 0; + pool_free_pos = 0; +} + + +static mem_header_t* get_mem_from_pool(ulong nquantas) +{ + ulong total_req_size; + + mem_header_t* h; + + if (nquantas < MIN_POOL_ALLOC_QUANTAS) + nquantas = MIN_POOL_ALLOC_QUANTAS; + + total_req_size = nquantas * sizeof(mem_header_t); + + if (pool_free_pos + total_req_size <= POOL_SIZE) + { + h = (mem_header_t*) (pool + pool_free_pos); + h->s.size = nquantas; + memmgr_free((void*) (h + 1)); + pool_free_pos += total_req_size; + } + else + { + return 0; + } + + return freep; +} + + +// Allocations are done in 'quantas' of header size. +// The search for a free block of adequate size begins at the point 'freep' +// where the last block was found. +// If a too-big block is found, it is split and the tail is returned (this +// way the header of the original needs only to have its size adjusted). +// The pointer returned to the user points to the free space within the block, +// which begins one quanta after the header. +// +void* memmgr_alloc(ulong nbytes) +{ + mem_header_t* p; + mem_header_t* prevp; + + // Calculate how many quantas are required: we need enough to house all + // the requested bytes, plus the header. The -1 and +1 are there to make sure + // that if nbytes is a multiple of nquantas, we don't allocate too much + // + ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1; + + // First alloc call, and no free list yet ? Use 'base' for an initial + // denegerate block of size 0, which points to itself + // + if ((prevp = freep) == 0) + { + base.s.next = freep = prevp = &base; + base.s.size = 0; + } + + for (p = prevp->s.next; ; prevp = p, p = p->s.next) + { + // big enough ? + if (p->s.size >= nquantas) + { + // exactly ? + if (p->s.size == nquantas) + { + // just eliminate this block from the free list by pointing + // its prev's next to its next + // + prevp->s.next = p->s.next; + } + else // too big + { + p->s.size -= nquantas; + p += p->s.size; + p->s.size = nquantas; + } + + freep = prevp; + return (void*) (p + 1); + } + // Reached end of free list ? + // Try to allocate the block from the pool. If that succeeds, + // get_mem_from_pool adds the new block to the free list and + // it will be found in the following iterations. If the call + // to get_mem_from_pool doesn't succeed, we've run out of + // memory + // + else if (p == freep) + { + if ((p = get_mem_from_pool(nquantas)) == 0) + { + #ifdef DEBUG_MEMMGR_FATAL + printf("!! Memory allocation failed !!\n"); + #endif + return 0; + } + } + } +} + + +// Scans the free list, starting at freep, looking the the place to insert the +// free block. This is either between two existing blocks or at the end of the +// list. In any case, if the block being freed is adjacent to either neighbor, +// the adjacent blocks are combined. +// +void memmgr_free(void* ap) +{ + mem_header_t* block; + mem_header_t* p; + + // acquire pointer to block header + block = ((mem_header_t*) ap) - 1; + + // Find the correct place to place the block in (the free list is sorted by + // address, increasing order) + // + for (p = freep; !(block > p && block < p->s.next); p = p->s.next) + { + // Since the free list is circular, there is one link where a + // higher-addressed block points to a lower-addressed block. + // This condition checks if the block should be actually + // inserted between them + // + if (p >= p->s.next && (block > p || block < p->s.next)) + break; + } + + // Try to combine with the higher neighbor + // + if (block + block->s.size == p->s.next) + { + block->s.size += p->s.next->s.size; + block->s.next = p->s.next->s.next; + } + else + { + block->s.next = p->s.next; + } + + // Try to combine with the lower neighbor + // + if (p + p->s.size == block) + { + p->s.size += block->s.size; + p->s.next = block->s.next; + } + else + { + p->s.next = block; + } + + freep = p; +} |