Design Overview
The Status module defines a unified error handling system across the entire framework. Every operation returns a rte_status_t code that indicates success or the specific failure reason.
Design principle:** Consistency. All modules use the same status codes, making error handling predictable and consistent.
Status Code Definitions
The numeric values are part of the ABI (rte_status.h is authoritative): existing entries are never renumbered, new ones are appended.
typedef enum {
rte_status_t
Common result/status codes.
@ RTE_STATUS_INTERNAL_ERROR
@ RTE_STATUS_INVALID_STATE
@ RTE_STATUS_NOT_IMPLEMENTED
@ RTE_STATUS_ALREADY_INITIALIZED
@ RTE_STATUS_VALUE_OUT_OF_RANGE
@ RTE_STATUS_INVALID_PARAM
@ RTE_STATUS_NOT_SUPPORTED
@ RTE_STATUS_DATA_CORRUPTION
@ RTE_STATUS_NOT_INITIALIZED
@ RTE_STATUS_HARDWARE_FAULT
@ RTE_STATUS_RESOURCE_EXHAUSTED
@ RTE_STATUS_NOT_CONNECTED
Code Allocation Strategy
1-13: Framework core status codes (parameter, timeout, hardware, etc.)
14-999: Reserved for framework expansion
1000+: Application-specific error codes (user can extend)
Design Rationale
Why Unified Status Codes?
Without framework status codes:**
bool buffer_result = rte_buffer_write(...);
errno = ...;
rte_status_t rte_timer_create(rte_timer_storage_t *storage, const rte_timer_config_t *config, rte_timer_handle_t *out_handle)
Creates a timer bound to caller-owned storage. Does not start it.
Problem: Inconsistent error handling across modules.
With framework status codes:**
Why Not Use errno?
- errno is thread-unsafe (global state)
- errno is platform-specific (POSIX assumption)
- errno values vary by system
- MISRA-compliant systems avoid global state
Application-Specific Codes
Applications can define their own status codes:
typedef enum {
APP_STATUS_TRAIN_SPEED_LIMIT_EXCEEDED = 1000,
APP_STATUS_TRACK_INTEGRITY_CHECK_FAILED = 1001,
APP_STATUS_SIGNAL_ASPECT_UNKNOWN = 1002,
} app_status_t;
String Conversion
The module provides rte_status_to_string() for diagnostics:
}
const char * rte_status_to_string(rte_status_t status)
Returns a short, static, human-readable string for a status code. Intended for diagnostics/logging on...
The strings are the short names without the RTE_STATUS_ prefix ("OK", "TIMEOUT", "NOT_CONNECTED", ...); a value outside the enum yields "UNKNOWN_STATUS". The result is never NULL.
Implementation** (src/utils/status/rte_status.c, abridged):
{
switch (status)
{
default: return "UNKNOWN_STATUS";
}
}
Usage Patterns in Framework
Pattern 1: Initialization Check
Every module follows this pattern:
if (config == NULL) {
}
if (is_initialized) {
}
}
Pattern 2: Operation with Timeout
Operations that can timeout:
rte_status_t rte_channel_recv(handle, buffer, size, timeout) {
if (no_data_within_timeout) {
}
}
Pattern 3: Resource Exhaustion
Operations that can fail due to capacity:
rte_status_t rte_buffer_write(handle, data, size, written) {
if (buffer_remaining < size) {
}
}
Integration with Safe-State
Status codes inform safe-state decisions. The two snippets below are example application policy, not a rule the framework enforces: which status from which call leads to a safe state is decided by the application (the framework itself enters a safe state only where a requirement says so, e.g. REQ-CHECKPOINT-003, REQ-VOTER-005).
Critical failure (example policy):**
}
#define RTE_SAFESTATE(level, reason)
Explicitly enters the given safe-state level with a reason code, capturing the call site automaticall...
@ RTE_SAFESTATE_LEVEL_SAFE
Non-critical operation:**
MISRA Compliance
The status module supports MISRA C:2012:
- ✓ Fixed return type (rte_status_t enum)
- ✓ No implicit conversions (explicit enum values)
- ✓ No global state (errno-free)
- ✓ Deterministic (same code always means same error)
- ✓ Thread-safe (no shared state)
Implementation Details
Files
String Conversion
rte_status_to_string() is a switch with one case per enumerator and a default clause (MISRA C:2012 rule 16.4) returning "UNKNOWN_STATUS"; there is no lookup table (see the Implementation snippet above).
Pros: no array indexed by an external value (no out-of-bounds read for a value outside the enum), and a value outside the enum is handled explicitly by default. Cons: a new enumerator needs its own case and its own entry in the unit test's codes[] list; with both, the test catches a missing case (it would return "UNKNOWN_STATUS").
Testing Strategy
Unit Tests
tests/status/test_rte_status.c (abridged):
for (i = 0; i < sizeof(codes) / sizeof(codes[0]); ++i) {
assert(s != NULL);
assert(strcmp(s, "UNKNOWN_STATUS") != 0);
}
Future Extensions
Possible extensions (reserved code space):
- Additional timeout types (READ_TIMEOUT vs WRITE_TIMEOUT)
- Buffer-specific codes (BUFFER_EMPTY, BUFFER_FULL)
- Network codes (CONNECTION_REFUSED, CONNECTION_RESET)
- All would fit within 1000+ application-specific range