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

Application Manager abstraction for safeAPIFramework applications. More...

Include dependency graph for sapi_appmanager.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  sapi_appmanager_operations_t
 Application lifecycle operations. More...
struct  sapi_appmanager_checkpoint_config_t
 Optional built-in checkpoint rendezvous configuration (ADR-019/ADR-034). More...
struct  sapi_appmanager_config_t
 Application manager configuration. More...
struct  sapi_appmanager_state_t
 Application manager runtime state. More...

Macros

#define SAPI_APPMANAGER_CHECKPOINT_SIGNATURE_SEED   ((uint64_t)0xFFFFFFFFFFFFFFFFULL)
 Reset value of the per-cycle checkpoint signature before any marks are folded into it (ADR-034) - see sapi_appmanager_checkpoint_fold_signature()'s own doc. A cycle in which no SAPI_CHECKPOINT_MARK() call is ever made therefore always computes checkpoint_id as sapi_appmanager_checkpoint_fold_signature(SAPI_APPMANAGER_CHECKPOINT_SIGNATURE_SEED).
#define SAPI_CHECKPOINT_MARK()
 Records a checkpoint mark for this call site (ADR-034) - see sapi_appmanager_checkpoint_mark()'s own doc.
#define SAPI_CHECKPOINT_MARK_LABEL(label_str)
 Records a checkpoint mark identified by a caller-supplied label instead of this call site's file:line (ADR-034) - see sapi_appmanager_checkpoint_mark()'s own doc.

Enumerations

enum  sapi_app_state_t {
  SAPI_APP_STATE_UNINITIALIZED = 0 , SAPI_APP_STATE_INITIALIZING = 1 , SAPI_APP_STATE_RUNNING = 2 , SAPI_APP_STATE_SHUTTING_DOWN = 3 ,
  SAPI_APP_STATE_SHUTDOWN = 4 , SAPI_APP_STATE_ERROR = 5
}
 Application state enumeration. More...

Functions

uint32_t sapi_appmanager_checkpoint_fold_signature (uint64_t signature)
 Pure helper: folds a 64-bit checkpoint signature down to the uint32_t sapi_checkpoint_config_t::checkpoint_id expects (ADR-034).
void sapi_appmanager_checkpoint_mark (const char *file, int32_t line, const char *label)
 Folds a hash of this call site into the current cycle's checkpoint signature (ADR-034).
int sapi_appmanager_run (const sapi_appmanager_config_t *config)
 Run application with lifecycle management.
sapi_app_state_t sapi_appmanager_get_state (void)
 Get current application state.
sapi_status_t sapi_appmanager_get_stats (sapi_appmanager_state_t *state)
 Get application statistics.
void sapi_appmanager_request_shutdown (void)
 Request application shutdown.
sapi_status_t sapi_appmanager_install_default_signal_handlers (void)
 POSIX-only convenience: installs SIGINT and SIGTERM handlers that call sapi_appmanager_request_shutdown(), so an operator (Ctrl+C) or process manager (SIGTERM) can stop a sapi_appmanager_run() loop gracefully - shutdown() still runs, this is not a hard kill.
void sapi_appmanager_reset_state (void)
 Forcibly resets the application manager's own bookkeeping (lifecycle state, iteration/error counters, shutdown-request flag, and the ADR-026 setup-phase lock) back to its initial, pre-run condition.

Detailed Description

Application Manager abstraction for safeAPIFramework applications.

Provides a single entry point pattern for safety-critical applications with well-defined lifecycle: initialize → execute → shutdown.

Each application implements the sapi_appmanager_operations_t interface:

  • init() — One-time initialization
  • pre_execute() — Optional, per-cycle input/prepare stage (may be NULL)
  • execute() — Main application loop (mandatory)
  • post_execute() — Optional, per-cycle output/cleanup stage (may be NULL)
  • shutdown() — Graceful cleanup

The sapi_appmanager_run() function manages lifecycle and error handling. Per ADR-019/ADR-034, it can also be configured (sapi_appmanager_config_t::checkpoint) to perform a bounded sapi_channel_checkpoint() rendezvous (ADR-017) as the LAST stage of every cycle, after pre_execute/execute/post_execute, so a dual/multi-channel application does not have to hand-roll that call itself; this is opt-in and defaults to disabled (NULL).

ADR-034: the checkpoint's own checkpoint_id is no longer a bare cycle counter (that broke across an independent reboot of just one channel - see sapi_appmanager_checkpoint_config_t's own doc). Instead, application code calls SAPI_CHECKPOINT_MARK() (or the labelled variant, SAPI_CHECKPOINT_MARK_LABEL()) at meaningful decision/preparation points during pre_execute()/execute()/post_execute(); each call folds a CRC64 hash of its call site (by default FILE:LINE, or a caller-supplied label) into a single running per-cycle signature. The checkpoint stage then rendezvous-compares THIS cycle's own folded signature with the peer's - so a match proves both channels reached the exact same sequence of marks this cycle (the same program path), not merely "both channels are alive." If ops->on_checkpoint_result is non-NULL, it is called exactly once per cycle with the outcome, letting an application stage (queue but not transmit) its outputs during the cycle and only commit (actually send) them once the checkpoint confirms both channels agree - see that field's own doc.

REQ-APPMANAGER-001: Applications shall use the Application Manager for controlled initialization, execution, and shutdown lifecycle.

ADR-026: the moment init() returns SAPI_STATUS_OK, sapi_appmanager_run() locks the application's setup phase (sapi_lifecycle_lock() - see sapi_lifecycle.h) - 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()) then rejects with SAPI_STATUS_INVALID_STATE for the remainder of this run: a timer/channel/voter/cross-comparator/ watchdog an application's own init() did not already create is not one its execute()/pre_execute()/post_execute() may create either. sapi_netlink_open()/sapi_dual_channel_init()/sapi_dual_negotiator_init() are deliberately NOT gated by this lock - see sapi_lifecycle.h's own doc for why a link an application already owns being re-established after a drop is not the same thing this lock exists to prevent.

Note
Unlike the seven OAL services (sapi_timer, sapi_nvm, sapi_memory, sapi_task, sapi_ipc, sapi_log, sapi_reboot), this module is not backend-dispatched (ADR-005) - it is a direct, OS-agnostic implementation, same as sapi_safestate. sapi_appmanager_install_default_signal_handlers() below is a deliberate, narrow exception to that OS-agnosticism: it is a POSIX-only convenience, compiled out (returns SAPI_STATUS_NOT_SUPPORTED) on any non-POSIX target. It exists because "let something external ask a long-running sapi_appmanager_run() loop to stop" is such a common integration need on POSIX hosts that most integrators would otherwise reimplement the same few lines of sigaction() themselves - see that function's own doc for the exact scope of the exception.

Definition in file sapi_appmanager.h.