|
RTE OSAdapter POSIX 0.1.0 build 41b3eb3
POSIX/Linux OAL OSAdapter for Platform_RTE
|
POSIX rte_timer OSAdapter: one pthread per timer, paced by an absolute CLOCK_MONOTONIC deadline (ADR-018 section 2.3). 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 <limits.h>#include <pthread.h>#include <sched.h>#include <signal.h>#include <stdbool.h>#include <stddef.h>#include "rte/oal/memory/rte_mem_util.h"#include <time.h>Go to the source code of this file.
Data Structures | |
| struct | posix_timer_state_t |
Macros | |
| #define | _POSIX_C_SOURCE 200809L |
| #define | RTE_POSIX_TIMER_STACK_SIZE ((size_t)8388608U) |
Typedefs | |
| typedef char | posix_timer_storage_fits_[(sizeof(posix_timer_state_t)<=sizeof(rte_timer_storage_t)) ? 1 :-1] |
Functions | |
| static void | create_timer_key (void) |
| static bool | timer_key_ready (void) |
| static void * | timer_thread_main (void *arg) |
| static void | run_timer_loop (posix_timer_state_t *state) |
| static bool | is_timer_thread (const posix_timer_state_t *state) |
| static rte_status_t | join_timer_thread (posix_timer_state_t *state) |
| static bool | set_creator_sched_attributes (pthread_attr_t *attr) |
| static rte_status_t | create_timer_thread (posix_timer_state_t *state) |
| static rte_status_t | osadapter_create (rte_timer_storage_t *storage, const rte_timer_config_t *config, rte_timer_handle_t *out_handle) |
| static rte_status_t | osadapter_stop (rte_timer_handle_t handle) |
| static rte_status_t | osadapter_start (rte_timer_handle_t handle) |
| static rte_status_t | osadapter_destroy (rte_timer_handle_t handle) |
| static rte_status_t | osadapter_now (rte_timestamp_ms_t *out_now_ms) |
| const rte_osadapter_timer_t * | rte_posix_osadapter_timer (void) |
| The POSIX rte_timer OSAdapter (one pthread per timer). | |
Variables | |
| static const rte_osadapter_timer_t | s_posix_timer_osadapter |
| static pthread_key_t | s_timer_key |
| static bool | s_timer_key_ready = false |
POSIX rte_timer OSAdapter: one pthread per timer, paced by an absolute CLOCK_MONOTONIC deadline (ADR-018 section 2.3).
Pacing (OSA rule R3, audit item 8; Platform_RTE REQ-OAL-TIMER-014, one monotonic time base): the timer thread reads CLOCK_MONOTONIC once when it starts and moves that deadline one period later before every expiry (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 deadline is never re-read from the clock, so the callback's run time does not shift the next expiry (no drift), and the wall clock (CLOCK_REALTIME) decides no expiry. A callback that overruns the period gets the next expiry at once (no wait), late but not skipped. macOS CLOCK_MONOTONIC counts during system sleep, so after a laptop sleep the missed expiries are delivered back to back.
Clock failure: if the first CLOCK_MONOTONIC 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 ("timer monotonic clock failed - timer stopped") and ends its loop with no further callback; a failed read is never used as time 0. start() has returned RTE_STATUS_OK, so the timer stops firing; stop/destroy join the thread as usual and the next start begins a fresh deadline. Same posture as a failed thread-specific-data mark below: no callback without a time base, the stalled cycle is left to the watchdog.
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). 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.
Thread attributes (OSA rule R1; Platform_RTE REQ-OAL-TIMER-003, the callback's context documented per OSAdapter): the expiry callback runs on the timer's own thread. start() builds one pthread_attr_t per start and sets, before pthread_create(), the fixed stack size RTE_POSIX_TIMER_STACK_SIZE and PTHREAD_EXPLICIT_SCHED with the scheduling policy and priority of the thread that calls start(), read with pthread_getschedparam(pthread_self()). The timer thread therefore runs exactly as its creator was scheduled at start() (e.g. SCHED_FIFO 80 after a successful rte_platform_realtime_init(80U) on a privileged Linux host, SCHED_OTHER elsewhere); this adapter requests no policy of its own. 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): when the creator's scheduling cannot be read, a scheduling attribute is refused, or pthread_create() with the explicit-sched attributes returns EPERM, the adapter reports it once per start (DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE, "timer scheduling not applied") and creates the thread again with PTHREAD_INHERIT_SCHED, the stack size kept (the behaviour before attributes were set). Any other pthread_create() error fails the start (RTE_STATUS_INTERNAL_ERROR, no thread, the timer not running). A refused stack size is reported ("timer stack size not applied") and the default stack is used.
Thread ownership (OSA rule R2, audit item 7a; Platform_RTE REQ-OAL-TIMER-011..013): the thread that calls start/stop/destroy (the controlling thread) owns the timer 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. stop()/destroy() join whenever it is set, also when the thread has already returned on its own (a one-shot timer after its expiry), and start() on a timer whose thread exists first joins it (restart). A failed pthread_join() returns RTE_STATUS_INTERNAL_ERROR with joinable kept, so a later stop/destroy joins it. The timer thread's loop writes no shared field. should_stop is the only field both threads write: start() sets it to 0 only while no timer thread exists (before pthread_create(), after any join); stop()/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 timer 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 timers (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 timer thread stores its own state pointer under the key (pthread_setspecific()) before its first callback, and a call is "from the timer's own callback" when pthread_getspecific() returns that timer's state. The check reads nothing the controlling thread writes after pthread_create(), so it also holds while pthread_create() has not returned yet. If pthread_setspecific() fails (ENOMEM), the thread reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE ("timer thread-specific data not set - timer not run") and returns without any callback: start() has returned RTE_STATUS_OK, the timer never fires, and stop/destroy join the thread as usual. It never runs callbacks without the self check.
Self-call rule: stop()/destroy() called from the timer's own callback cannot join the calling thread. They only set should_stop (through posix_period_wake_all()) and return RTE_STATUS_OK; no further callback runs, and the next stop/start/destroy from another thread joins the thread. start() from the callback returns RTE_STATUS_NOT_SUPPORTED and changes nothing (it would otherwise run a second thread for the same timer). A stop wakes a waiting timer thread; pthread_join() itself still waits, with no bound, for a callback that is running (audit item 7b-2).
Definition in file rte_posix_osadapter_timer.c.
| #define _POSIX_C_SOURCE 200809L |
Definition at line 1 of file rte_posix_osadapter_timer.c.
| #define RTE_POSIX_TIMER_STACK_SIZE ((size_t)8388608U) |
Local makros
Definition at line 134 of file rte_posix_osadapter_timer.c.
| typedef char posix_timer_storage_fits_[(sizeof(posix_timer_state_t)<=sizeof(rte_timer_storage_t)) ? 1 :-1] |
Definition at line 150 of file rte_posix_osadapter_timer.c.
|
static |
Local function declarations
pthread_once() routine: creates the self-check key (no destructor: the stored value is the timer's own state, not owned by the thread).
Definition at line 192 of file rte_posix_osadapter_timer.c.
|
static |
Creates the timer thread with attributes set before creation (see file header). Single exit. Returns RTE_STATUS_OK with the thread created (the creator's scheduling copied, or inherited scheduling after one report), or RTE_STATUS_INTERNAL_ERROR with no thread created. Does not touch state->joinable.
Definition at line 331 of file rte_posix_osadapter_timer.c.
|
static |
True when the caller is this timer's own thread (its callback calls start/stop/destroy on its own handle): the calling thread's thread-specific value is this timer's state (file header). Reads no field of state.
Definition at line 274 of file rte_posix_osadapter_timer.c.
|
static |
Joins the timer 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 282 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 389 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 479 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 484 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 445 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 420 of file rte_posix_osadapter_timer.c.
| const rte_osadapter_timer_t * rte_posix_osadapter_timer | ( | void | ) |
The POSIX rte_timer OSAdapter (one pthread per timer).
Global variables declarations Global functions
The expiry callback runs on the timer's own thread. Start sets on the thread attributes, before pthread_create (OSA rule R1), a fixed stack size (RTE_POSIX_TIMER_STACK_SIZE, default 8 MiB) and PTHREAD_EXPLICIT_SCHED with the scheduling policy and priority of the thread calling start. Where that is refused, 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 stop and destroy, also after a one-shot timer has fired, and by a restart (start on a started timer) before the new thread is created. A failed pthread_join returns RTE_STATUS_INTERNAL_ERROR and keeps the thread for a later stop or destroy. From the timer's own callback, stop and destroy only end the timer (RTE_STATUS_OK, no further callback; the next stop, start or destroy from another thread joins the thread) and start returns RTE_STATUS_NOT_SUPPORTED without changing anything. The callback'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 timer thread that cannot store its mark reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE and runs no callback. Stop and destroy wake a timer thread that waits for its next expiry (one process-wide priority-inheritance mutex and condition variable, created by the first timer or task create and never deleted; create returns RTE_STATUS_INTERNAL_ERROR and reports DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE once if it cannot be created), so they do not wait for the rest of the period. The join is an unbounded wait for the callback in progress.
Definition at line 182 of file rte_posix_osadapter_timer.c.
|
static |
The wait / callback loop of a timer thread (absolute monotonic deadline, one-shot or periodic, should_stop). A failed clock read or wait reports once and ends the loop without a further callback (see file header).
Definition at line 233 of file rte_posix_osadapter_timer.c.
|
static |
Sets PTHREAD_EXPLICIT_SCHED and the calling thread's own scheduling policy and priority on attr (OSA rule R1: scheduling fixed before the thread exists, without requesting a policy the creator does not already run under). Returns true only when pthread_getschedparam() and every attribute call succeeded; false makes the caller fall back to inherited scheduling (see file header). Does not report.
Definition at line 305 of file rte_posix_osadapter_timer.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 199 of file rte_posix_osadapter_timer.c.
|
static |
Timer thread: marks itself as this timer's thread for the self check, then runs the loop. Without the mark it runs no callback (see file header). Writes no shared field.
Definition at line 213 of file rte_posix_osadapter_timer.c.
|
static |
Local variables declarations
Definition at line 169 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 175 of file rte_posix_osadapter_timer.c.
|
static |
Definition at line 176 of file rte_posix_osadapter_timer.c.