RTE RBC 2oo2 Reference Application 0.1.0 build 0006685
SIL 4 2oo2 Dual-Site Fault-Tolerant ERTMS Radio Block Centre Reference Architecture
Loading...
Searching...
No Matches
main.c File Reference

safeAPIRBC2oo2: channel A/B binary, started as role A or B, for site WEST or EAST. C is a separate binary (C/main_c.c) - see app_main_common.c for the runtime setup shared by both. This file is the whole AB channel's own composition root: it owns both how the process starts up and how its cyclic executive is wired - deliberately kept that way so a reader can open just this file and see the whole story, rather than having to also read AB/GP/com/ab_gp_channel.c to find out how the process comes up or what each cycle does. AB/GP/com/ab_gp_channel.c is the channel factory and the real per-cycle implementation this file wires onto - see that file's own header for the mechanism; this one is the narrative. More...

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "rte/app/appmanager/rte_appmanager.h"
#include "rte/oal/log/rte_log.h"
#include "rte/oal/memory/rte_mem_util.h"
#include "rte/posix_osadapter/rte_posix_osadapter.h"
#include "ab_gp_channel_cycle_hooks.h"
#include "../com/ab_gp_channel.h"
#include "../com/ab_gp_jru_forward.h"
#include "../../common/app_main_common.h"
#include "../../common/rbc_util_frame.h"
#include "../../common/site_config.h"
#include "rte/core/rte_core_version.h"
#include "rte_rbc2oo2_version.h"
#include "rte_gp_run.h"
Include dependency graph for main.c:

Go to the source code of this file.

Functions

static int fatal_setup_step_failed (const char *step, rte_status_t status, ab_gp_channel_handle_t handle)
static rte_appmanager_config_t ab_gp_channel_make_config (ab_gp_channel_handle_t handle)
 Builds the rte_appmanager_config_t for running an already-opened, already-wired channel (ab_gp_channel_open_link() plus whichever of this file's own "Startup sequence" setup steps the caller already ran on it - see main()'s own body above). config.context is handle itself - safe to use for as long as the process keeps running (the underlying context is a static, single-instance- per-process object, never freed).
static const char * ab_gp_channel_get_name (void)
static const char * ab_gp_channel_get_version (void)
int rte_gp_run (int argc, char **argv)

Detailed Description

safeAPIRBC2oo2: channel A/B binary, started as role A or B, for site WEST or EAST. C is a separate binary (C/main_c.c) - see app_main_common.c for the runtime setup shared by both. This file is the whole AB channel's own composition root: it owns both how the process starts up and how its cyclic executive is wired - deliberately kept that way so a reader can open just this file and see the whole story, rather than having to also read AB/GP/com/ab_gp_channel.c to find out how the process comes up or what each cycle does. AB/GP/com/ab_gp_channel.c is the channel factory and the real per-cycle implementation this file wires onto - see that file's own header for the mechanism; this one is the narrative.

WEST: A <-> B EAST: A <-> B | | C C

A-WEST <-----> A-EAST (inter-site negotiation link, this channel's own) B-WEST <-----> B-EAST (inter-site negotiation link, this channel's own)

Hot standby: both sites always run their own full A/B/C group; only each site's own C tags its output ACTIVE (this site is ONLINE) or SUPPRESSED (STANDBY), per that site's own live role - negotiated directly between A and B, one independent negotiation link per channel (no standalone SITE role - see AB/GP/com/ab_gp_channel_negotiate.c, C/monitor_c_report.c, and README).

Usage: run six instances across these two binaries (role x site, in any order, in separate terminals/containers - or separate machines, once each CONNECT-role link's RTE_EXAMPLE_*_HOST_ENV is pointed at a real remote host instead of 127.0.0.1 - see common_config.h and docker-compose.yml): rte_example A WEST rte_example B WEST rte_monitor_c WEST rte_example A EAST rte_example B EAST rte_monitor_c EAST (etc/run_all.sh launches all six.)


Startup sequence

After argv parsing and app_main_common_init() (installs SIGINT/SIGTERM handlers - see below), main() runs twelve setup steps against AB/GP/com/ab_gp_channel.c before ever calling rte_appmanager_run() - this is deliberate: ab_gp_channel_init() (the actual rte_appmanager_operations_t::init hook) is kept genuinely minimal (just resets this run's own per-cycle counters), so every one of these steps runs here instead, where a failure gets uniform cleanup via ab_gp_channel_close_link() - see that function's own doc, and ab_gp_channel.c's file header, for why that matters (rte_appmanager_run()'s own "shutdown on init failure" safety net only covers code that runs as the init() hook itself, which none of this does anymore):

  1. ab_gp_channel_open_link() - FATAL. Opens the actual A<->B peer link (A listens, B connects-with-retry). Self- cleans on its own failure - see its own doc for why this one step alone must NOT be followed by ab_gp_channel_close_link().
  2. ab_gp_channel_train_codec_setup() - FATAL. Registers train/'s own ab_gp_train_session_t codec.
  3. ab_gp_channel_ga_setup() - FATAL. GA module registration (ma_logic_adaptation/ il/ctc).
  4. ab_gp_channel_relay_queues_setup() - Initializes every relay_rx_queue[kind][index]. Cannot fail. 4a. ab_gp_channel_saf_train_setup() - FATAL. Train-link SaF termination from RTE_SAFECOMM_TRAIN_RBC_ID (unset = off); a set but invalid value aborts rather than run unprotected.
  5. ab_gp_channel_negotiate_setup() - FATAL. Opens this channel's own inter-site negotiation link and settles the startup tie-break.
  6. ab_gp_channel_checkpoint_setup() - non-fatal. Wires the built-in AppManager checkpoint mechanism.
  7. ab_gp_channel_dual_setup() - non-fatal. Arms the dual- transfer liveness watchdog (single-mode degradation on peer silence).
  8. ab_gp_channel_watchdog_setup() - non-fatal. Arms this channel's general health watchdog.
  9. ab_gp_channel_crosscompare_setup() - FATAL. Creates the real A-vs-B rte_cross_comparator_t every cycle's decision uses.

ab_gp_channel_peer_rx_task_setup() - FATAL. Starts the background peer-rx task.

  1. ab_gp_channel_relay_tasks_setup() - FATAL. Starts every per- {client-type, instance} relay- connect background task.
  2. ab_gp_channel_cycle_timer_setup() - FATAL. Arms the periodic cycle timer. A non-fatal step's own failure just disables that one subsystem for the run (logged internally - see each function's own doc in ab_gp_channel.h); a fatal step's failure (after step 1 has already succeeded) logs, calls ab_gp_channel_close_link(handle), and aborts startup - see fatal_setup_step_failed() below. Once all twelve have run, ab_gp_channel_make_config() (below) assembles the rte_appmanager_config_t and main() hands off to rte_appmanager_run() for the cyclic executive proper.

A and B then run their rte_appmanager loop forever (real 500ms cyclic executive), so something has to be able to stop them: app_main_common_init() installs SIGINT/SIGTERM handlers that call rte_appmanager_request_shutdown(), which the app manager checks at the top of its loop and turns into a graceful stop (ab_gp_channel_shutdown() still runs - links/watchdog/timer/task all get closed down cleanly, not just killed).


The main loop: three hooks, one cycle every 500ms

ab_gp_channel_pre_execute()/ab_gp_channel_execute()/ab_gp_channel_post_execute() (ab_gp_channel_cycle_hooks.h) - the rte_appmanager_operations_t hooks rte_appmanager_run() calls every cycle - are each their own file in this directory (pre_execute.c/execute.c/post_execute.c), not defined here: each is a short orchestrator sequencing calls into AB/GP/com/ab_gp_channel.c's own named, single-purpose step functions, which hold the real logic (that file's ab_gp_channel_context_t stays fully private to it - main/'s own files, including this one, only ever hold the opaque ab_gp_channel_handle_t returned by ab_gp_channel_open_link()). In short, each cycle: pre_execute() - gather this cycle's inputs: the latest M136 from C, the latest AB_SAMPLE from the peer, this channel's own West<->East negotiation result. execute() - the decision logic: AB/logic's route<->train connect sweep, then the actual AGREE/DISAGREE cross-compare. post_execute() - send this cycle's outputs: the peer sample (dual transfer) and, on AGREE (or SINGLE mode), the agreed M24/M15/M3/CTC_* answers forwarded to C. See ab_gp_channel.c's own file header for the full phase-by-phase breakdown (checkpoint/dual-transfer/inter-site-negotiation reasoning included) - this summary is deliberately the short version.

Definition in file main.c.

Function Documentation

◆ fatal_setup_step_failed()

int fatal_setup_step_failed ( const char * step,
rte_status_t status,
ab_gp_channel_handle_t handle )
static

Local makros Local types declarations Local variables declarations Global variables declarations Local function declarations

Logs step's own failing status, tears down handle via ab_gp_channel_close_link() (safe here since ab_gp_channel_open_link() has already succeeded by the time any of main()'s later setup steps can fail - see this file's own "Startup sequence" header doc), and returns the process exit code main() itself uses for every fatal setup-step failure after step 1.

Definition at line 330 of file main.c.

◆ ab_gp_channel_make_config()

rte_appmanager_config_t ab_gp_channel_make_config ( ab_gp_channel_handle_t handle)
static

Builds the rte_appmanager_config_t for running an already-opened, already-wired channel (ab_gp_channel_open_link() plus whichever of this file's own "Startup sequence" setup steps the caller already ran on it - see main()'s own body above). config.context is handle itself - safe to use for as long as the process keeps running (the underlying context is a static, single-instance- per-process object, never freed).

Parameters
handleA handle from a successful ab_gp_channel_open_link() call.
Returns
A config ready to pass to rte_appmanager_run().

Definition at line 351 of file main.c.

◆ ab_gp_channel_get_name()

const char * ab_gp_channel_get_name ( void )
static

rte_appmanager_operations_t::get_name - trivial, no channel state needed, so this lives here rather than behind an accessor into ab_gp_channel.c's own private context.

Definition at line 391 of file main.c.

◆ ab_gp_channel_get_version()

const char * ab_gp_channel_get_version ( void )
static

rte_appmanager_operations_t::get_version - see ab_gp_channel_get_name()'s own doc.

Definition at line 398 of file main.c.

◆ rte_gp_run()

int rte_gp_run ( int argc,
char ** argv )

Global functions Real entry point, exported from librte_gp (this project's own shared library, later session's own GP<->GA symmetric dummy-then-real linking pass - see safeAPIRBC2oo2GA/CLAUDE.md's own doc on why rte_example became a thin launcher over this library instead of a monolithic executable). Body unchanged from the old plain int main(int argc, char **argv) - only the name/export changed, so launcher_main.c's own int main() can call it.

Definition at line 189 of file main.c.