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

Mutex and semaphore vtable slots. More...

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_check.h"
#include "ra8_err.h"
#include "ra8_esp_hosted_port.h"
#include "ra8_esp_hosted_rtos_internal.h"
#include "ra8_log.h"
#include "tx_api.h"
#include "port_esp_hosted_host_os.h"
Include dependency graph for ra8_esp_hosted_rtos_sync.c:

Go to the source code of this file.

Data Structures

struct  ra8_esp_hosted_sync_state_t
 Module state of the mutex and semaphore half – entirely static. More...

Enumerations

enum  ra8_esp_hosted_sync_const_t : uint32_t { k_ra8_esp_hosted_sem_initial = 1U }
 Numeric constants of the mutex and semaphore half. More...

Functions

static void * internal_h_create_mutex (void)
 Create a mutex from the fixed mutex table.
static int internal_h_lock_mutex (void *mutex_handle, int timeout_ms)
 Take a mutex, blocking for at most timeout_ms.
static int internal_h_unlock_mutex (void *mutex_handle)
 Release a mutex the caller owns.
static int internal_h_destroy_mutex (void *mutex_handle)
 Delete a mutex and free its table row.
static void * internal_h_create_semaphore (int max_count)
 Create a counting semaphore from the fixed semaphore table.
static int internal_h_get_semaphore (void *semaphore_handle, int timeout_ms)
 Take a semaphore, blocking for at most timeout_ms.
static int internal_h_post_semaphore (void *semaphore_handle)
 Post a semaphore from thread context.
static int internal_h_post_semaphore_from_isr (void *semaphore_handle)
 Post a semaphore from an interrupt handler.
static int internal_h_destroy_semaphore (void *semaphore_handle)
 Delete a semaphore and free its table row.
ra8_err_t priv_ra8_esp_hosted_rtos_sync_init (void)
 Clear the mutex and semaphore tables and mark them usable.
ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit (void)
 Delete every outstanding mutex and semaphore.
ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync (hosted_osi_funcs_t *out)
 Populate the mutex and semaphore slots of the vtable.

Variables

static const char * s_tag = "ESPH_SYNC"
 Log tag for the mutex and semaphore half of the port.
static ra8_esp_hosted_sync_state_t s_sync
 Singleton state of the mutex and semaphore half.

Detailed Description

Mutex and semaphore vtable slots.

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

See port/esp-hosted/src/ra8_esp_hosted_rtos_internal.h for the contracts. The RTOS slice is three translation units because one would be several times the project's thousand-line file cap; the split follows the object kinds, which is also how the fixed tables divide. This unit owns the mutex and semaphore tables.

There are no mempool-lock rows to fill: H_USE_MEMPOOL is deliberately hosted_osi_funcs_t at all. See port_esp_hosted_host_config.h for why – the vendored header guards them with #ifdef rather than #if, so any definition, including zero, would switch them on and make the struct layout depend on include order.

Since
0.1.0

Definition in file ra8_esp_hosted_rtos_sync.c.

Enumeration Type Documentation

◆ ra8_esp_hosted_sync_const_t

enum ra8_esp_hosted_sync_const_t : uint32_t

Numeric constants of the mutex and semaphore half.

One value, stated here rather than inline so the create-time semaphore count is impossible to change by accident.

Invariant
k_ra8_esp_hosted_sem_initial is exactly one, so the single drain every vendored call site performs leaves the semaphore empty.
The value is never larger than any caller's max_count.
Example:
static_assert(k_ra8_esp_hosted_sem_initial == 1U, "one drain empties it");
@ k_ra8_esp_hosted_sem_initial
Instances a new semaphore starts with.
See also
priv_ra8_esp_hosted_rtos_bind_sync
Since
0.1.0
Enumerator
k_ra8_esp_hosted_sem_initial 

Instances a new semaphore starts with.

Definition at line 71 of file ra8_esp_hosted_rtos_sync.c.

Function Documentation

◆ internal_h_create_mutex()

void * internal_h_create_mutex ( void )
static

Create a mutex from the fixed mutex table.

Priority inheritance is enabled: the bus lock is taken by both the transaction thread and a lower-priority power-save path, which is exactly the inversion ThreadX's inheritance exists to bound.

Returns
Opaque mutex handle, or null on failure.
Return values
nullptrThe substrate is down or the mutex table is full.
non-nullA handle usable with the other mutex slots.
Precondition
The substrate is initialised.
The caller destroys the mutex before teardown.
Postcondition
On success one table row is occupied and the mutex is unowned.
On failure no row stays claimed.
Note
Not thread-safe against a concurrent create.
Since
0.1.0

Definition at line 128 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_mutexes, priv_ra8_esp_hosted_rtos_slot_take(), RA8_INTERNAL, ra8_log_error, s_sync, s_tag, tx_mutex_create, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_create_semaphore()

void * internal_h_create_semaphore ( int max_count)
static

Create a counting semaphore from the fixed semaphore table.

The initial count is one, not max_count. Every call site in the vendored tree – bus_init_internal in spi_drv.c, rpc_platform_init, rpc_core's per-request semaphore – follows the create immediately with one _h_get_semaphore(sem, 0) whose own comment says it is there to leave the semaphore empty so the waiting task blocks. Starting at max_count would leave max_count - 1 phantom instances behind that single drain, and spi_drv.c reads a successful take as "a transmit message is present as per sem" – so the phantom counts would make it repeatedly believe a frame is queued when none is. Starting at one makes that drain do exactly what its comment claims on every path, binary or counting. max_count is therefore validated and otherwise unused: ThreadX counting semaphores carry no ceiling.

Parameters
[in]max_countLargest count the caller intends to reach; must be positive.
Returns
Opaque semaphore handle, or null on failure.
Return values
nullptrThe substrate is down, max_count was not positive, or the semaphore table is full.
non-nullA handle usable with the other semaphore slots.
Precondition
The substrate is initialised.
The caller drains the semaphore if it wants it empty.
Postcondition
On success one table row is occupied and the count is one.
On failure no row stays claimed.
Note
Not thread-safe against a concurrent create.
Since
0.1.0

Definition at line 273 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_semaphores, k_ra8_esp_hosted_sem_initial, priv_ra8_esp_hosted_rtos_slot_take(), RA8_INTERNAL, ra8_log_error, s_sync, s_tag, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_destroy_mutex()

int internal_h_destroy_mutex ( void * mutex_handle)
static

Delete a mutex and free its table row.

Frees the row last so a concurrent lookup never sees a half-deleted object.

Parameters
[in]mutex_handleHandle from _h_create_mutex.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe mutex is gone and its row is free.
RET_INVALIDThe handle was not usable.
RET_FAILThreadX refused the delete.
Precondition
The substrate is initialised.
Nothing owns or is waiting on the mutex.
Postcondition
The table row is free for reuse.
A later lock through the stale handle reports RET_INVALID.
Note
Not thread-safe against a concurrent create. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 227 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_mutexes, priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL, RET_INVALID, RET_OK, s_sync, tx_mutex_delete, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync(), and priv_ra8_esp_hosted_rtos_sync_deinit().

◆ internal_h_destroy_semaphore()

int internal_h_destroy_semaphore ( void * semaphore_handle)
static

Delete a semaphore and free its table row.

Frees the row last so a concurrent lookup never sees a half-deleted object.

Parameters
[in]semaphore_handleHandle from _h_create_semaphore.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe semaphore is gone and its row is free.
RET_INVALIDThe handle was not usable.
RET_FAILThreadX refused the delete.
Precondition
The substrate is initialised.
No thread is blocked on the semaphore.
Postcondition
The table row is free for reuse.
A later take through the stale handle reports RET_INVALID.
Note
Not thread-safe against a concurrent create. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 405 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_semaphores, priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL, RET_INVALID, RET_OK, s_sync, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync(), and priv_ra8_esp_hosted_rtos_sync_deinit().

◆ internal_h_get_semaphore()

int internal_h_get_semaphore ( void * semaphore_handle,
int timeout_ms )
static

Take a semaphore, blocking for at most timeout_ms.

A zero timeout is a non-blocking try-take that returns RET_OK on success – spi_drv.c spells it if (!_h_get_semaphore(sem, 0)) and treats the zero as "an item is queued", so the mapping is load-bearing.

Parameters
[in]semaphore_handleHandle from _h_create_semaphore.
[in]timeout_msWait in milliseconds; 0 = try, negative = forever.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKAn instance was taken.
RET_INVALIDThe handle was not usable.
RET_FAIL_TIMEOUTThe count stayed zero for the whole wait.
Precondition
The substrate is initialised.
The caller is a thread when the timeout is non-zero.
Postcondition
On success the count has fallen by one.
On failure the count is unchanged.
Note
Thread context only when blocking. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 311 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_semaphores, priv_ra8_esp_hosted_rtos_ms_to_ticks(), priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL_TIMEOUT, RET_INVALID, RET_OK, s_sync, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_lock_mutex()

int internal_h_lock_mutex ( void * mutex_handle,
int timeout_ms )
static

Take a mutex, blocking for at most timeout_ms.

Zero milliseconds is a try-lock; a negative value, which is how HOSTED_BLOCK_MAX arrives through an int, blocks until the mutex is free.

Parameters
[in]mutex_handleHandle from _h_create_mutex.
[in]timeout_msWait in milliseconds; 0 = try, negative = forever.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe caller now owns the mutex.
RET_INVALIDThe handle was not usable.
RET_FAIL_TIMEOUTThe wait expired with the mutex still held.
Precondition
The substrate is initialised.
The caller will release the mutex it takes.
Postcondition
On success the ownership depth has risen by one.
On failure the ownership depth is unchanged.
Note
Thread-safe; that is the point. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 165 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_mutexes, priv_ra8_esp_hosted_rtos_ms_to_ticks(), priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL_TIMEOUT, RET_INVALID, RET_OK, s_sync, tx_mutex_get, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_post_semaphore()

int internal_h_post_semaphore ( void * semaphore_handle)
static

Post a semaphore from thread context.

Increments the count and, if a thread is blocked on it, releases that thread. ThreadX imposes no ceiling, so a post always succeeds on a live semaphore.

Parameters
[in]semaphore_handleHandle from _h_create_semaphore.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe count was incremented.
RET_INVALIDThe handle was not usable.
RET_FAILThreadX refused the post.
Precondition
The substrate is initialised.
The caller is not an interrupt handler; use the ISR variant there.
Postcondition
On success the count has risen by one.
On failure the count is unchanged.
Note
Thread-safe. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 344 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_semaphores, priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL, RET_INVALID, RET_OK, s_sync, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_post_semaphore_from_isr()

int internal_h_post_semaphore_from_isr ( void * semaphore_handle)
static

Post a semaphore from an interrupt handler.

Called from the HANDSHAKE and DATA_READY edge handlers. It does exactly what the thread-context post does, because tx_semaphore_put is itself ISR-safe – and deliberately nothing else: no logging, no blocking, no allocation, so the handler stays bounded.

Parameters
[in]semaphore_handleHandle from _h_create_semaphore.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe count was incremented.
RET_INVALIDThe handle was not usable.
RET_FAILThreadX refused the post.
Precondition
The substrate is initialised.
The caller is an interrupt handler or a thread; either is fine.
Postcondition
On success the count has risen by one.
No log line is emitted on any path.
Note
Safe from interrupt context; that is this slot's whole purpose.
Since
0.1.0

Definition at line 375 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_semaphores, priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RA8_ISR_SAFE, RET_FAIL, RET_INVALID, RET_OK, s_sync, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ internal_h_unlock_mutex()

int internal_h_unlock_mutex ( void * mutex_handle)
static

Release a mutex the caller owns.

Reports a distinct failure for an unbalanced release rather than swallowing it, because that is always a defect in the caller.

Parameters
[in]mutex_handleHandle from _h_create_mutex.
Returns
RET_OK on success, a negative RET_* code otherwise.
Return values
RET_OKThe ownership depth fell by one.
RET_INVALIDThe handle was not usable.
RET_FAILThe caller did not own the mutex.
Precondition
The substrate is initialised.
The caller took the mutex it is releasing.
Postcondition
On success the ownership depth has fallen by one.
On failure the ownership depth is unchanged.
Note
Thread-safe. Validation is by return code because the vtable signature has no error channel.
Since
0.1.0

Definition at line 197 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_esp_hosted_max_mutexes, priv_ra8_esp_hosted_rtos_slot_index(), RA8_INTERNAL, RET_FAIL, RET_INVALID, RET_OK, s_sync, tx_mutex_put, and TX_SUCCESS.

Referenced by priv_ra8_esp_hosted_rtos_bind_sync().

◆ priv_ra8_esp_hosted_rtos_bind_sync()

ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync ( hosted_osi_funcs_t * out)

Populate the mutex and semaphore slots of the vtable.

The binder of the synchronisation translation unit, which owns the mutex and semaphore tables. Called by priv_ra8_esp_hosted_osi_bind_all alongside the other two binders. There are no mempool-lock rows to fill; see the file-level note on H_USE_MEMPOOL.

Parameters
[out]outVtable to populate. Must be non-null.
Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery mutex and semaphore slot is populated.
k_ra8_err_null_ptrout was null.
Precondition
out points at storage that outlives the vendored core.
priv_ra8_esp_hosted_rtos_init has run, or the slots will report failures.
Postcondition
The four mutex slots and five semaphore slots are non-null.
No other slot is written.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_bind_sync(hosted_osi_funcs_t *out)
Populate the mutex and semaphore slots of the vtable.
See also
priv_ra8_esp_hosted_rtos_bind
Since
0.1.0

Definition at line 452 of file ra8_esp_hosted_rtos_sync.c.

References internal_h_create_mutex(), internal_h_create_semaphore(), internal_h_destroy_mutex(), internal_h_destroy_semaphore(), internal_h_get_semaphore(), internal_h_lock_mutex(), internal_h_post_semaphore(), internal_h_post_semaphore_from_isr(), internal_h_unlock_mutex(), k_ra8_ok, RA8_CHECK_NULL_PTR, and s_tag.

Referenced by priv_ra8_esp_hosted_osi_bind_all().

◆ priv_ra8_esp_hosted_rtos_sync_deinit()

ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit ( void )
nodiscard

Delete every outstanding mutex and semaphore.

The synchronisation half of priv_ra8_esp_hosted_rtos_deinit: walks both tables and deletes whatever is still in use, then clears the state so a later create fails cleanly rather than touching a dead control block.

Returns
ra8_err_t Error code.
Return values
k_ra8_okEvery object was released.
k_ra8_err_not_initializedThe tables were not initialised.
k_ra8_err_rtos_errorThreadX refused a delete.
Precondition
No thread is blocked on a port mutex or semaphore.
The vendored core has stopped using its handles.
Postcondition
Every occupancy flag is clear.
A later take through a stale handle reports RET_INVALID.
Note
Not thread-safe; call from the same context as the init.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_sync_deinit(void)
Delete every outstanding mutex and semaphore.
See also
priv_ra8_esp_hosted_rtos_sync_init
Since
0.1.0

Definition at line 431 of file ra8_esp_hosted_rtos_sync.c.

References internal_h_destroy_mutex(), internal_h_destroy_semaphore(), k_ra8_err_not_initialized, k_ra8_err_rtos_error, k_ra8_esp_hosted_max_mutexes, k_ra8_esp_hosted_max_semaphores, k_ra8_ok, memset(), ra8_log_error, RET_OK, s_sync, and s_tag.

Referenced by priv_ra8_esp_hosted_rtos_deinit().

◆ priv_ra8_esp_hosted_rtos_sync_init()

ra8_err_t priv_ra8_esp_hosted_rtos_sync_init ( void )
nodiscard

Clear the mutex and semaphore tables and mark them usable.

The synchronisation half of priv_ra8_esp_hosted_rtos_init. Separated so the unit that owns the tables also owns their lifecycle, and so a test can bring the locks up without the allocator.

Returns
ra8_err_t Error code.
Return values
k_ra8_okBoth tables are empty and usable.
k_ra8_err_invalid_stateThe tables were already initialised.
Precondition
The ThreadX kernel is running.
No handle from a previous incarnation of the tables is still held.
Postcondition
Every occupancy flag is clear.
A create call will now succeed.
Note
Not thread-safe; call once during bring-up.
Example:
ra8_err_t priv_ra8_esp_hosted_rtos_sync_init(void)
Clear the mutex and semaphore tables and mark them usable.
See also
priv_ra8_esp_hosted_rtos_sync_deinit
Since
0.1.0

Definition at line 420 of file ra8_esp_hosted_rtos_sync.c.

References k_ra8_err_invalid_state, k_ra8_ok, memset(), ra8_log_error, s_sync, and s_tag.

Referenced by priv_ra8_esp_hosted_rtos_init().

Variable Documentation

◆ s_sync

Singleton state of the mutex and semaphore half.

Zero-initialised at link time; brought up by priv_ra8_esp_hosted_rtos_sync_init.

Note
Static; do not access outside this TU.
Warning
Direct modification bypasses every ThreadX consistency check.
Since
0.1.0

Definition at line 107 of file ra8_esp_hosted_rtos_sync.c.

Referenced by internal_h_create_mutex(), internal_h_create_semaphore(), internal_h_destroy_mutex(), internal_h_destroy_semaphore(), internal_h_get_semaphore(), internal_h_lock_mutex(), internal_h_post_semaphore(), internal_h_post_semaphore_from_isr(), internal_h_unlock_mutex(), priv_ra8_esp_hosted_rtos_sync_deinit(), and priv_ra8_esp_hosted_rtos_sync_init().

◆ s_tag

const char* s_tag = "ESPH_SYNC"
static

Log tag for the mutex and semaphore half of the port.

Shared by every diagnostic this translation unit emits.

Note
Static; do not access outside this TU.
Warning
Changing it changes log-scraping expectations on the bench.
Since
0.1.0

Definition at line 53 of file ra8_esp_hosted_rtos_sync.c.