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.c File Reference

Application Manager implementation. More...

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "safeapi/app/appmanager/sapi_appmanager.h"
#include "safeapi/redundancy/checksum/sapi_checksum.h"
#include "safeapi/redundancy/checkpoint/sapi_checkpoint.h"
#include "safeapi/utils/lifecycle/sapi_lifecycle.h"
#include "safeapi/oal/log/sapi_log.h"
#include "safeapi/oal/timer/sapi_timer.h"
Include dependency graph for sapi_appmanager.c:

Go to the source code of this file.

Macros

#define _POSIX_C_SOURCE   200809L
 struct sigaction/sigaction()/sigemptyset() below are POSIX.1-2001, not base ISO C99 - must be defined before ANY header is included (same rule/pattern as safeAPIRBC2oo2's channel_ab.c/site.c/ monitor_c.c). Without this, glibc's strict-C99 mode hides these declarations entirely: this exact omission passed on macOS (Apple's libc does not gate them behind the same feature-test macro) but failed Linux CI with "storage size of 'sa' isn't known" / implicit-declaration errors under -Werror - caught via a real GitHub Actions failure, not local testing.
#define SAPI_APPMANAGER_HAVE_POSIX_SIGNALS   0
 1 when compiled on a POSIX-ish target (signal.h available) so sapi_appmanager_install_default_signal_handlers() can install a real SIGINT/SIGTERM handler; 0 otherwise, in which case that function returns SAPI_STATUS_NOT_SUPPORTED.

Functions

static bool sapi_appmanager_handle_stage_result (sapi_status_t status, const char *stage_name, uint32_t error_threshold)
 Records the outcome of one per-cycle stage (checkpoint, pre_execute, execute, or post_execute) against the shared error accounting, and decides whether the remaining stages of this cycle should run.
static void sapi_appmanager_checkpoint_signature_reset (void)
 Resets g_checkpoint_signature to a fixed seed and marks it active for the current cycle - called once per sapi_appmanager_run() loop iteration, before pre_execute() (ADR-034).
static void sapi_appmanager_encode_u64_le (uint8_t out[8], uint64_t value)
 Packs a uint64_t into an 8-byte buffer, explicit little-endian - same convention sapi_checkpoint.c's own build_arrival_message() already uses, so a fold computed on one CPU architecture and compared against a peer's own fold on a different architecture still agrees (no raw struct/memcpy of a multi-byte integer across a network).
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.
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.
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.

Variables

static sapi_appmanager_state_t g_app_state
 Global application state (single instance; no dynamic allocation).
static volatile int g_shutdown_requested = 0
 Set by the installed signal handler (or sapi_appmanager_request_shutdown()) to request that sapi_appmanager_run()'s loop exit cleanly.
static uint64_t g_checkpoint_signature
 Running per-cycle checkpoint-mark signature (ADR-034) - see sapi_appmanager_checkpoint_mark()'s own doc in the header. Reset once per cycle by sapi_appmanager_checkpoint_signature_reset(); folded by every sapi_appmanager_checkpoint_mark() call in between. Deliberately NOT part of the public sapi_appmanager_state_t (no consumer needs to read it directly - only the folded checkpoint_id, computed on demand by sapi_appmanager_checkpoint_fold_signature(), leaves this file).
static bool g_checkpoint_signature_active
 True once g_checkpoint_signature has been reset for the CURRENT sapi_appmanager_run() cycle - see sapi_appmanager_checkpoint_mark()'s doc: a mark call outside an active cycle (before the loop starts, or after it ends) is a documented no-op rather than silently folding into whatever a NEXT, unrelated run's first cycle computes.

Detailed Description

Application Manager implementation.

Provides lifecycle management for safety-critical applications.

Definition in file sapi_appmanager.c.

Macro Definition Documentation

◆ _POSIX_C_SOURCE

#define _POSIX_C_SOURCE   200809L

struct sigaction/sigaction()/sigemptyset() below are POSIX.1-2001, not base ISO C99 - must be defined before ANY header is included (same rule/pattern as safeAPIRBC2oo2's channel_ab.c/site.c/ monitor_c.c). Without this, glibc's strict-C99 mode hides these declarations entirely: this exact omission passed on macOS (Apple's libc does not gate them behind the same feature-test macro) but failed Linux CI with "storage size of 'sa' isn't known" / implicit-declaration errors under -Werror - caught via a real GitHub Actions failure, not local testing.

Definition at line 13 of file sapi_appmanager.c.

◆ SAPI_APPMANAGER_HAVE_POSIX_SIGNALS

#define SAPI_APPMANAGER_HAVE_POSIX_SIGNALS   0

1 when compiled on a POSIX-ish target (signal.h available) so sapi_appmanager_install_default_signal_handlers() can install a real SIGINT/SIGTERM handler; 0 otherwise, in which case that function returns SAPI_STATUS_NOT_SUPPORTED.

Definition at line 50 of file sapi_appmanager.c.

Function Documentation

◆ sapi_appmanager_handle_stage_result()

bool sapi_appmanager_handle_stage_result ( sapi_status_t status,
const char * stage_name,
uint32_t error_threshold )
static

Records the outcome of one per-cycle stage (checkpoint, pre_execute, execute, or post_execute) against the shared error accounting, and decides whether the remaining stages of this cycle should run.

Centralizes the "log, count against error_count, check error_threshold" behavior that ADR-019's checkpoint/pre_execute/post_execute stages share with execute()'s pre-existing error handling, so all four stages react to a non-OK status identically (REQ-APPMANAGER-007).

Parameters
statusStatus returned by the stage that just ran.
stage_nameShort, human-readable stage name for the log line on failure (e.g. "checkpoint", "pre_execute"). Must not be NULL.
error_thresholdErrors before shutdown (0 = no limit), forwarded from sapi_appmanager_config_t::error_threshold.
Returns
true if status is SAPI_STATUS_OK (caller should proceed to the next stage of this cycle); false otherwise (caller should skip the remaining stages for this cycle - g_app_state.error_count and, if error_threshold was reached, g_shutdown_requested have already been updated).

Definition at line 87 of file sapi_appmanager.c.

◆ sapi_appmanager_checkpoint_signature_reset()

void sapi_appmanager_checkpoint_signature_reset ( void )
static

Resets g_checkpoint_signature to a fixed seed and marks it active for the current cycle - called once per sapi_appmanager_run() loop iteration, before pre_execute() (ADR-034).

Definition at line 136 of file sapi_appmanager.c.

◆ sapi_appmanager_encode_u64_le()

void sapi_appmanager_encode_u64_le ( uint8_t out[8],
uint64_t value )
static

Packs a uint64_t into an 8-byte buffer, explicit little-endian - same convention sapi_checkpoint.c's own build_arrival_message() already uses, so a fold computed on one CPU architecture and compared against a peer's own fold on a different architecture still agrees (no raw struct/memcpy of a multi-byte integer across a network).

Definition at line 150 of file sapi_appmanager.c.

Variable Documentation

◆ g_app_state

sapi_appmanager_state_t g_app_state
static
Initial value:
= {
.iteration_count = 0,
.error_count = 0,
.last_error = SAPI_STATUS_OK
}
@ SAPI_APP_STATE_UNINITIALIZED
@ SAPI_STATUS_OK
Definition sapi_status.h:28

Global application state (single instance; no dynamic allocation).

Definition at line 54 of file sapi_appmanager.c.

◆ g_shutdown_requested

volatile int g_shutdown_requested = 0
static

Set by the installed signal handler (or sapi_appmanager_request_shutdown()) to request that sapi_appmanager_run()'s loop exit cleanly.

Definition at line 63 of file sapi_appmanager.c.

◆ g_checkpoint_signature

uint64_t g_checkpoint_signature
static

Running per-cycle checkpoint-mark signature (ADR-034) - see sapi_appmanager_checkpoint_mark()'s own doc in the header. Reset once per cycle by sapi_appmanager_checkpoint_signature_reset(); folded by every sapi_appmanager_checkpoint_mark() call in between. Deliberately NOT part of the public sapi_appmanager_state_t (no consumer needs to read it directly - only the folded checkpoint_id, computed on demand by sapi_appmanager_checkpoint_fold_signature(), leaves this file).

Definition at line 121 of file sapi_appmanager.c.

◆ g_checkpoint_signature_active

bool g_checkpoint_signature_active
static

True once g_checkpoint_signature has been reset for the CURRENT sapi_appmanager_run() cycle - see sapi_appmanager_checkpoint_mark()'s doc: a mark call outside an active cycle (before the loop starts, or after it ends) is a documented no-op rather than silently folding into whatever a NEXT, unrelated run's first cycle computes.

Definition at line 129 of file sapi_appmanager.c.