Inter-Task Communication
VAIOS provides a set of inter-task communication (IPC) primitives that enable coordination and data exchange between tasks. These mechanisms are designed to support synchronization, resource sharing, and event-driven execution while maintaining predictable behavior in a preemptive environment.
The core IPC primitives include binary semaphores, counting semaphores, mutexes, and recursive mutexes. Semaphores are used for signaling and resource counting, allowing tasks to block until a resource becomes available or an event occurs. Mutexes provide mutual exclusion for shared resources, ensuring that only one task can access a critical section at a time. Recursive mutexes extend this behavior by allowing the owning task to acquire the same lock multiple times, maintaining an internal recursion count.
Each synchronization primitive maintains an internal wait queue of tasks that are blocked while attempting to acquire the resource. When a resource becomes available, one of the waiting tasks is unblocked and moved back to the ready state. Blocking operations support optional timeouts, allowing tasks to resume execution if the wait condition is not satisfied within a specified number of ticks.
VAIOS also provides ISR-safe variants of certain IPC operations, allowing interrupt handlers to signal tasks without directly performing complex scheduling operations. These functions defer scheduling decisions to the appropriate context, ensuring that interrupt latency remains low while still enabling responsive task wake-up.
In addition to traditional synchronization primitives, VAIOS includes lock-free queue implementations for efficient data transfer between tasks. Single-producer single-consumer (SPSC) and multi-producer multi-consumer (MPMC) queues are provided to support different communication patterns. These structures enable high-throughput data exchange without requiring locks, making them suitable for performance-critical paths.
All IPC mechanisms are tightly integrated with the scheduler. Tasks that block on synchronization primitives are placed into the appropriate wait queues and are automatically transitioned back to the ready state when conditions are met or timeouts expire. This integration ensures that communication and synchronization are handled efficiently and consistently within the system.