Back to Fprime

Operating System Abstraction Layer (OSAL)

Os/docs/sdd.md

4.2.28.1 KB
Original Source

Operating System Abstraction Layer (OSAL)

1. Introduction

1.1 Purpose

The Operating System Abstraction Layer (OSAL) provides a portable interface to operating system services for the framework. It abstracts platform-specific OS functionality behind a common API, enabling F´ applications to run on multiple operating systems without modification to the source code.

1.2 Scope

This document describes the high-level architecture and design of the OSAL, including its abstraction patterns, supported features, and implementation strategy. It does not provide detailed API specifications or implementation details.

2. Core Services

Core services are those that directly wrap OS primitives and are implemented by each platform backend. They form the foundation upon which derived and generic services are built.

2.1 Concurrency

ServicePurpose
MutexMutual-exclusion lock and RAII ScopeLock helper.
TaskThread creation, joining, and lifecycle management including start/stop callbacks.
QueueInter-task message passing with configurable depth, priority support, and blocking modes.

2.2 File system

ServicePurpose
FileOpen, read, write, seek, flush, and CRC computation on files.
DirectoryOpen, iterate, and create directory entries.
FileSystemHigher-level operations: remove, move/rename, copy, stat, query free space, and working-directory management.

2.3 System Resources

ServicePurpose
RawTimeAccess to the system clock for measuring time intervals.
CpuCPU count and per-CPU usage statistics.
MemorySystem memory usage statistics.

2.4 Console

ServicePurpose
ConsoleWrite messages to the system console.

3. Derived Services

Derived services are built on top of core services, providing higher-level abstractions that are implemented through the usage of core services.

ServicePurposeCore Services Used
ConditionVariableCondition-variable signaling, paired with Mutex for producer/consumer patterns.Mutex
ScopeLockRAII helper for automatically acquiring and releasing a Mutex within a specific scope.Mutex
IntervalTimerLightweight start/stop timer for measuring elapsed microseconds.RawTime

4. Generic Services

Generic services are implemented in the Os::Generic namespace and are not tied to platform-specific functionalities. They provide utilities or abstractions that are not tied to any specific OS, but are related to OS-level operations and are therefore included in the Os module.

ServicePurpose
PriorityQueueHeap-based priority queue implementation

5. Implementation Architecture

5.1 Delegate Pattern

Every OSAL core service (e.g. File, Task, Mutex, etc.) follows a uniform three-layer pattern:

LayerExampleDescription
InterfaceOs::FileInterfaceA pure-virtual base class that defines the contract for a given OS service.
WrapperOs::FileA final concrete class that holds a reference to the interface delegate constructed inside it. Application code interacts exclusively with the wrapper.
ImplementationOs::Posix::FileA concrete class that implements the interface. This is what needs to be implemented to support a new OS on F Prime.

This pattern allows for the selection of the implementation used for a given build to be performed through the build system at link-time: CMake chooses which Default*.cpp file to link, and that file provides the getDelegate factory function for a given OSAL implementation.

The following diagram (simplified for brevity) illustrates the relationship between these layers for the File service as an illustration. The same pattern applies to all other services. In the final Os::File wrapper, the OS functions (e.g. open(), read(), close()) are forwarded to its m_delegate which is a reference to an implementation of the Os::FileInterface, which is implemented by the platform-specific implementation class.

mermaid
classDiagram
    direction LR
    namespace Os {
        class FileInterface {
            <<interface>>
            +read()
        }
        class File {
            <<final>>
            -FileInterface& m_delegate
            +read()
        } 
     class PosixFile {
                +read()
            }
            class FreeRTOSFile {
                +read()
            }   
    }


    File *-- FileInterface
    FileInterface <|--  PosixFile
    FileInterface <|--  FreeRTOSFile
    FileInterface <|--  File

5.2 API usage

Application code interacts exclusively with the wrapper classes (e.g., Os::File) and never directly with the interfaces or implementations. The wrapper forwards calls to the delegate interface, which is implemented by the platform-specific implementation class.

There are two usage patterns for the wrapper classes:

Usage PatternDescriptionServiceExample Usage
SingletonsGlobal state and/or accessed through static methodsFileSystem, Cpu, Memory, TaskTrough a static call:
Os::FileSystem::rename(source, destination);
HandlesRepresents an OS object that carries stateFile, Directory, Mutex, Task, Queue, ConsoleThrough an instance:
Os::File my_file; my_file.open("path/to/file.txt");

The full API for each service is documented in the header files in the Os/ module.

[!NOTE] Os::Task exposes both usage patterns. Os::Task::delay() is a static method that blocks the current task for a specified duration, while Os::Task instances represent individual tasks that can be started and stopped.

5.3 Initialization

Os::init() is called once at system startup. It initializes the singleton instances used by services that have global state (Console, FileSystem, Cpu, Memory, Task).

While calling Os::init() is not strictly required, it does provide a deterministic place to initialize all singletons. When not called, singletons are initialized at the time of their first use.

5.4 Error Handling

All operations return a typed Status enumeration specific to each service. Platform backends translate native error codes (e.g., errno) into these status values so that callers never need to interpret platform-specific errors.

6. OSAL Implementations

The following OSAL implementations are available in the core F´ repository:

BackendLocationDescription
PosixOs/Posix/Full implementation using POSIX APIs (pthread, file I/O, clock_gettime, etc.). Serves as the default for Linux, macOS, and other POSIX compliant systems.
StubOs/Stub/No-op implementations that return Status::NOT_SUPPORTED. Useful while some implementations are not available to a platform.

Additional OSAL implementations are available through platform support packages. For more information, see Supported Platforms or search for a platform support package in the fprime-community GitHub organization.

OSAL selection is controlled by the CMake build system. Each backend provides a set of Default<ServiceName>.cpp files; the build includes exactly one such file per service, giving the linker a single definition of each getDelegate factory method which initializes the wrapper's delegate reference to the appropriate implementation.

7. Resources