Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpacesBeforeTrailingComments: 1

# Never fold short blocks — clarity over compactness.
# Never fold short blocks: clarity over compactness.
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
Expand All @@ -36,10 +36,10 @@ AllowShortLoopsOnASingleLine: false
# Case labels align with the `switch` (existing code convention).
IndentCaseLabels: false

# Don't reorder includes — a few headers depend on order today.
# Don't reorder includes: a few headers depend on order today.
SortIncludes: Never

# Macros aligned in blocks — helpful for the RM `USEROBJMAN_DECLARE` family.
# Macros aligned in blocks: helpful for the RM `USEROBJMAN_DECLARE` family.
AlignConsecutiveMacros: Consecutive
AlignConsecutiveAssignments: None
AlignConsecutiveDeclarations: None
Expand Down
28 changes: 27 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ jobs:
run: cmake --build build --target dmosal -j "$(nproc)"
- name: Run clang-tidy over library sources
run: |
files=$(git ls-files 'source/*.c' ':!source/zephyr')
files=$(git ls-files 'source/*.c' ':!source/zephyr' ':!source/freertos')
clang-tidy -p build $files

zephyr:
Expand Down Expand Up @@ -194,6 +194,32 @@ jobs:
- name: Build and run cmocka tests
run: zephyr/docker.sh test

freertos:
name: freertos posix simulator (examples + tests)
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- name: Cache the FreeRTOS build image
id: image-cache
uses: actions/cache@v4
with:
path: /tmp/dmosal-freertos.tar
key: freertos-image-${{ hashFiles('freertos/Dockerfile') }}
- name: Load cached image
if: steps.image-cache.outputs.cache-hit == 'true'
run: docker load -i /tmp/dmosal-freertos.tar
- name: Build the FreeRTOS image
if: steps.image-cache.outputs.cache-hit != 'true'
run: |
docker build -t dmosal-freertos:local -f freertos/Dockerfile freertos
docker save -o /tmp/dmosal-freertos.tar dmosal-freertos:local
- name: Build examples and tests
run: freertos/docker.sh build
- name: Run examples
run: freertos/docker.sh run
- name: Run cmocka tests
run: freertos/docker.sh test

docs:
name: docs (build)
runs-on: ubuntu-22.04
Expand Down
12 changes: 11 additions & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,22 @@ repos:
- id: clang-format
types_or: [c, c++]

# Every C source and header must carry an SPDX license identifier.
- repo: local
hooks:
- id: spdx-license-header
name: SPDX license header
language: pygrep
entry: 'SPDX-License-Identifier: \S+'
args: [--negate]
files: \.(c|h)$|\.h\.in$

# Manual stage: needs build/compile_commands.json. Run with `just tidy`.
- repo: local
hooks:
- id: clang-tidy
name: clang-tidy
entry: clang-tidy -p build
language: system
files: ^source/(?!zephyr/).*\.c$
files: ^source/(?!zephyr/|freertos/).*\.c$
stages: [manual]
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ set(DMOSAL_EXTRA_WARNING_FLAGS
-Wmissing-prototypes
)

# Sanitizers / coverage — one flag string shared between compile and link.
# Sanitizers / coverage: one flag string shared between compile and link.
set(_dm_extra "")
if(DMOSAL_ENABLE_ASAN)
set(_dm_extra "${_dm_extra} -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer -O1")
Expand All @@ -70,7 +70,7 @@ endif()

find_package(Threads REQUIRED)

# Explicit source list — new files require a cmake refresh (on purpose).
# Explicit source list: new files require a cmake refresh (on purpose).
set(osal_SRC
source/osal.c
source/osal_error.c
Expand All @@ -86,7 +86,7 @@ set(osal_SRC
source/linux/osal_timer.c
)

# Generated headers live under the build tree — never in the source tree.
# Generated headers live under the build tree: never in the source tree.
set(DMOSAL_GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/gen/dmosal")
file(MAKE_DIRECTORY "${DMOSAL_GEN_DIR}")

Expand Down
9 changes: 7 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing

Contributions are welcome — bug reports, patches, or ideas.
Contributions are welcome: bug reports, patches, or ideas.

## Build and test

Expand All @@ -10,10 +10,15 @@ cmake -S . -B build
cmake --build build --target check
```

Or use [`just`](https://github.com/casey/just): `just check`. Zephyr and FreeRTOS
backends are tested in Docker with `just zephyr-test` and `just freertos-test`.
CI runs all three, so please keep the portable tests in `test/osal/` free of
backend-specific code (put those in `test/<backend>/`).

## Style

There's a `.clang-format` at the repo root. If you have clang-format handy, running
it over your changes keeps diffs tidy; if not, don't worry about it — CI will point
it over your changes keeps diffs tidy; if not, don't worry about it, CI will point
out any drift.

## PRs
Expand Down
117 changes: 51 additions & 66 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,107 +1,92 @@
# dmosal — OS Abstraction Layer
# dmosal: OS Abstraction Layer

[![CI](https://github.com/drymon/osal/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/drymon/osal/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/drymon/osal/branch/main/graph/badge.svg)](https://codecov.io/gh/drymon/osal)
[![License: BSD-2-Clause](https://img.shields.io/badge/License-BSD--2--Clause-blue.svg)](LICENSE)
[![Language: C](https://img.shields.io/badge/language-C-brightgreen.svg)](#)

A small, portable embedded C abstraction layer providing deterministic/bounded
resource management and consistent concurrency, timing, and communication
semantics across POSIX and RTOS platforms.
A small, portable C abstraction layer for tasks, mutexes, semaphores, queues,
timers and time, with the same semantics on every supported OS.

Everything (tasks, mutexes, semaphores, queues, timers, ...) is allocated
statically up front through a central resource manager, so there's no malloc
on the hot path and the worst-case memory usage is known ahead of time. A
Linux backend and a Zephyr backend are included; other targets can be
added behind the same API without breaking existing callers.
All resources are statically allocated up front, so there is no `malloc` on
any hot path and worst-case memory use is known in advance. New backends can
be added behind the same API without breaking existing callers.

```
+-------------------------------+
| Application |
+-------------------------------+
+--------------+----------------+
| OSAL | libc |
+--------------+----------------+
+-------------------------------+
| OS User Space APIs |
+-------------------------------+
+-------------------------------+
| OS Kernel Space |
+-------------------------------+
+-------------------------------+
| HW |
+-------------------------------+
```
## Supported backends

## Getting started
| Backend | Source | Tested on | Details |
|----------|---------------------------------|------------------------------------|----------------------------------------|
| Linux | [source/linux/](source/linux/) | Native Linux (pthreads, POSIX IPC) | Quick start |
| Zephyr | [source/zephyr/](source/zephyr/) | `native_sim` virtual board (Docker) | [zephyr/README.md](zephyr/README.md) |
| FreeRTOS | [source/freertos/](source/freertos/) | POSIX/Linux simulator (Docker) | [freertos/README.md](freertos/README.md) |
| ... | your own, see [docs/porting.md](docs/porting.md) | | |

You'll need `cmake`, `libcmocka-dev`, and `doxygen`:
The same [examples](examples/) and [cmocka tests](test/) run unchanged on every
backend. The Zephyr and FreeRTOS targets need no hardware. More backends can be
added behind the same API.

```
sudo apt install cmake libcmocka-dev doxygen
+-------------------------------+
| Application |
+---------------+---------------+
| dmosal | libc |
+---------------+---------------+
| Linux | Zephyr | FreeRTOS | ...|
+-------------------------------+
```

Then build the library, run the tests, and check out the examples:
## Quick start

Install the dependencies, then build and test on Linux:

```
just check # configure + build + run tests
just build # build the examples target
sudo apt install cmake libcmocka-dev doxygen
just check # configure, build, run tests
just build # build the examples
```

If you'd rather not install a toolchain locally, there's a pinned
[`Dockerfile`](Dockerfile):
No toolchain locally? Use the pinned [`Dockerfile`](Dockerfile):

```
docker build -t dmosal-dev .
docker run --rm -v "$PWD":/workspace -w /workspace dmosal-dev just check
```

Don't have [`just`](https://github.com/casey/just) installed? Check the
[`justfile`](justfile) — every recipe there is just a couple of plain
`cmake`/`ctest` commands you can run directly.

There are a few more recipes worth knowing about: `just check-valgrind`,
`just check-asan`, `just check-tsan`, `just check-coverage`, `just doc`,
`just format`, `just tidy`. Run `just --list` to see everything.
Without [`just`](https://github.com/casey/just), the [`justfile`](justfile)
recipes are plain `cmake`/`ctest` commands you can run directly.

Resource limits (how many tasks, queues, etc. you get) are set at CMake
configure time — see [osal_config.cmake](osal_config.cmake).
Resource limits (number of tasks, queues, ...) are set at configure time in
[osal_config.cmake](osal_config.cmake).

## Zephyr
## Zephyr and FreeRTOS

dmosal also runs on [Zephyr RTOS](https://zephyrproject.org/) through a native
backend (`k_mutex`, `k_sem`, `k_thread`, `k_timer`, `k_msgq`) in
[source/zephyr/](source/zephyr/). The repo is a Zephyr module, and the same
programs from [examples/](examples/) build unchanged for Zephyr. It is tested
on the virtual `native_sim` board, so no hardware is needed, and everything
(including the Zephyr source) runs inside Docker:
Both run inside Docker, so no local SDK is needed:

```
just zephyr-build # build the examples for Zephyr native_sim (Docker)
just zephyr-run # run the Zephyr examples
```
just zephyr-build # build examples and tests for native_sim
just zephyr-run # run the examples
just zephyr-test # run the cmocka tests

See [zephyr/README.md](zephyr/README.md) for setup, configuration and how the
backend maps to Zephyr primitives.
just freertos-build # build examples and tests for the POSIX simulator
just freertos-run # run the examples
just freertos-test # run the cmocka tests
```

## Examples
## Other recipes

Sample programs live in [examples/](examples/). Build them with `just build`
(CMake target `examples`) for Linux, or with `zephyr/docker.sh build` for
Zephyr.
`just check-valgrind`, `check-asan`, `check-tsan`, `check-coverage`, `doc`,
`format`, `tidy`. Run `just --list` for everything.

## Documentation

- API reference (Doxygen): run `just doc`, output ends up in
`build/doc/html/`.
- Design docs: [docs/](docs/README.md) — architecture, API spec, resource
lifetime, thread-safety, porting guide.
- API reference (Doxygen): `just doc` → `build/doc/html/`.
- Design docs: [docs/](docs/README.md) (architecture, API spec, lifetime,
thread safety, porting guide).

## Contributing

Bug reports, patches, ideas — all welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
for how to build, test, and keep the style consistent.
See [CONTRIBUTING.md](CONTRIBUTING.md) for building, testing and style.

## License

BSD-2-Clause — see [LICENSE](LICENSE).
BSD-2-Clause. See [LICENSE](LICENSE).
12 changes: 6 additions & 6 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ Doxygen-generated API reference (built via `make doc`).
| Document | What it covers |
|---|---|
| [architecture.md](architecture.md) | Layered design, subsystem overview, resource-manager pattern, callback threading model, backend model. |
| [api-spec.md](api-spec.md) | Behavioral specification per subsystem — functions, states, error codes, invariants. |
| [api-spec.md](api-spec.md) | Behavioral specification per subsystem: functions, states, error codes, invariants. |
| [lifetime.md](lifetime.md) | Init/deinit ordering, resource ownership, when it is safe to use / release a resource. |
| [porting.md](porting.md) | How to add a new backend (e.g. an RTOS or bare-metal target). Reference: the Linux backend. |
| [thread-safety.md](thread-safety.md) | Per-API table classifying every public call as thread-safe, single-owner, or init-thread-only. |

If you're just getting started, read them in this order:

1. `architecture.md` — the mental model
2. `thread-safety.md` — what you can and cannot call concurrently
3. `lifetime.md` — how resources come into existence and go away
4. `api-spec.md` — deeper look at each subsystem
5. `porting.md` — only if you're adding a new backend
1. `architecture.md`: the mental model
2. `thread-safety.md`: what you can and cannot call concurrently
3. `lifetime.md`: how resources come into existence and go away
4. `api-spec.md`: deeper look at each subsystem
5. `porting.md`: only if you're adding a new backend
Loading
Loading