ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_slab.c File Reference

Fixed-cell slab allocator implementation (Layer 0, #147). More...

#include "ra8_slab.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
Include dependency graph for ra8_slab.c:

Go to the source code of this file.

Functions

static uint32_t internal_slab_next (const ra8_slab_t *slab, uint32_t idx)
 Read the freelist next-index stored in free cell idx.
static void internal_slab_set_next (ra8_slab_t *slab, uint32_t idx, uint32_t next)
 Write the freelist next-index into cell idx.
ra8_err_t ra8_slab_init (ra8_slab_t *slab, void *buffer, uint32_t buffer_bytes, uint32_t cell_bytes)
 Initialise a slab over a caller-owned buffer.
ra8_err_t ra8_slab_alloc (ra8_slab_t *slab, void **out_cell)
 Allocate one cell from the slab (O(1)).
ra8_err_t ra8_slab_free (ra8_slab_t *slab, void *cell)
 Return a previously-allocated cell to the slab (O(1)).
ra8_err_t ra8_slab_stats (const ra8_slab_t *slab, uint32_t *out_free, uint32_t *out_total)
 Report the slab's free / total cell counts.

Variables

static const char *const s_tag = "ra8_slab"
 Module log tag.

Detailed Description

Fixed-cell slab allocator implementation (Layer 0, #147).

Tag
[Ring 2 / Core] {World: NS}

The freelist is intrusive: each free cell stores, in its first 4 bytes, the index of the next free cell (k_ra8_slab_nil terminates). memcpy is used to read/write that index so the access is alignment- and aliasing-safe regardless of the cell's payload type.

Definition in file ra8_slab.c.

Function Documentation

◆ internal_slab_next()

uint32_t internal_slab_next ( const ra8_slab_t * slab,
uint32_t idx )
static

Read the freelist next-index stored in free cell idx.

Loads the 4-byte next-index threaded through the free cell at idx via memcpy (alignment-safe).

Parameters
[in]slabInitialised slab.
[in]idxIndex of a free cell (< slab->cell_count).
Returns
The stored next-cell index, or k_ra8_slab_nil at the list tail.
Return values
k_ra8_slab_nilCell idx is the tail of the freelist.
Precondition
slab and slab->base are non-NULL.
idx addresses a cell currently on the freelist.
Postcondition
No state is modified.
The returned value is a valid index or k_ra8_slab_nil.
Note
Not thread-safe.
Since
0.1.0

Definition at line 52 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_bytes, memcpy(), and RA8_INTERNAL.

Referenced by ra8_slab_alloc().

◆ internal_slab_set_next()

void internal_slab_set_next ( ra8_slab_t * slab,
uint32_t idx,
uint32_t next )
static

Write the freelist next-index into cell idx.

Stores the 4-byte next index into the cell at idx via memcpy (alignment-safe), threading it onto the freelist.

Parameters
[in,out]slabInitialised slab.
[in]idxIndex of the cell to update (< slab->cell_count).
[in]nextNext-cell index to store (or k_ra8_slab_nil).
Returns
Nothing.
Precondition
slab and slab->base are non-NULL.
idx addresses a cell inside the slab.
Postcondition
Cell idx holds next as its freelist link.
No other state is modified.
Note
Not thread-safe.
Since
0.1.0

Definition at line 80 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_bytes, memcpy(), and RA8_INTERNAL.

Referenced by ra8_slab_free(), and ra8_slab_init().

◆ ra8_slab_alloc()

ra8_err_t ra8_slab_alloc ( ra8_slab_t * slab,
void ** out_cell )
nodiscard

Allocate one cell from the slab (O(1)).

Parameters
[in]slabInitialised slab.
[out]out_cellReceives the cell pointer on success.
Returns
ra8_err_t Error code.
Return values
k_ra8_okA cell was handed out; *out_cell set.
k_ra8_err_null_ptrslab or out_cell was NULL.
k_ra8_err_no_memThe slab is exhausted (no free cell).
Precondition
slab was populated by ra8_slab_init.
out_cell is writable.
Postcondition
On success *out_cell points at cell_bytes of usable storage.
On success free_count decreased by one.
Note
Not thread-safe. The returned cell's contents are unspecified.
Since
0.1.0

Definition at line 111 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_bytes, ra8_slab_t::free_count, ra8_slab_t::free_head, internal_slab_next(), k_ra8_err_no_mem, k_ra8_ok, k_ra8_slab_nil, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by mem_run_slab().

◆ ra8_slab_free()

ra8_err_t ra8_slab_free ( ra8_slab_t * slab,
void * cell )
nodiscard

Return a previously-allocated cell to the slab (O(1)).

Parameters
[in]slabInitialised slab.
[in]cellA cell pointer previously returned by ra8_slab_alloc.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCell returned to the freelist.
k_ra8_err_null_ptrslab or cell was NULL.
k_ra8_err_invalid_argcell is outside the slab or not on a cell boundary.
Precondition
cell came from this slab and is not already free.
slab was populated by ra8_slab_init.
Postcondition
On success free_count increased by one and cell is reusable.
On any non-ok return the slab is unchanged.
Note
Not thread-safe. Double-free of an in-bounds cell is not detected (it corrupts the freelist); callers must not double-free.
Since
0.1.0

Definition at line 125 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_bytes, ra8_slab_t::cell_count, ra8_slab_t::free_count, ra8_slab_t::free_head, internal_slab_set_next(), k_ra8_err_invalid_arg, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by mem_run_slab().

◆ ra8_slab_init()

ra8_err_t ra8_slab_init ( ra8_slab_t * slab,
void * buffer,
uint32_t buffer_bytes,
uint32_t cell_bytes )
nodiscard

Initialise a slab over a caller-owned buffer.

Divides buffer into floor(buffer_bytes / cell_bytes) cells and threads every cell onto the freelist so all cells start free.

Parameters
[out]slabSlab state to populate (zero-initialised by caller).
[in]bufferBacking memory, 4-byte aligned, out-living the slab.
[in]buffer_bytesSize of buffer in bytes.
[in]cell_bytesBytes per cell (>= 4 and a multiple of 4).
Returns
ra8_err_t Error code.
Return values
k_ra8_okSlab ready; all cells free.
k_ra8_err_null_ptrslab or buffer was NULL.
k_ra8_err_invalid_sizecell_bytes < 4, not 4-aligned, or larger than buffer_bytes (zero cells).
Precondition
buffer is at least buffer_bytes and 4-byte aligned.
slab does not alias buffer.
Postcondition
On success slab->free_count == slab->cell_count >= 1.
On any non-ok return slab is left unmodified-usable (not bound).
Note
Not thread-safe.
Since
0.1.0

Definition at line 85 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_bytes, ra8_slab_t::cell_count, ra8_slab_t::free_count, ra8_slab_t::free_head, internal_slab_set_next(), k_ra8_err_invalid_size, k_ra8_ok, k_ra8_slab_align_bytes, k_ra8_slab_min_cell_bytes, k_ra8_slab_nil, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by mem_run_slab().

◆ ra8_slab_stats()

ra8_err_t ra8_slab_stats ( const ra8_slab_t * slab,
uint32_t * out_free,
uint32_t * out_total )
nodiscard

Report the slab's free / total cell counts.

Parameters
[in]slabInitialised slab.
[out]out_freeFree cell count (may be NULL).
[out]out_totalTotal cell count (may be NULL).
Returns
ra8_err_t Error code.
Return values
k_ra8_okCounters reported.
k_ra8_err_null_ptrslab was NULL.
Precondition
slab was populated by ra8_slab_init.
At least one output pointer is non-NULL to be useful.
Postcondition
On success the requested counters are written.
No slab state is mutated.
Note
Thread-safe with respect to a quiescent slab (pure read).
Since
0.1.0

Definition at line 149 of file ra8_slab.c.

References ra8_slab_t::base, ra8_slab_t::cell_count, ra8_slab_t::free_count, k_ra8_err_invalid_state, k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by mem_run_slab().

Variable Documentation

◆ s_tag

const char* const s_tag = "ra8_slab"
static

Module log tag.

Definition at line 29 of file ra8_slab.c.