Platform Abstraction Requirements¶
This section defines requirements for the platform abstraction layer (PAL), which enables OpenSOMEIP to run on multiple operating systems and RTOSes.
Overview¶
The platform abstraction layer provides portable interfaces for:
Threading (Thread, Mutex, ConditionVariable, ScopedLock, sleep_for)
Memory management (Message pool allocation)
Networking (socket API abstraction)
Byte-order conversion
Each platform backend implements these interfaces in a *_impl.h
header selected at build time via CMake include-path configuration.
PAL Architecture¶
The platform abstraction shall use a build-system-selected include-path mechanism:
Rationale: Eliminates unmaintainable Code Location: |
PAL Interface Contracts¶
Mutex Interface¶
Rationale: Exclusive locking is the fundamental synchronization primitive used by SD, TP, and transport layers. Code Location: |
Rationale: Timely release prevents deadlock and ensures progress. Code Location: |
Rationale: Non-blocking acquisition is needed for lock-free polling patterns and diagnostic probes. Code Location: |
Rationale: Mutex identity is tied to its OS resource handle; copying would create dangling or aliased handles. Code Location: |
The Mutex implementation shall not corrupt internal state if Rationale: Double-unlock is a common programming error; the PAL must not crash or corrupt state. Error Handling: Platform-defined (POSIX: undefined; FreeRTOS: xSemaphoreGive returns pdFAIL; Zephyr: k_mutex_unlock returns -EPERM). Code Location: |
ConditionVariable Interface¶
Rationale: Atomic release-and-wait is the fundamental building block for producer/consumer patterns in SD and event delivery. Code Location: |
Rationale: Predicate-based wait eliminates spurious-wakeup bugs at the API level. Code Location: |
Rationale: Single-wake avoids thundering-herd effects on SD message dispatch. Code Location: |
Rationale: Broadcast wake is needed for shutdown sequences where all worker threads must unblock. Code Location: |
On all exit paths from Rationale: Mutex ownership loss after wait leads to data races that are extremely hard to diagnose. Code Location: |
If the predicate throws during Rationale: Exception-unsafe CV wrappers cause mutex ownership loss, leading to data races. Error Handling: RAII guard calls Code Location: |
Thread Interface¶
Rationale: Immediate-start semantics match Code Location: |
Rationale: Callers must check joinability before calling join() to avoid double-join errors. Code Location: |
Rationale: Join is the primary mechanism for safe thread shutdown in transport and SD layers. Code Location: |
Rationale: Thread identity is tied to an OS thread handle; copying would create invalid aliases. Code Location: |
If the underlying OS fails to create a thread (e.g., stack exhaustion
on FreeRTOS, thread limit on Zephyr), the Thread object shall be in a
non-joinable state and Rationale: Embedded systems have limited thread resources; failure must be handled gracefully. Error Handling: Code Location: |
The Thread destructor shall safely abort a running thread if
Rationale: Forgetting to join is a common error; the destructor must clean up without undefined behavior. Error Handling: Call platform-specific abort (vTaskDelete, k_thread_abort) and free context. Code Location: |
ScopedLock Interface¶
The Rationale: Automatic acquisition on construction ensures the critical section begins at the point of declaration. Code Location: |
The Rationale: Automatic release on scope exit prevents mutex leaks on early returns and exceptions. Code Location: |
Rationale: Copying a lock guard would create double-unlock on destruction. Code Location: |
sleep_for Interface¶
Rationale: SD timers and TP reassembly timeout rely on sleep_for providing a minimum delay guarantee. Code Location: |
Rationale: Prevents accidental infinite blocks when computed durations are zero or negative. Code Location: |
Memory Interface¶
Rationale: Decouples message lifetime management from the platform memory strategy (heap vs. pool). Code Location: |
Multiple calls to Rationale: Protocol layers allocate messages concurrently; aliased objects would cause data corruption. Code Location: |
When the platform’s message pool is exhausted,
Rationale: Embedded pools have fixed capacity; callers must handle exhaustion gracefully. Error Handling: Return Code Location: |
Pool-based Rationale: Transport and SD layers allocate messages from different threads. Error Handling: Mutex-protected allocation path. Code Location: |
Networking Interface¶
Rationale: Portable socket close is needed because POSIX uses
Code Location: |
Rationale: Graceful TCP shutdown requires separate shutdown before close. Code Location: |
Rationale: Non-blocking I/O is required for event-driven transport receive loops. Code Location: |
Rationale: Some operations (e.g., TCP connect) benefit from blocking mode with timeout. Code Location: |
Rationale: Transport layers check the return value to detect invalid socket states. Error Handling: Return Code Location: |
Byte-Order Interface¶
Rationale: SOME/IP Service ID, Method ID, and Length fields are 16-bit big-endian on the wire. Code Location: |
Rationale: Parsing incoming SOME/IP headers requires converting wire-format 16-bit fields to host order. Code Location: |
Rationale: SOME/IP Message ID and Length are serialized as 32-bit big-endian values. Code Location: |
Rationale: Parsing incoming SOME/IP headers requires converting wire-format 32-bit fields to host order. Code Location: |
Static Allocation Contracts¶
Container Interface¶
The PAL shall provide a Rationale: Protocol layers use dynamic vectors extensively; a bounded static replacement is required for no-heap builds. Code Location: |
The PAL shall provide a Rationale: Service names, endpoint identifiers, and diagnostic strings must be representable without heap allocation in safety-critical builds. Code Location: |
The PAL shall provide a Rationale: Session tables and subscription registries require associative lookup without runtime allocation. Code Location: |
The PAL shall provide a Rationale: Event dispatch and work queues require bounded FIFO storage with deterministic access time. Code Location: |
The PAL shall provide a Rationale: Callback registration (event handlers, transport hooks) must
work without Code Location: |
When a static container reaches its compile-time capacity, insertion
operations ( Rationale: Bounded containers must surface capacity limits to callers so protocol layers can implement safe failure modes. Error Handling: Return Code Location: |
Buffer Pool Interface¶
Rationale: Payload serialization and TP reassembly require transient byte buffers without heap allocation. Code Location: |
Rationale: Explicit release enables deterministic reuse of fixed pool slots and prevents pool exhaustion. Code Location: |
The buffer pool shall provide multiple compile-time-configured size tiers.
Rationale: Tiered pools reduce memory waste while keeping allocation time bounded and predictable. Code Location: |
When all slots in the matching buffer-pool tier are in use,
Rationale: Fixed pools have bounded capacity; callers must handle exhaustion the same way as message-pool exhaustion. Error Handling: Return Code Location: |
Pool-based Rationale: Transport and SD layers acquire buffers from different threads. Error Handling: Mutex-protected acquire/release path. Code Location: |
Static Configuration Interface¶
All static-allocation capacities (message pool size, buffer-pool tier
counts and slot sizes, container defaults) shall be configurable at
compile time via CMake options and propagated to a generated
Rationale: Integrators must size pools for their ECU memory budget without modifying library source code. Code Location: |
Rationale: Code Location: |
When Rationale: Automated verification that the no-heap policy is enforced across the entire stack, not just individual components. Code Location: |
Static Allocation Backend¶
The static-allocation backend shall implement all PAL container types
( Rationale: A single backend directory provides the container
implementations selected when Code Location: |
The static-allocation backend shall implement
Rationale: Message objects are the highest-frequency allocation in the protocol stack; a static pool eliminates heap use and fragmentation. Code Location: |
The static-allocation backend shall implement tiered byte-buffer pools using pre-allocated static storage:
Rationale: Payload buffers are the second-highest allocation frequency; tiered static pools balance memory efficiency and determinism. Code Location: |
The static-allocation backend shall protect message and buffer pools with
the PAL Rationale: Pool thread safety must work identically on host, FreeRTOS, ThreadX, and Zephyr without OS-specific locking code in pool logic. Code Location: |
Public API classes that use the pimpl idiom shall store their implementation
object in a compile-time-sized inline buffer ( Rationale: Pimpl is used throughout the stack; without static pimpl storage, enabling no-heap mode would still trigger heap allocation in constructors. Code Location: |
Platform Backends¶
POSIX/Host Backend¶
The POSIX/host backend shall implement the PAL threading primitives using C++ standard library types:
Rationale: POSIX/host is the primary development and CI platform; standard library types provide zero-overhead abstractions. Code Location: |
The POSIX/host backend shall implement Rationale: On host/desktop, heap allocation is the natural choice; no pool is needed. Code Location: |
The POSIX/host backend shall provide networking through standard BSD
socket headers (
Rationale: POSIX sockets are the reference networking API. Code Location: |
The POSIX/host backend shall map byte-order macros to
Rationale: POSIX provides standard network byte-order functions. Code Location: |
FreeRTOS Backend¶
The FreeRTOS backend shall implement the PAL threading primitives:
Rationale: FreeRTOS is one of the most widely used RTOSes in automotive embedded systems. Code Location: |
The FreeRTOS backend shall provide a static pool allocator for Message objects:
Rationale: Embedded targets require deterministic memory allocation without heap fragmentation. Code Location: |
ThreadX Backend¶
The ThreadX backend shall implement the PAL threading primitives:
Rationale: ThreadX (Azure RTOS) is widely used in automotive and industrial embedded systems. Code Location: |
The ThreadX backend shall provide a static pool allocator for Message objects:
Rationale: Embedded targets require deterministic memory allocation without heap fragmentation. Code Location: |
lwIP Backend¶
The lwIP backend shall provide networking through lwIP’s socket layer:
Rationale: lwIP is the standard TCP/IP stack for FreeRTOS and ThreadX on microcontrollers. Code Location: |
The lwIP backend shall map byte-order macros to lwIP definitions from
Rationale: lwIP provides its own byte-order functions optimized for the target architecture. Code Location: |
Zephyr Backend¶
The Zephyr backend shall implement the PAL threading primitives:
Rationale: Zephyr is the RTOS with native SOME/IP SD multicast support used in OpenSOMEIP CI. Code Location: |
The Zephyr backend shall provide Rationale: Zephyr provides kernel-managed memory pools suitable for deterministic embedded allocation. Code Location: |
The Zephyr backend shall provide networking through Zephyr’s
Rationale: Zephyr removed Code Location: |
The Zephyr backend shall map byte-order macros to
Rationale: Zephyr provides endian-aware byte-order functions. Code Location: |
Win32 Backend¶
The Win32 backend shall implement the PAL threading primitives using C++ standard library types (identical to POSIX/host):
Rationale: Windows support enables development on Windows workstations. Code Location: |
The Win32 backend shall implement Rationale: Desktop Windows uses standard heap allocation. Code Location: |
The Win32 backend shall provide networking through Winsock2:
Rationale: Winsock2 is the standard networking API on Windows. Code Location: |
The Win32 backend shall map byte-order macros to Winsock2 functions. Rationale: Winsock2 provides standard byte-order functions on Windows. Code Location: |