Safe API Framework
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
sapi_lifecycle.h File Reference

Process-wide application setup-phase lock (ADR-026). More...

#include <stdbool.h>
#include "safeapi/utils/status/sapi_status.h"
Include dependency graph for sapi_lifecycle.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

void sapi_lifecycle_lock (void)
 Locks the application's setup phase.
void sapi_lifecycle_unlock (void)
 Unlocks the application's setup phase (setup is allowed again).
bool sapi_lifecycle_is_locked (void)
sapi_status_t sapi_lifecycle_check_setup_allowed (void)
 Convenience check for a setup-only constructor: call this as one of the first checks in any function that creates/registers a new long-lived resource (a timer, channel, voter, cross-comparator, or watchdog - see this file's own header for the excluded netlink/dual exceptions).

Detailed Description

Process-wide application setup-phase lock (ADR-026).

A safety-critical application shall have a well-defined INIT phase (create timers, channels, voters, cross-comparators, watchdogs) that completes before its RUN phase begins - and once RUN has begun, no further such construction is legitimate: an application whose resource set can still change while it is executing cyclically is not one whose behavior can be fully verified ahead of time.

sapi_appmanager_run() is this framework's own INIT/RUN boundary: it calls sapi_lifecycle_lock() the moment ops->init() returns successfully (see that function's own doc) and sapi_lifecycle_unlock() at the very start of every call (mirroring its own existing g_app_state reset - see sapi_appmanager.c). Every setup-only constructor this framework ships (sapi_timer_create(), sapi_channel_init(), sapi_voter_init()/_register_channel(), sapi_cross_comparator_init()/_register_channel(), sapi_watchdog_create()) calls sapi_lifecycle_check_setup_allowed() as one of its own first checks and returns SAPI_STATUS_INVALID_STATE once locked - see each function's own doc for exactly where.

Deliberately excluded (ADR-026 section 3): sapi_netlink_open(), sapi_dual_channel_init(), and sapi_dual_negotiator_init() are NOT gated by this lock. All three are legitimately re-invoked after RUN has begun by an application's own reconnect-after-link-loss logic (e.g. safeAPIRBC2oo2's channel_ab_io.c/channel_ab_negotiate_reconnect()), which is re-establishing a link the application already owns, not adding a new one the application's own design never accounted for - see ADR-026 for the full rationale on why that distinction, not the "called after RUN" timing alone, is what this lock actually polices.

This is a single, process-wide flag (ADR-026 section 2, same single-instance assumption sapi_appmanager's own g_app_state already makes - see that module's own file header) - not one lock per sapi_appmanager_config_t, since this framework has no concept of more than one concurrently-running application per process today.

REQ-LIFECYCLE-001: setup-only constructors shall reject their call with SAPI_STATUS_INVALID_STATE once the application's setup phase has been locked. REQ-LIFECYCLE-002: the setup-phase lock shall be a plain, unsynchronized global (no dynamic allocation, no OS dependency) - this module has no OS dependency of its own, matching sapi_safestate's own posture (ADR-002 section 4).

Definition in file sapi_lifecycle.h.