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

The fixed decode arena that lets a protobuf codec run with no heap. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_c6link.h"
#include "ra8_c6link_internal.h"
Include dependency graph for ra8_c6link_arena.c:

Go to the source code of this file.

Enumerations

enum  ra8_c6link_arena_t : uint32_t {
  k_ra8_c6link_arena_align = 8U ,
  k_ra8_c6link_arena_mask = 7U
}
 Alignment the arena hands out blocks at. More...

Functions

void * priv_c6link_arena_alloc (void *ctx, size_t size)
 Take a block from the link's decode arena.
void priv_c6link_arena_free (void *ctx, void *pointer)
 Return a block to the link's decode arena.
void priv_c6link_arena_reset (ra8_c6link_t *link)
 Empty the link's decode arena.
void priv_c6link_arena_bind (ProtobufCAllocator *out, ra8_c6link_t *link)
 Bind an allocator descriptor to a link's arena.

Detailed Description

The fixed decode arena that lets a protobuf codec run with no heap.

Tag
[Ring 4 / PAL] {World: NS}

rpc__unpack() allocates: one block for the message, one per nested message, one per repeated field and one per binary field. This firmware has no heap – _sbrk is a strong symbol that reports a fatal error – so the codec is handed an allocator over a caller-supplied buffer instead.

A bump allocator is the right shape for it. Every allocation a decode makes is released by the matching rpc__free_unpacked(), and the RPC layer empties the arena immediately afterwards, so the peak requirement is one message rather than one run and no fragmentation can accumulate. That is what keeps the whole control plane inside NASA Power of 10 Rule 3: the only storage decision is the caller's single = {} array, made before the link opens.

The free row is not a no-op. protobuf-c unwinds its own partial work when a decode fails part-way, and those releases are strictly newest-first, so rolling the bump offset back when the freed block is the newest one reclaims exactly the space a failed decode would otherwise strand.

Since
0.1.0

Definition in file ra8_c6link_arena.c.

Enumeration Type Documentation

◆ ra8_c6link_arena_t

enum ra8_c6link_arena_t : uint32_t

Alignment the arena hands out blocks at.

protobuf-c stores uint64_t fields (WifiInitConfig::feature_caps is one) inside blocks it gets from this allocator, so eight-byte alignment is a correctness requirement on the target and not a performance choice.

Invariant
k_ra8_c6link_arena_align is a power of two, so the rounding mask below is exact.
Every returned block is aligned to it.
Example:
const uint32_t rounded = (want + k_ra8_c6link_arena_align - 1U) & ~mask;
See also
priv_c6link_arena_alloc
Since
0.1.0
Enumerator
k_ra8_c6link_arena_align 

Alignment, in bytes, of every block the arena hands out.

k_ra8_c6link_arena_mask 

k_ra8_c6link_arena_align minus one, as a rounding mask.

Definition at line 60 of file ra8_c6link_arena.c.

Function Documentation

◆ priv_c6link_arena_alloc()

void * priv_c6link_arena_alloc ( void * ctx,
size_t size )

Take a block from the link's decode arena.

The alloc row of the ::ProtobufCAllocator handed to the generated codec. Bumps a pointer through the caller-supplied arena, eight-byte aligned. There is no fallback to a heap: this firmware has none, and an over-request must fail the decode rather than fault.

Parameters
[in]ctxThe ra8_c6link_t whose arena to draw from; must be non-null.
[in]sizeBytes requested; zero yields a non-null zero-length block, which is what protobuf-c expects.
Returns
Pointer to the block, or null when the arena cannot serve it.
Return values
NULLThe arena is exhausted, or ctx was null.
Precondition
The link is open, so its arena pointer and size are valid.
The caller releases through priv_c6link_arena_free.
Postcondition
The bump offset advanced by the aligned size, or nothing changed.
arena_last names this block when the call succeeded.
Note
Not thread-safe; one link, one pump, one decode at a time.
Example:
ProtobufCAllocator a = { .alloc = priv_c6link_arena_alloc, ... };
See also
priv_c6link_arena_reset
Since
0.1.0

Definition at line 67 of file ra8_c6link_arena.c.

References ra8_c6link::arena, ra8_c6link::arena_bytes, ra8_c6link::arena_last, ra8_c6link::arena_used, k_ra8_c6link_arena_mask, and RA8_PRIV.

Referenced by priv_c6link_arena_bind().

◆ priv_c6link_arena_bind()

void priv_c6link_arena_bind ( ProtobufCAllocator * out,
ra8_c6link_t * link )

Bind an allocator descriptor to a link's arena.

Fills the ::ProtobufCAllocator the generated codec is handed. Passing null to the codec instead would select protobuf-c's default allocator, which calls malloc; in this firmware _sbrk is a strong symbol that reports a fatal error, so that path faults rather than failing.

Parameters
[out]outDescriptor to fill; must be non-null.
[in]linkLink whose arena backs it; must be non-null.
Returns
Nothing.
Precondition
link is open.
out outlives every decode it is passed to.
Postcondition
Both rows and the context of out are set.
No link state is modified.
Note
Safe from any context; it only assigns.
Example:
ProtobufCAllocator a;
See also
priv_c6link_arena_alloc
Since
0.1.0

Definition at line 116 of file ra8_c6link_arena.c.

References priv_c6link_arena_alloc(), priv_c6link_arena_free(), and RA8_PRIV.

Referenced by internal_mdl_take_accepted(), internal_mdl_take_cancelled(), internal_mdl_take_chunk(), and priv_c6link_rpc_consume().

◆ priv_c6link_arena_free()

void priv_c6link_arena_free ( void * ctx,
void * pointer )

Return a block to the link's decode arena.

The free row of the allocator. A bump arena cannot free out of order, but it can free the newest block: when pointer is the most recent allocation the bump offset rolls back to it, which is what turns the codec's own unwind-on-error path into genuinely reclaimed space rather than waste. Any other pointer is retained until priv_c6link_arena_reset runs, which the RPC layer does after every decode.

Parameters
[in]ctxThe ra8_c6link_t whose arena owns the block; null is ignored.
[in]pointerBlock to release; null is ignored.
Returns
Nothing.
Precondition
pointer came from priv_c6link_arena_alloc on the same link.
No other reference to the block survives the call.
Postcondition
The bump offset is unchanged or rolled back to pointer.
No memory outside the arena is touched.
Note
Not thread-safe, for the same reason as the allocator.
Example:
See also
priv_c6link_arena_alloc
Since
0.1.0

Definition at line 94 of file ra8_c6link_arena.c.

References ra8_c6link::arena, ra8_c6link::arena_last, ra8_c6link::arena_used, and RA8_PRIV.

Referenced by priv_c6link_arena_bind().

◆ priv_c6link_arena_reset()

void priv_c6link_arena_reset ( ra8_c6link_t * link)

Empty the link's decode arena.

Called after every message is decoded and released, so each decode starts from a known offset and no leak can accumulate across messages. That is what bounds the arena requirement to one message rather than to a run.

Parameters
[in,out]linkLink whose arena to empty; null is ignored.
Returns
Nothing.
Precondition
No block from the arena is still referenced.
The link is open, or the call is a no-op.
Postcondition
The bump offset is zero.
The arena's bytes are left untouched, not scrubbed.
Note
Not thread-safe.
Example:
See also
priv_c6link_arena_alloc
Since
0.1.0

Definition at line 107 of file ra8_c6link_arena.c.

References ra8_c6link::arena_last, ra8_c6link::arena_used, and RA8_PRIV.

Referenced by priv_c6link_rpc_consume().