|
RTE OSAdapter POSIX 0.1.0 build 41b3eb3
POSIX/Linux OAL OSAdapter for Platform_RTE
|
POSIX rte_task OSAdapter: one pthread per task (ADR-018 section 2.3). period_ms > 0 runs entry in a loop paced by an absolute CLOCK_MONOTONIC deadline; period_ms == 0 runs entry once. More...
#include "rte/posix_osadapter/rte_posix_osadapter.h"#include "rte_posix_osadapter_period.h"#include "rte_posix_osadapter_report.h"#include <errno.h>#include <pthread.h>#include <sched.h>#include <signal.h>#include <stdbool.h>#include "rte/oal/memory/rte_mem_util.h"Go to the source code of this file.
Data Structures | |
| struct | posix_task_state_t |
Macros | |
| #define | _POSIX_C_SOURCE 200809L |
Typedefs | |
| typedef char | posix_task_storage_fits_[(sizeof(posix_task_state_t)<=sizeof(rte_task_storage_t)) ? 1 :-1] |
Functions | |
| static bool | set_fifo_attributes (pthread_attr_t *attr, uint32_t priority) |
| static void | create_task_key (void) |
| static bool | task_key_ready (void) |
| static void | run_periodic_task (posix_task_state_t *state) |
| static void | run_task (posix_task_state_t *state) |
| static void * | task_thread_main (void *arg) |
| static bool | is_task_thread (const posix_task_state_t *state) |
| static rte_status_t | join_task_thread (posix_task_state_t *state) |
| static rte_status_t | create_task_thread (posix_task_state_t *state) |
| static rte_status_t | osadapter_create (rte_task_storage_t *storage, const rte_task_config_t *config, rte_task_handle_t *out_handle) |
| static rte_status_t | osadapter_suspend (rte_task_handle_t handle) |
| static rte_status_t | osadapter_start (rte_task_handle_t handle) |
| static rte_status_t | osadapter_destroy (rte_task_handle_t handle) |
| const rte_osadapter_task_t * | rte_posix_osadapter_task (void) |
| The POSIX rte_task OSAdapter (one pthread per task). | |
Variables | |
| static pthread_key_t | s_task_key |
| static bool | s_task_key_ready = false |
| static const rte_osadapter_task_t | s_posix_task_osadapter |
POSIX rte_task OSAdapter: one pthread per task (ADR-018 section 2.3). period_ms > 0 runs entry in a loop paced by an absolute CLOCK_MONOTONIC deadline; period_ms == 0 runs entry once.
Pacing (OSA rule R3, audit item 8; Platform_RTE REQ-OAL-TIMER-014, one monotonic time base): a periodic task thread reads CLOCK_MONOTONIC once when it starts and moves that deadline one period later before every entry call (rte_posix_osadapter_period.h). It waits for the deadline on the process-wide wake object (audit item 7b-1): non-Apple hosts pthread_cond_timedwait() to the absolute deadline on a CLOCK_MONOTONIC condition variable; macOS (no condition variable clock attribute) pthread_cond_timedwait_relative_np() of the time left to the same absolute deadline, the clock read again after every wake-up. The entry's run time does not shift the next call (no drift); an entry that overruns the period is called again at once, late but not skipped. macOS CLOCK_MONOTONIC counts during system sleep, so after a laptop sleep the missed calls follow back to back. If the first clock read or a wait fails (a clock_gettime() error, a wake-mutex error other than a timeout, or the condition wait returning an error other than ETIMEDOUT), the thread reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE once ("task monotonic clock failed - task stopped") and calls entry no more; a failed read is never used as time
Wake object: the first create in the process also creates the period wake object (posix_period_wake_ready(): a priority-inheritance mutex and a condition variable, never deleted), also for a run-once task. If it is refused (reported once), that create and every later one return RTE_STATUS_INTERNAL_ERROR with the storage untouched, like a refused self-check key below.
Known simplification (stated in ADR-018): rte_task has no native "suspend, keep state, resume later" primitive in POSIX threads without signal-based hacks this OSAdapter does not use. suspend() here stops the thread cleanly (same as destroy() minus freeing the handle); start() after suspend() begins a fresh run from the top of entry's cycle rather than resuming mid-cycle. Acceptable for a first cut - a caller that needs true pause/resume semantics needs an OSAdapter with more OS support than a portable pthread implementation can offer.
Thread attributes (OSA rule R1, Platform_RTE REQ-OAL-TASK-002 "priorities fixed at creation"): start() builds one pthread_attr_t per start and sets, before pthread_create(), the configured stack size (when stack_size > 0), PTHREAD_EXPLICIT_SCHED, SCHED_FIFO and the priority clamped into the platform's SCHED_FIFO range. Every attribute call's return code is checked; the thread never starts under one policy and is switched to another afterwards. A failed pthread_attr_init() fails the start (RTE_STATUS_INTERNAL_ERROR, no thread).
Fallback (ADR-018, unchanged in intent): SCHED_FIFO needs privilege (typically CAP_SYS_NICE or root) that most development/CI hosts and unprivileged containers do not grant. When a scheduling attribute is refused, sched_get_priority_min/max() fails, or pthread_create() with the explicit-sched attributes returns EPERM, the adapter reports it once per start (DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE, "task SCHED_FIFO priority not applied") and creates the thread again with PTHREAD_INHERIT_SCHED, stack size kept: the creator's policy and priority on Linux; macOS (observed): time-sharing at the creator's priority, while pthread_getschedparam() says SCHED_OTHER 31. The integrator's DEGRADED handler decides whether that host is acceptable. Any other pthread_create() error fails the start (RTE_STATUS_INTERNAL_ERROR, no thread, the task not running). A refused stack size is reported ("task stack size not applied") and the default stack is used, as before.
Thread ownership (OSA rule R2, audit item 7a; Platform_RTE REQ-OAL-TASK-011..013): the thread that calls start/suspend/destroy (the controlling thread) owns the task thread and joins every thread it created. joinable is set after a successful pthread_create() and cleared only after pthread_join() returned 0; only the controlling thread reads or writes it. suspend()/destroy() join whenever it is set, also when the thread has already returned on its own (a run-once task after its entry), and start() on a task whose thread exists first joins it (restart from the top, see above). A failed pthread_join() returns RTE_STATUS_INTERNAL_ERROR with joinable kept, so a later suspend/destroy joins it. The task thread's loop writes no shared field. should_stop is the only field both threads write: start() sets it to 0 only while no task thread exists (before pthread_create(), after any join); suspend()/destroy() set it to 1, from either thread, so two writes that can overlap both store 1. They set it through posix_period_wake_all(), which stores it under the wake mutex and broadcasts, so a periodic task thread waiting for its deadline returns at once instead of up to one period later (audit item 7b-1; the thread reads the flag under the same mutex before it waits, so the wake-up cannot be lost - rte_posix_osadapter_period.h). If the wake mutex cannot be taken within RTE_POSIX_PERIOD_WAKE_LOCK_TIMEOUT_MS the flag is stored without it and the thread ends at its next deadline. It stays a volatile sig_atomic_t (C99 has no <stdatomic.h>); pthread_create(), pthread_join() and the wake mutex are the synchronisation points around it.
Self check (thread-specific data): the first create in the process creates one pthread key for all tasks (pthread_once(); never deleted, it lives as long as the process). If pthread_once() or pthread_key_create() fails, that create and every later one return RTE_STATUS_INTERNAL_ERROR (the key is not retried). Each task thread stores its own state pointer under the key (pthread_setspecific()) before its first entry call, and a call is "from the task's own entry" when pthread_getspecific() returns that task's state. The check reads nothing the controlling thread writes after pthread_create(), so it also holds while pthread_create() has not returned yet (a run-once entry runs at once). If pthread_setspecific() fails (ENOMEM), the thread reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE ("task thread-specific data not set - task not run") and returns without calling entry: start() has returned RTE_STATUS_OK, entry never runs, and suspend/destroy join the thread as usual. It never calls entry without the self check.
Self-call rule: suspend()/destroy() called from the task's own entry cannot join the calling thread. They only set should_stop (through posix_period_wake_all()) and return RTE_STATUS_OK; entry is not called again, and the next start/suspend/destroy from another thread joins the thread. start() from the entry returns RTE_STATUS_NOT_SUPPORTED and changes nothing (it would otherwise run a second thread for the same task). A stop wakes a waiting periodic task thread; pthread_join() itself still waits, with no bound, for an entry that is running (audit item 7b-2).
Definition in file rte_posix_osadapter_task.c.
| #define _POSIX_C_SOURCE 200809L |
Definition at line 1 of file rte_posix_osadapter_task.c.
| typedef char posix_task_storage_fits_[(sizeof(posix_task_state_t)<=sizeof(rte_task_storage_t)) ? 1 :-1] |
Definition at line 139 of file rte_posix_osadapter_task.c.
|
static |
pthread_once() routine: creates the self-check key (no destructor: the stored value is the task's own state, not owned by the thread).
Definition at line 194 of file rte_posix_osadapter_task.c.
|
static |
Creates the task thread with attributes set before creation (see file header). Single exit. Returns RTE_STATUS_OK with the thread created (SCHED_FIFO, or inherited scheduling after one report), or RTE_STATUS_INTERNAL_ERROR with no thread created. Does not touch state->joinable.
Definition at line 330 of file rte_posix_osadapter_task.c.
|
static |
True when the caller is this task's own thread (its entry calls start/suspend/destroy on its own handle): the calling thread's thread-specific value is this task's state (file header). Reads no field of state.
Definition at line 300 of file rte_posix_osadapter_task.c.
|
static |
Joins the task thread if one exists (joinable), after setting should_stop and waking the thread from its wait (posix_period_wake_all()). Called by the controlling thread only. Returns RTE_STATUS_OK with no thread left (joinable cleared), or RTE_STATUS_INTERNAL_ERROR when pthread_join() failed (joinable kept, a later call retries).
Definition at line 308 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 384 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 473 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 439 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 414 of file rte_posix_osadapter_task.c.
| const rte_osadapter_task_t * rte_posix_osadapter_task | ( | void | ) |
The POSIX rte_task OSAdapter (one pthread per task).
Priority scale: rte_task_config_t::priority is a SCHED_FIFO priority, clamped into [sched_get_priority_min(SCHED_FIFO), sched_get_priority_max(SCHED_FIFO)]. It is set on the thread attributes (PTHREAD_EXPLICIT_SCHED) together with the stack size before pthread_create (OSA rule R1). Where SCHED_FIFO is refused (no privilege), start reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE and the thread runs with inherited scheduling (ADR-018).
Every thread start creates is joined (OSA rule R2): by suspend and destroy, also after a run-once entry has returned, and by a restart (start on a started task) before the new thread is created. A failed pthread_join returns RTE_STATUS_INTERNAL_ERROR and keeps the thread for a later suspend or destroy. From the task's own entry (periodic or run-once), suspend and destroy only end the task (RTE_STATUS_OK, entry not called again; the next start, suspend or destroy from another thread joins the thread) and start returns RTE_STATUS_NOT_SUPPORTED without changing anything. The entry's own thread is recognised through thread-specific data (one pthread key per process, created by the first create and never deleted): create returns RTE_STATUS_INTERNAL_ERROR if the key cannot be created, and a task thread that cannot store its mark reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE and calls no entry. Suspend and destroy wake a periodic task thread that waits for its next period (the same process-wide wake object as the timer OSAdapter's; create returns RTE_STATUS_INTERNAL_ERROR if it cannot be created), so they do not wait for the rest of the period. The join is an unbounded wait for the entry in progress.
Definition at line 481 of file rte_posix_osadapter_task.c.
|
static |
The periodic loop of a task thread (period_ms > 0): absolute monotonic deadline, entry once per period until should_stop. A failed clock read or wait reports once and ends the loop without a further entry call (see file header).
Definition at line 216 of file rte_posix_osadapter_task.c.
|
static |
The body of a task thread: entry once (period_ms == 0) or the periodic loop until should_stop.
Definition at line 249 of file rte_posix_osadapter_task.c.
|
static |
Sets PTHREAD_EXPLICIT_SCHED, SCHED_FIFO and the priority on attr (OSA rule R1: static real-time priority, set before the thread exists). priority is clamped into the platform's SCHED_FIFO range [min, max] rather than passed through unchecked; the comparison is done on uint32_t, so a priority above INT_MAX clamps to max. Returns true only when every call succeeded; false when sched_get_priority_min/max() failed or an attribute was refused, in which case the caller falls back to inherited scheduling (see file header). Does not report.
Definition at line 152 of file rte_posix_osadapter_task.c.
|
static |
Creates the self-check key on the first call in the process; true once it exists. False when pthread_once() or pthread_key_create() failed (not retried, see file header).
Definition at line 201 of file rte_posix_osadapter_task.c.
|
static |
Task thread: marks itself as this task's thread for the self check, then runs the task. Without the mark it calls no entry (see file header). Writes no shared field.
Definition at line 280 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 478 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 144 of file rte_posix_osadapter_task.c.
|
static |
Definition at line 145 of file rte_posix_osadapter_task.c.