aos/lib/aos/simpleslab.c
2022-05-27 19:11:22 +02:00

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);
}