21static bool voter_channel_count_matches_strategy(
const rte_voter_t *voter, uint32_t channel_count)
28 ok = (channel_count == 2U);
31 ok = (channel_count == 3U);
34 ok = (channel_count >= 1U) &&
45static uint32_t voter_required_quorum(
const rte_voter_t *voter)
70static bool voter_data_equal(
const rte_voter_t *voter,
const void *a,
const void *b,
size_t size)
74 if (voter->config.
compare != NULL)
80 equal = (memcmp(a, b, size) == 0);
85static uint32_t voter_count_healthy(
const rte_voter_t *voter)
88 uint32_t healthy = 0U;
91 for (i = 0U; i < voter->channel_count; i++)
108static uint32_t voter_receive_from_healthy_channels(
rte_voter_t *voter,
size_t data_size,
110 bool responded[],
bool *out_saw_timeout)
112 uint32_t successful = 0U;
115 *out_saw_timeout =
false;
116 for (i = 0U; i < voter->channel_count; i++)
136 *out_saw_timeout =
true;
159static void voter_group_matching_responses(
const rte_voter_t *voter, uint32_t channel_count,
161 const bool responded[],
size_t data_size,
162 uint32_t group_id[], uint32_t group_count[],
163 uint32_t *out_num_groups)
165 uint32_t num_groups = 0U;
169 for (i = 0U; i < channel_count; i++)
177 for (j = 0U; j < i; j++)
183 if (voter_data_equal(voter, buffers[i], buffers[j], data_size))
185 group_id[i] = group_id[j];
186 group_count[group_id[i]]++;
193 group_id[i] = num_groups;
194 group_count[num_groups] = 1U;
198 *out_num_groups = num_groups;
205 if ((storage == NULL) || (config == NULL))
214 return lifecycle_status;
232 storage->config = *config;
233 storage->channel_count = 0U;
234 storage->total_disagreements = 0U;
235 storage->initialized =
true;
244 if ((voter == NULL) || (channel == NULL))
248 if (!voter->initialized)
257 return lifecycle_status;
264 voter->channels[voter->channel_count] = channel;
265 voter->channel_count++;
272 uint32_t healthy_count = 0U;
273 bool any_failed =
false;
274 bool any_timeout =
false;
277 if ((voter == NULL) || (data == NULL) || (data_size == 0U))
281 if (!voter->initialized)
289 if (!voter_channel_count_matches_strategy(voter, voter->channel_count))
294 for (i = 0U; i < voter->channel_count; i++)
316 if (healthy_count == 0U)
338 uint32_t num_groups = 0U;
339 uint32_t successful = 0U;
340 uint32_t required_quorum;
341 uint32_t best_group = 0U;
342 uint32_t best_count = 0U;
343 bool saw_timeout =
false;
347 if ((voter == NULL) || (data == NULL) || (data_size == 0U))
351 if (!voter->initialized)
359 if (!voter_channel_count_matches_strategy(voter, voter->channel_count))
364 required_quorum = voter_required_quorum(voter);
366 for (i = 0U; i < voter->channel_count; i++)
368 responded[i] =
false;
372 if (voter_count_healthy(voter) < required_quorum)
378 successful = voter_receive_from_healthy_channels(voter, data_size, buffers, responded, &saw_timeout);
380 if (successful == 0U)
384 else if (successful < required_quorum)
395 voter_group_matching_responses(
397 data_size, group_id, group_count, &num_groups);
399 for (i = 0U; i < num_groups; i++)
401 if (group_count[i] > best_count)
403 best_count = group_count[i];
408 if (best_count >= required_quorum)
410 for (i = 0U; i < voter->channel_count; i++)
412 if (responded[i] && (group_id[i] == best_group))
414 (void)memcpy(data, buffers[i], data_size);
429 *result = local_result;
434 if (bytes_received != NULL)
436 *bytes_received = data_size;
441 if (bytes_received != NULL)
443 *bytes_received = 0U;
448 voter->total_disagreements++;
488 uint32_t num_groups = 0U;
489 uint32_t required_quorum;
490 uint32_t best_group = 0U;
491 uint32_t best_count = 0U;
495 if ((voter == NULL) || (buffers == NULL) || (data_size == 0U))
499 if (!voter->initialized)
511 if (!voter_channel_count_matches_strategy(voter, buffer_count))
515 for (i = 0U; i < buffer_count; i++)
517 if (buffers[i] == NULL)
523 required_quorum = voter_required_quorum(voter);
525 for (i = 0U; i < buffer_count; i++)
527 (void)memcpy(local_buffers[i], buffers[i], data_size);
533 responded, data_size, group_id, group_count, &num_groups);
535 for (i = 0U; i < num_groups; i++)
537 if (group_count[i] > best_count)
539 best_count = group_count[i];
544 if (best_count >= required_quorum)
555 *result = local_result;
560 for (i = 0U; i < buffer_count; i++)
562 if (responded[i] && (group_id[i] == best_group))
564 if (out_data != NULL)
566 (void)memcpy(out_data, local_buffers[i], data_size);
571 if (out_size != NULL)
573 *out_size = data_size;
578 if (out_size != NULL)
589 voter->total_disagreements++;
604 uint32_t *healthy_count,
605 uint32_t *total_disagreements)
611 if (healthy_count != NULL)
613 *healthy_count = voter_count_healthy(voter);
615 if (total_disagreements != NULL)
617 *total_disagreements = voter->total_disagreements;
624 return (voter != NULL) ? voter->channel_count : 0U;
629 if ((voter == NULL) || (index >= voter->channel_count))
633 return voter->channels[index];
640 if ((voter == NULL) || (name == NULL))
644 for (i = 0U; i < voter->channel_count; i++)
648 if ((channel_name != NULL) && (strcmp(channel_name, name) == 0))
650 return voter->channels[i];
662 voter->initialized =
false;
rte_status_t rte_lifecycle_check_setup_allowed(void)
Convenience check for a setup-only constructor: call this as one of the first checks in any function ...
void rte_log_write(rte_log_level_t level, const char *tag, const char *message)
Emits one log message. Non-blocking; never fails the caller's control flow even if the message is dro...
#define RTE_SAFESTATE(level, reason)
Explicitly enters the given safe-state level with a reason code, capturing the call site automaticall...
rte_status_t
Common result/status codes.
@ RTE_STATUS_INVALID_PARAM
@ RTE_STATUS_NOT_INITIALIZED
@ RTE_STATUS_HARDWARE_FAULT
@ RTE_STATUS_RESOURCE_EXHAUSTED
const char * rte_channel_get_name(const rte_channel_t *handle)
Returns this channel's name, as given in rte_channel_config_t::name at rte_channel_init() time.
rte_status_t rte_channel_receive(rte_channel_t *handle, void *data, size_t data_size, uint32_t timeout_ms)
Receives data on this channel via its OSAdapter receive callback.
rte_status_t rte_channel_get_health(const rte_channel_t *handle, rte_channel_health_t *out_health)
Queries this channel's health statistics.
rte_channel_storage_t rte_channel_t
Opaque handle to a vital channel instance.
rte_status_t rte_channel_send(rte_channel_t *handle, const void *data, size_t data_size)
Sends data on this channel via its OSAdapter send callback.
rte_voter_storage_t rte_voter_t
Opaque handle to a voter instance.
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.
#define RTE_VOTER_MAX_MESSAGE_SIZE
Maximum payload size rte_voter_send()/_receive() supports.
#define RTE_VOTER_MAX_CHANNELS
Maximum number of channels a single voter can register.
rte_status_t rte_voter_register_channel(rte_voter_t *voter, rte_channel_t *channel)
Registers one already-initialized channel 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_status_t rte_voter_destroy(rte_voter_t *voter)
Destroys a voter instance.
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-com...
rte_voting_result_t
Outcome of one rte_voter_receive() call.
rte_status_t rte_voter_send(rte_voter_t *voter, const void *data, size_t data_size)
Broadcasts data to every registered, healthy 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_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 giv...
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_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_VOTING_INSUFFICIENT_QUORUM
Process-wide application setup-phase lock (ADR-026).
OS Abstraction Layer - Logging/diagnostics service.
Safe-state transitions and checked assertions (ADR-004).
N-way voting across registered rte_channel_t links (2oo2/2oo3/NMR).
Health statistics for one vital channel.
Configuration for rte_voter_init().
rte_safestate_level_t safestate_level
rte_voter_compare_fn compare
void * disagreement_context
uint32_t channel_timeout_ms
rte_safestate_reason_t safestate_reason
void(*) on_disagreement(void *context, rte_voting_result_t result)
rte_voting_strategy_t voting_strategy
Storage for one voter instance (opaque to caller). No dynamic memory.