Safe API Framework 0.1.0 build 384e6ae
Layered API framework for safety-related applications (ERTMS RBC reference targeting CENELEC EN 50128 SIL 4)
Loading...
Searching...
No Matches
Voter (N-way channel voting)

Files

file  src/redundancy/voter/rte_voter.c
 N-way voting engine (ADR-025): validates parameters, dispatches send/receive to every registered healthy channel, and - for receive - groups the responses by mutual agreement and picks the largest group meeting quorum.

Data Structures

struct  rte_voter_config_t
 Configuration for rte_voter_init(). More...
struct  rte_voter_storage_t
 Storage for one voter instance (opaque to caller). No dynamic memory. More...

Macros

#define RTE_VOTER_MAX_CHANNELS   8U
 Maximum number of channels a single voter can register.
#define RTE_VOTER_MAX_MESSAGE_SIZE   256U
 Maximum payload size rte_voter_send()/_receive() supports.

Typedefs

typedef bool(*) rte_voter_compare_fn(const void *a, const void *b, size_t size, void *user_ctx)
 Optional custom comparison callback.
typedef rte_voter_storage_t rte_voter_t
 Opaque handle to a voter instance.

Enumerations

enum  rte_voting_strategy_t { RTE_VOTING_2OO2 = 1 , RTE_VOTING_2OO3 = 2 , RTE_VOTING_NMR = 3 }
 Voting strategy: how many registered channels must agree. More...
enum  rte_voting_result_t { RTE_VOTING_AGREED = 0 , RTE_VOTING_DISAGREED = 1 , RTE_VOTING_TIMEOUT = 2 , RTE_VOTING_INSUFFICIENT_QUORUM = 3 }
 Outcome of one rte_voter_receive() call. More...

Functions

rte_status_t rte_voter_init (rte_voter_storage_t *storage, const rte_voter_config_t *config)
 Initializes a voter with zero registered channels.
rte_status_t rte_voter_register_channel (rte_voter_t *voter, rte_channel_t *channel)
 Registers one already-initialized channel with this voter.
rte_status_t rte_voter_send (rte_voter_t *voter, const void *data, size_t data_size)
 Broadcasts data to every registered, healthy channel.
rte_status_t rte_voter_receive (rte_voter_t *voter, void *data, size_t data_size, rte_voting_result_t *result, size_t *bytes_received)
 Receives from every registered, healthy channel and votes.
rte_status_t rte_voter_vote_buffers (rte_voter_t *voter, const void *const *buffers, uint32_t buffer_count, size_t data_size, rte_voting_result_t *result, void *out_data, size_t *out_size)
 N-way vote on caller-collected buffers, without any registered-channel I/O (ADR-039's N-way cross-compare half: rte_voter used directly, buffer-based, matching rte_cross_comparator_execute_buffers()'s existing shape - decided over building a separate primitive). Same grouping/quorum logic as rte_voter_receive() (REQ-VOTER-004), applied to buffers instead of polling registered channels - this function performs no I/O and ignores any channels registered on voter (same posture rte_cross_comparator_execute_buffers() already established for its own module: a Voter (N-way channel voting) with zero registered channels is a legitimate, expected call shape here).
rte_status_t rte_voter_get_aggregated_health (const rte_voter_t *voter, uint32_t *healthy_count, uint32_t *total_disagreements)
 Aggregated health across every registered channel.
uint32_t rte_voter_get_channel_count (const rte_voter_t *voter)
 Number of channels currently registered with this voter.
rte_channel_t * rte_voter_get_channel (const rte_voter_t *voter, uint32_t index)
 Direct access to one registered channel, by index.
rte_channel_t * rte_voter_get_channel_by_name (const rte_voter_t *voter, const char *name)
 Direct access to one registered channel, by name (e.g. "ChannelAtoB") - the name each channel was given via rte_channel_config_t::name at its own rte_channel_init() time.
rte_status_t rte_voter_destroy (rte_voter_t *voter)
 Destroys a voter instance.

Detailed Description

Macro Definition Documentation

◆ RTE_VOTER_MAX_CHANNELS

#define RTE_VOTER_MAX_CHANNELS   8U

Maximum number of channels a single voter can register.

Definition at line 132 of file rte_voter.h.

◆ RTE_VOTER_MAX_MESSAGE_SIZE

#define RTE_VOTER_MAX_MESSAGE_SIZE   256U

Maximum payload size rte_voter_send()/_receive() supports.

Definition at line 135 of file rte_voter.h.

Typedef Documentation

◆ rte_voter_compare_fn

typedef bool(*) rte_voter_compare_fn(const void *a, const void *b, size_t size, void *user_ctx)

Optional custom comparison callback.

If not registered (rte_voter_config_t::compare == NULL), the default is a full byte compare (memcmp(a, b, size) == 0) - the payloads being compared have already had their transport-integrity CRC verified by the channel layer (rte_checksum) if the OSAdapter uses rte_checksum_vital_message_verify(); this callback is about semantic/value comparison, not integrity checking.

Parameters
[in]aFirst buffer.
[in]bSecond buffer.
[in]sizeNumber of bytes to compare.
[in]user_ctxrte_voter_config_t::compare_context, passed through verbatim.
Returns
true if a and b are considered equal for voting purposes.

Definition at line 82 of file rte_voter.h.

◆ rte_voter_t

Opaque handle to a voter instance.

Definition at line 149 of file rte_voter.h.

Enumeration Type Documentation

◆ rte_voting_strategy_t

Voting strategy: how many registered channels must agree.

Enumerator
RTE_VOTING_2OO2 

2 out of 2: both channels must agree.

RTE_VOTING_2OO3 

2 out of 3: majority among 3 channels, tolerates 1 fault.

RTE_VOTING_NMR 

N out of M: rte_voter_config_t::quorum_size of registered channels must agree.

Definition at line 42 of file rte_voter.h.

◆ rte_voting_result_t

Outcome of one rte_voter_receive() call.

Enumerator
RTE_VOTING_AGREED 

A quorum-sized group of channels agreed on the data.

RTE_VOTING_DISAGREED 

No group of channels large enough to meet quorum agreed.

RTE_VOTING_TIMEOUT 

One or more channels timed out.

RTE_VOTING_INSUFFICIENT_QUORUM 

Fewer than the required number of healthy/responding channels.

Definition at line 54 of file rte_voter.h.

Function Documentation

◆ rte_voter_init()

rte_status_t rte_voter_init ( rte_voter_storage_t * storage,
const rte_voter_config_t * config )

Initializes a voter with zero registered channels.

Parameters
[out]storagePre-allocated storage. Must not be NULL.
[in]configVoting configuration. Must not be NULL. For RTE_VOTING_NMR, config->quorum_size must be >= 1.
Returns
RTE_STATUS_OK on success
RTE_STATUS_INVALID_PARAM if storage/config is NULL, or (NMR strategy and quorum_size == 0)

REQ-VOTER-001: No dynamic allocation; fixed RTE_VOTER_MAX_CHANNELS array. REQ-VOTER-002: Rejects an unrecognized voting_strategy, or NMR with quorum_size == 0.

Definition at line 201 of file rte_voter.c.

◆ rte_voter_register_channel()

rte_status_t rte_voter_register_channel ( rte_voter_t * voter,
rte_channel_t * channel )

Registers one already-initialized channel with this voter.

Parameters
[in]voterVoter handle. Must not be NULL and must be initialized.
[in]channelAlready rte_channel_init()'d channel. Must not be NULL.
Returns
RTE_STATUS_OK on success
RTE_STATUS_INVALID_PARAM if voter/channel is NULL
RTE_STATUS_NOT_INITIALIZED if voter was never initialized
RTE_STATUS_RESOURCE_EXHAUSTED if RTE_VOTER_MAX_CHANNELS are already registered
Postcondition
For RTE_VOTING_2OO2/2OO3, rte_voter_send()/_receive() require exactly 2/3 channels to be registered respectively before use; calling them with the wrong count returns RTE_STATUS_INVALID_PARAM.

Definition at line 240 of file rte_voter.c.

◆ rte_voter_send()

rte_status_t rte_voter_send ( rte_voter_t * voter,
const void * data,
size_t data_size )

Broadcasts data to every registered, healthy channel.

Parameters
[in]voterVoter handle. Must not be NULL and initialized.
[in]dataData to send. Must not be NULL.
[in]data_sizeSize in bytes; must be > 0 and <= RTE_VOTER_MAX_MESSAGE_SIZE.
Returns
RTE_STATUS_OK if every healthy channel accepted the send
RTE_STATUS_INVALID_PARAM for a bad argument or wrong registered-channel count for a fixed strategy (2OO2/2OO3)
RTE_STATUS_RESOURCE_EXHAUSTED if data_size exceeds the max
RTE_STATUS_HARDWARE_FAULT if no channel is healthy, or any healthy channel's send failed

REQ-VOTER-003: Requires the registered-channel count to match the configured strategy before sending.

Definition at line 269 of file rte_voter.c.

◆ rte_voter_receive()

rte_status_t rte_voter_receive ( rte_voter_t * voter,
void * data,
size_t data_size,
rte_voting_result_t * result,
size_t * bytes_received )

Receives from every registered, healthy channel and votes.

Groups the channels that responded successfully by mutual agreement (per config->compare, default memcmp); the largest group that meets the configured quorum wins - AGREED, with *data set to that group's value. If no group is large enough, DISAGREED. If fewer than 2 channels responded at all, TIMEOUT (0 responded) or INSUFFICIENT_QUORUM (1 responded, or not enough healthy channels to possibly meet quorum before even trying).

Parameters
[in]voterVoter handle. Must not be NULL and initialized.
[out]dataBuffer to receive the winning group's data. Must not be NULL.
[in]data_sizeSize of data buffer; must be > 0 and <= RTE_VOTER_MAX_MESSAGE_SIZE.
[out]resultVoting outcome. Can be NULL.
[out]bytes_receivedBytes written to data. Can be NULL.
Returns
RTE_STATUS_OK if result is RTE_VOTING_AGREED
RTE_STATUS_INVALID_PARAM for a bad argument or wrong registered-channel count for a fixed strategy
RTE_STATUS_HARDWARE_FAULT otherwise (DISAGREED/TIMEOUT/ INSUFFICIENT_QUORUM)
Postcondition
On RTE_VOTING_DISAGREED, this function invokes config->on_disagreement (if set) and then unconditionally enters config->safestate_level - it does not return unless that level is RTE_SAFESTATE_LEVEL_DEGRADED (the only level rte_safestate_enter() may return from).

REQ-VOTER-003: Requires the registered-channel count to match the configured strategy before receiving/voting. REQ-VOTER-004: Groups responses by mutual agreement and selects the largest quorum-meeting group (majority vote), not a pairwise compare against a single reference channel. REQ-VOTER-005: On DISAGREED, always invokes on_disagreement (if registered) and then unconditionally enters config->safestate_level.

Definition at line 331 of file rte_voter.c.

◆ rte_voter_vote_buffers()

rte_status_t rte_voter_vote_buffers ( rte_voter_t * voter,
const void *const * buffers,
uint32_t buffer_count,
size_t data_size,
rte_voting_result_t * result,
void * out_data,
size_t * out_size )

N-way vote on caller-collected buffers, without any registered-channel I/O (ADR-039's N-way cross-compare half: rte_voter used directly, buffer-based, matching rte_cross_comparator_execute_buffers()'s existing shape - decided over building a separate primitive). Same grouping/quorum logic as rte_voter_receive() (REQ-VOTER-004), applied to buffers instead of polling registered channels - this function performs no I/O and ignores any channels registered on voter (same posture rte_cross_comparator_execute_buffers() already established for its own module: a Voter (N-way channel voting) with zero registered channels is a legitimate, expected call shape here).

Parameters
[in]voterVoter handle (rte_voter_init()'d - registered channels, if any, are ignored). Must not be NULL.
[in]buffersArray of buffer_count already-collected buffers (e.g. each replica's own value for the same logical quantity, gathered by the caller over whatever transport it uses). Must not be NULL.
[in]buffer_countNumber of entries in buffers; must match voter->config. voting_strategy the same way rte_voter_receive()'s own registered- channel count must (REQ-VOTER-003, generalized to a caller-supplied count instead of a registered one) - RTE_STATUS_INVALID_PARAM otherwise. Must not exceed RTE_VOTER_MAX_CHANNELS.
[in]data_sizeBytes of each buffer to compare; must be > 0 and <= RTE_VOTER_MAX_MESSAGE_SIZE.
[out]resultVoting outcome (always RTE_VOTING_AGREED or RTE_VOTING_DISAGREED - there is no I/O here, so TIMEOUT/INSUFFICIENT_QUORUM never occur, same as rte_cross_comparator_execute_buffers()). Can be NULL.
[out]out_dataReceives the winning group's data on AGREED. Can be NULL.
[out]out_sizeBytes written to out_data. Can be NULL.
Returns
RTE_STATUS_OK if result is RTE_VOTING_AGREED.
RTE_STATUS_INVALID_PARAM for a bad argument, buffer_count exceeding RTE_VOTER_MAX_CHANNELS, or buffer_count not matching voter->config.voting_strategy.
RTE_STATUS_HARDWARE_FAULT on RTE_VOTING_DISAGREED - but see
Postcondition
: this function does not return in that case.
On RTE_VOTING_DISAGREED, identical to rte_voter_receive(): invokes config->on_disagreement (if set) and then unconditionally enters config->safestate_level.

Definition at line 480 of file rte_voter.c.

◆ rte_voter_get_aggregated_health()

rte_status_t rte_voter_get_aggregated_health ( const rte_voter_t * voter,
uint32_t * healthy_count,
uint32_t * total_disagreements )

Aggregated health across every registered channel.

Parameters
[in]voterVoter handle. Must not be NULL.
[out]healthy_countNumber of currently-healthy registered channels. Can be NULL.
[out]total_disagreementsRunning count of DISAGREED results returned by this voter. Can be NULL.
Returns
RTE_STATUS_OK on success
RTE_STATUS_INVALID_PARAM if voter is NULL

Definition at line 603 of file rte_voter.c.

◆ rte_voter_get_channel_count()

uint32_t rte_voter_get_channel_count ( const rte_voter_t * voter)

Number of channels currently registered with this voter.

Intended for callers (e.g. rte_channel_checkpoint()) that need to iterate the voter's registered channels directly rather than through send()/receive()'s own voting.

Parameters
[in]voterVoter handle. Must not be NULL.
Returns
Registered channel count, or 0 if voter is NULL.

Definition at line 622 of file rte_voter.c.

◆ rte_voter_get_channel()

rte_channel_t * rte_voter_get_channel ( const rte_voter_t * voter,
uint32_t index )

Direct access to one registered channel, by index.

Parameters
[in]voterVoter handle. Must not be NULL.
[in]index0-based index; must be < rte_voter_get_channel_count(voter).
Returns
The registered channel, or NULL if voter is NULL or index is out of range.

Definition at line 627 of file rte_voter.c.

◆ rte_voter_get_channel_by_name()

rte_channel_t * rte_voter_get_channel_by_name ( const rte_voter_t * voter,
const char * name )

Direct access to one registered channel, by name (e.g. "ChannelAtoB") - the name each channel was given via rte_channel_config_t::name at its own rte_channel_init() time.

Linear search over the registered channels (channel counts here are small - RTE_VOTER_MAX_CHANNELS - so this is not a hot-path lookup by design); compares with strcmp(), so an exact, case-sensitive match is required.

Parameters
[in]voterVoter handle. Must not be NULL.
[in]nameName to search for. Must not be NULL.
Returns
The first registered channel whose own name matches (exact strcmp() equality); NULL if voter or name is NULL, or no registered channel has a matching (non-NULL) name.

REQ-VOTER-006: Returns the first registered channel whose rte_channel_get_name() exactly (strcmp()) matches name; NULL if voter/name is NULL or no name matches (a channel with a NULL name is never matched, REQ-CHANNEL-005).

Definition at line 636 of file rte_voter.c.

◆ rte_voter_destroy()

rte_status_t rte_voter_destroy ( rte_voter_t * voter)

Destroys a voter instance.

No dynamic memory to free; registered channels are NOT destroyed (caller retains ownership).

Parameters
[in]voterVoter handle. May be NULL.
Returns
RTE_STATUS_OK always.
Safety:
Idempotent; safe to call with NULL.

Definition at line 656 of file rte_voter.c.