95 lines
2.6 KiB
C
95 lines
2.6 KiB
C
/**
|
|
* \file
|
|
* \brief Very simple slab allocator.
|
|
*
|
|
* This file implements a simple slab allocator. It allocates blocks of a fixed
|
|
* size from one contiguous memory region.
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2008, 2009, 2010, ETH Zurich.
|
|
* All rights reserved.
|
|
*
|
|
* This file is distributed under the terms in the attached LICENSE file.
|
|
* If you do not find this file, copies can be found by writing to:
|
|
* ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
|
|
*/
|
|
|
|
#include <aos/aos.h>
|
|
#include <aos/simpleslab.h>
|
|
#include <aos/static_assert.h>
|
|
|
|
struct simpleblock_head {
|
|
struct simpleblock_head *next;///< Pointer to next block in free list
|
|
};
|
|
|
|
STATIC_ASSERT_SIZEOF(struct simpleblock_head, SIMPLESLAB_BLOCK_HDRSIZE);
|
|
|
|
/**
|
|
* \brief Initialise a new slab allocator
|
|
*
|
|
* \param slabs Pointer to slab allocator instance, to be filled-in
|
|
* \param blocksize Size of blocks to be allocated by this allocator
|
|
* \param buf Buffer from which to allocate blocks
|
|
* \param buflen Size of buf
|
|
*/
|
|
void simpleslab_init(struct simpleslab_allocator *slabs, size_t blocksize, void *buf, size_t buflen)
|
|
{
|
|
assert(blocksize >= sizeof(struct simpleblock_head));
|
|
|
|
/* calculate number of blocks in buffer */
|
|
assert(buflen / blocksize <= UINT32_MAX);
|
|
slabs->free = slabs->total = buflen / blocksize;
|
|
assert(slabs->total > 0);
|
|
assert(buf != NULL);
|
|
|
|
slabs->start = buf;
|
|
slabs->end = buf + buflen;
|
|
|
|
/* enqueue blocks in freelist */
|
|
struct simpleblock_head *bh = slabs->blocks = buf;
|
|
for (uint32_t i = slabs->total; i > 1; i--) {
|
|
buf = (char *)buf + blocksize;
|
|
bh->next = buf;
|
|
bh = buf;
|
|
}
|
|
bh->next = NULL;
|
|
}
|
|
|
|
/**
|
|
* \brief Allocate a new block from the slab allocator
|
|
*
|
|
* \param slabs Pointer to slab allocator instance
|
|
*
|
|
* \returns Pointer to block on success, NULL on error (out of blocks)
|
|
*/
|
|
void *simpleslab_alloc(struct simpleslab_allocator *slabs)
|
|
{
|
|
struct simpleblock_head *bh = slabs->blocks;
|
|
if (bh == NULL) return NULL;
|
|
slabs->blocks = bh->next;
|
|
slabs->free--;
|
|
|
|
return bh;
|
|
}
|
|
|
|
/**
|
|
* \brief Free a block to the slab allocator
|
|
*
|
|
* \param slabs Pointer to slab allocator instance
|
|
* \param block Pointer to block previously returned by #slab_alloc
|
|
*/
|
|
void simpleslab_free(struct simpleslab_allocator *slabs, void *block)
|
|
{
|
|
assert(block != NULL);
|
|
assert(slabs->start <= block && block < slabs->end);
|
|
|
|
struct simpleblock_head *bh = (struct simpleblock_head *)block;
|
|
|
|
/* re-enqueue in slab's free list */
|
|
bh->next = slabs->blocks;
|
|
slabs->blocks = bh;
|
|
slabs->free++;
|
|
assert(slabs->free <= slabs->total);
|
|
}
|