Skip to content

Commit 4a672d3

Browse files
committed
docs(HardRT): Revisit and update whole documentation in the addition of new MUTEXES.md
1 parent b26cf7e commit 4a672d3

14 files changed

Lines changed: 614 additions & 244 deletions

README.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Minimal footprint, predictable behavior, and zero hardware dependencies in its c
1313
- **Portable ports** — currently: null, posix, cortex-m.
1414
- **Scheduler** — priority, round-robin, or hybrid.
1515
- **Semaphores (binary + counting)** — blocking take, `try_take`, ISR-safe `give` with FIFO wake-up; counting mode via `hrt_sem_init_counting`.
16+
- **Mutexes** — owner-tracked, non-recursive, FIFO waiter queue with direct handoff on unlock.
1617
- **Message Queues** — fixed-size, copy-based FIFO, blocking/non-blocking and ISR support.
1718
- **Static tasks** — stacks and TCBs supplied by the application.
1819
- **CMake package** — install and consume via `find_package(HardRT)`.
@@ -21,7 +22,7 @@ Minimal footprint, predictable behavior, and zero hardware dependencies in its c
2122

2223
Please refer to [PORTING.md](docs/PORTING.md) for additional port inclusion.
2324

24-
> The POSIX port is for logic verification, not timing accuracy. ucontext is used and supported on Linux/glibc.
25+
> The POSIX port is for logic verification, not timing accuracy. `ucontext` is used and supported on Linux/glibc.
2526
2627
> “On Cortex-M, the max time from tick to running the next highest priority ready task is bounded by: ISR tail + PendSV latency + context save/restore”
2728
@@ -83,7 +84,7 @@ cmake --install . --prefix "$PWD/install"
8384

8485
Consume from another CMake project:
8586
```cmake
86-
find_package(HardRT 0.2.0 REQUIRED)
87+
find_package(HardRT 0.3.1 REQUIRED)
8788
add_executable(app main.c)
8889
target_link_libraries(app PRIVATE HardRT::hardrt)
8990
```
@@ -95,7 +96,7 @@ For further information and CMake flags, see the [Build](docs/BUILD.md) document
9596

9697
### Tick vs Timeslice
9798
- **Tick:** base time unit generated by a timer interrupt (or POSIX signal). HardRT increments a counter each tick and wakes sleepers.
98-
- **Timeslice:** number of ticks a task may run before being rotated under RR. In v0.3.0, rotation happens on yield/sleep; strict preemption at the slice end is planned.
99+
- **Timeslice:** number of ticks a task may run before being rotated under RR. In the current implementation, rotation is triggered safely through the scheduler path rather than by direct context switching inside the tick hook.
99100

100101

101102
### Policy: Round‑robin within one priority (Sequence at tick times)
@@ -135,7 +136,13 @@ Caption:
135136

136137
### Semaphores (binary + counting)
137138
- `hrt_sem_init`, `hrt_sem_init_counting`, `hrt_sem_take`, `hrt_sem_try_take`, `hrt_sem_give`, `hrt_sem_give_from_isr`.
138-
- Use as a mutex substitute or an event signal. For mutex-like use, enabling immediate handoff on give is recommended (see roadmap).
139+
- Use semaphores for **event signaling**, **resource counting**, and producer/consumer synchronization.
140+
141+
### Mutexes
142+
- `hrt_mutex_init`, `hrt_mutex_lock`, `hrt_mutex_try_lock`, `hrt_mutex_unlock`.
143+
- Owner-tracked, non-recursive, task-context-only mutual exclusion primitive.
144+
- Unlock performs direct handoff to one waiter when contention exists.
145+
- Current implementation does **not** provide priority inheritance or timed lock.
139146

140147
### Message Queues
141148
- `hrt_queue_init`, `hrt_queue_send`, `hrt_queue_recv`, `hrt_queue_try_send`, `hrt_queue_try_recv`.

RELEASE_NOTES.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
Added
2-
- Message Queues: fixed-size, copy-based FIFO with blocking, non-blocking and ISR support.
3-
- Comprehensive test suite for queues and idle behavior.
4-
- C++ wrapper API (hardrtpp.hpp) providing idiomatic C++ access to HardRT
2+
- Message queues: fixed-size, copy-based FIFO with blocking, non-blocking and ISR support
3+
- Mutexes: owner-tracked, non-recursive mutual exclusion with FIFO waiter queue and direct handoff on unlock
4+
- Comprehensive POSIX tests for queues and mutexes
5+
- C++ wrapper API (`hardrtpp.hpp`) providing idiomatic C++ access to HardRT primitives
56
- C++ example applications demonstrating mixed C/C++ usage
67

78
Notes
89
- Core HardRT kernel remains pure C
910
- C++ support is optional and zero-cost when unused
10-
- ABI/API compatibility with v0.3.0 is preserved
11+
- Mutexes are task-context only and currently do not implement priority inheritance
12+
- ABI/API compatibility with v0.3.0 is preserved

cpp/hardrtpp.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ namespace hardrt {
121121

122122
/**
123123
* @brief Get the RTOS version as a human-readable string.
124-
* @return Version string (e.g., "0.3.0").
124+
* @return Version string (e.g., "0.3.1").
125125
*/
126126
static const char* version_string() {
127127
return hrt_version_string();
@@ -193,7 +193,7 @@ namespace hardrt {
193193
/**
194194
* @brief Give (release) the semaphore.
195195
*
196-
* Wakes up the highest priority task waiting on this semaphore.
196+
* Wakes one waiting task according to the semaphore handoff policy.
197197
* @return 0 on success.
198198
*/
199199
int give() {

docs/API_C.md

Lines changed: 89 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
21
## 🧠 API Overview (C)
32

4-
This page summarizes the public C API available in HardRT v0.3.0. See `inc/hardrt.h` for authoritative declarations.
3+
This page summarizes the public C API available in HardRT v0.3.1. See `inc/hardrt.h` for authoritative declarations.
54

65
### Types
76

@@ -24,22 +23,24 @@ typedef enum { HRT_PRIO0=0, HRT_PRIO1, /* ... */ HRT_PRIO11 } hrt_prio_t;
2423

2524
/* Init-time configuration */
2625
typedef struct {
27-
uint32_t tick_hz; /* default: 1000 */
28-
hrt_policy_t policy; /* default: PRIORITY_RR */
29-
uint16_t default_slice; /* RR timeslice in ticks; 0 disables RR by default */
26+
uint32_t tick_hz;
27+
hrt_policy_t policy;
28+
uint16_t default_slice;
29+
uint32_t core_hz;
30+
hrt_tick_source_t tick_src;
3031
} hrt_config_t;
3132

3233
/* Per-task attributes passed at creation */
3334
typedef struct {
34-
hrt_prio_t priority; /* default: HRT_PRIO1 if attr==NULL */
35-
uint16_t timeslice; /* 0 = cooperative in class; otherwise quantum in ticks */
35+
hrt_prio_t priority;
36+
uint16_t timeslice;
3637
} hrt_task_attr_t;
3738
```
3839
3940
### Version and port identity
4041
4142
```c
42-
const char* hrt_version_string(void); /* e.g. "0.3.0" */
43+
const char* hrt_version_string(void); /* e.g. "0.3.1" */
4344
unsigned hrt_version_u32(void); /* (maj<<16)|(min<<8)|patch */
4445
const char* hrt_port_name(void); /* e.g. "posix" or "null" */
4546
int hrt_port_id(void); /* 0=null, 1=posix, ... */
@@ -55,16 +56,16 @@ int hrt_create_task(hrt_task_fn fn, void* arg,
5556
void hrt_start(void);
5657
```
5758
58-
- `hrt_init` starts the port tick using `cfg->tick_hz` (defaults to 1000 Hz if 0). It also sets the scheduler policy and default timeslice.
59-
- `hrt_create_task` registers a static task using the provided stack buffer. Minimum 64 words are required on hosted platforms (POSIX). If `attr==NULL`, the task inherits `cfg->default_slice` and default priority `HRT_PRIO1`.
60-
- `hrt_start` enters the scheduler loop (does not return on POSIX; is a no-op on the null port).
59+
- `hrt_init` initializes the kernel, applies scheduler configuration, and starts the port tick when the selected tick source requires it.
60+
- `hrt_create_task` registers a static task using the provided stack buffer. Minimum stack constraints depend on the port.
61+
- `hrt_start` enters the scheduler loop. On the null port it returns immediately.
6162
6263
### Control and time
6364
6465
```c
65-
void hrt_sleep(uint32_t ms); /* sleep for ms; wakes on future ticks */
66-
void hrt_yield(void); /* yield to allow others in same class */
67-
uint32_t hrt_tick_now(void); /* system tick counter (increments at tick_hz; wraps on overflow) */
66+
void hrt_sleep(uint32_t ms);
67+
void hrt_yield(void);
68+
uint32_t hrt_tick_now(void);
6869
```
6970

7071
### Runtime tuning
@@ -74,36 +75,84 @@ void hrt_set_policy(hrt_policy_t p);
7475
void hrt_set_default_timeslice(uint16_t t);
7576
```
7677
77-
- Changing policy or default slice affects scheduling of READY tasks created after the change; existing tasks keep their configured `timeslice`.
78+
- Changing policy affects scheduling decisions from the next scheduling point onward.
79+
- Changing the default slice affects tasks created after the change. Existing tasks keep their configured timeslice.
7880
7981
### Round-robin semantics
8082
81-
- When policy is `HRT_SCHED_RR` or `HRT_SCHED_PRIORITY_RR` and a task has a non-zero `timeslice`, the running task’s quantum (`slice_left`) is decremented every tick.
82-
- When the quantum reaches zero, a reschedule is pended from the tick ISR, and the actual rotation to the tail of the ready queue occurs when returning to the scheduler (safe context). This is how the POSIX and null ports integrate today.
83-
- Tasks with `timeslice == 0` are cooperative within their priority class and will not be rotated by time slicing (but they can `hrt_yield()`).
83+
- When policy is `HRT_SCHED_RR` or `HRT_SCHED_PRIORITY_RR` and a task has a non-zero `timeslice`, the running task’s quantum is decremented on tick accounting.
84+
- When the quantum reaches zero, the scheduler reschedule path is pended and the actual rotation happens at a safe scheduling point.
85+
- Tasks with `timeslice == 0` are cooperative within their priority class and will not be rotated by time slicing.
8486
8587
### Semaphores
8688
87-
The kernel provides a minimal semaphore primitive in `hardrt_sem.h` (binary by default, counting via an explicit init):
89+
The kernel provides a minimal semaphore primitive in `hardrt_sem.h`.
8890
8991
```c
90-
void hrt_sem_init(hrt_sem_t* s, unsigned init); /* binary (legacy) */
92+
void hrt_sem_init(hrt_sem_t* s, unsigned init);
9193
void hrt_sem_init_counting(hrt_sem_t* s, unsigned init, uint8_t max_count);
9294
93-
int hrt_sem_take(hrt_sem_t* s); /* blocks until available; 0 on success */
94-
int hrt_sem_try_take(hrt_sem_t* s); /* 0 on success, -1 if not available */
95-
int hrt_sem_give(hrt_sem_t* s); /* wakes exactly one waiter if present */
96-
int hrt_sem_give_from_isr(hrt_sem_t* s, int* need_switch); /* ISR-safe */
95+
int hrt_sem_take(hrt_sem_t* s);
96+
int hrt_sem_try_take(hrt_sem_t* s);
97+
int hrt_sem_give(hrt_sem_t* s);
98+
int hrt_sem_give_from_isr(hrt_sem_t* s, int* need_switch);
9799
```
98100

101+
Notes:
102+
- Binary semaphores saturate at `1`.
103+
- Counting semaphores saturate at `max_count`.
104+
- Waiters are queued FIFO.
105+
- `hrt_sem_give_from_isr()` is supported.
106+
- Semaphores are **not owner-tracked**. For mutual exclusion, prefer `hrt_mutex_t`.
107+
108+
See `docs/SEMAPHORES.md` for details.
109+
110+
### Mutexes
111+
112+
The kernel provides a dedicated mutex primitive in `hardrt_mutex.h`.
99113

100-
Notes
101-
- Binary semantics: multiple consecutive `give()` calls do not overflow; one subsequent `take()` will succeed.
102-
- Waiters are queued FIFO; on wake the task is made READY and normal priority/RR scheduling applies.
103-
- If a waiter is woken from task context, the giver yields so a higher‑priority waiter can run immediately.
104-
- The ISR variant only pends a context switch and optionally sets `*need_switch=1`.
114+
```c
115+
#define HRT_MUTEX_NO_OWNER (-1)
116+
117+
typedef struct {
118+
volatile uint8_t locked;
119+
int16_t owner;
120+
uint8_t q[HARDRT_MAX_TASKS];
121+
uint8_t head;
122+
uint8_t tail;
123+
uint8_t count_wait;
124+
} hrt_mutex_t;
125+
126+
void hrt_mutex_init(hrt_mutex_t* m);
127+
int hrt_mutex_lock(hrt_mutex_t* m);
128+
int hrt_mutex_try_lock(hrt_mutex_t* m);
129+
int hrt_mutex_unlock(hrt_mutex_t* m);
130+
```
105131
106-
See `docs/SEMAPHORES.md` for a full guide and examples.
132+
Notes:
133+
- Mutexes are **owner-tracked** and **non-recursive**.
134+
- `hrt_mutex_lock()` blocks until ownership is acquired.
135+
- `hrt_mutex_unlock()` may directly hand ownership to the next waiter.
136+
- Waiters are queued FIFO.
137+
- Mutex calls are **task-context only**. There is no ISR mutex API.
138+
- The current implementation does **not** include timed lock, recursive mutexes, or priority inheritance.
139+
140+
See `docs/MUTEXES.md` for full semantics.
141+
142+
### Queues
143+
144+
The kernel provides fixed-size copy-based message queues in `hardrt_queue.h`.
145+
146+
```c
147+
void hrt_queue_init(hrt_queue_t *q, void *storage, uint16_t capacity, size_t item_size);
148+
int hrt_queue_send(hrt_queue_t *q, const void *item);
149+
int hrt_queue_try_send(hrt_queue_t *q, const void *item);
150+
int hrt_queue_try_send_from_isr(hrt_queue_t *q, const void *item, int *need_switch);
151+
int hrt_queue_recv(hrt_queue_t *q, void *out);
152+
int hrt_queue_try_recv(hrt_queue_t *q, void *out);
153+
int hrt_queue_try_recv_from_isr(hrt_queue_t *q, void *out, int *need_switch);
154+
uint16_t hrt_queue_count(const hrt_queue_t *q);
155+
```
107156

108157
### Minimal example
109158

@@ -117,12 +166,18 @@ static void taskA(void*){ for(;;){ hrt_sleep(500); } }
117166
static void taskB(void*){ for(;;){ hrt_sleep(1000);} }
118167

119168
int main(void){
120-
hrt_config_t cfg = { .tick_hz=1000, .policy=HRT_SCHED_PRIORITY_RR, .default_slice=5 };
169+
hrt_config_t cfg = {
170+
.tick_hz = 1000,
171+
.policy = HRT_SCHED_PRIORITY_RR,
172+
.default_slice = 5,
173+
.core_hz = 0,
174+
.tick_src = HRT_TICK_SYSTICK
175+
};
121176
hrt_init(&cfg);
122-
hrt_task_attr_t p0 = { .priority=HRT_PRIO0, .timeslice=0 };
123-
hrt_task_attr_t p1 = { .priority=HRT_PRIO1, .timeslice=5 };
177+
hrt_task_attr_t p0 = { .priority = HRT_PRIO0, .timeslice = 0 };
178+
hrt_task_attr_t p1 = { .priority = HRT_PRIO1, .timeslice = 5 };
124179
hrt_create_task(taskA, 0, stackA, 2048, &p0);
125180
hrt_create_task(taskB, 0, stackB, 2048, &p1);
126181
hrt_start();
127182
}
128-
```
183+
```

docs/BUILD.md

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ This page covers configuring, building, installing, and consuming HardRT.
55
## Prerequisites
66
- A C compiler (GCC/Clang)
77
- CMake ≥ 3.16
8-
- (Optional) A C++17 compiler if C++ wrapper is enabled
8+
- Optional C++17 compiler if the C++ wrapper is enabled
99

1010
## Configure & build (terminal)
1111
```bash
@@ -28,64 +28,61 @@ cmake --build . --target two_tasks -j
2828

2929
Expected output (excerpt on POSIX):
3030
```
31-
HardRT version: 0.3.0 (0x000300), port: posix (id=1)
31+
HardRT version: 0.3.1 (0x000301), port: posix (id=1)
3232
[A] tick count [0]
3333
[B] tock -----
3434
...
3535
```
3636

37-
> Tip: the `null` port is a stub — it doesn’t start a tick or switch contexts. `hrt_start()` returns immediately, so tasks do not run there.
37+
> Tip: the `null` port is a stub. It doesn’t start a tick or switch contexts. `hrt_start()` returns immediately, so tasks do not run there.
3838
3939
## Building tests (POSIX)
4040
The POSIX test suite builds as a single executable `hardrt_tests`.
4141
```bash
4242
cmake -DHARDRT_PORT=posix -DHARDRT_BUILD_TESTS=ON ..
4343
cmake --build . --target hardrt_tests -j && ./hardrt_tests
4444
```
45-
For details, see docs/TESTS_POSIX.md.
45+
46+
For details, see `docs/TESTS_POSIX.md`.
4647

4748
## CMake options
4849
| Option | Default | Description |
4950
|-------------------------|---------|-----------------------------------------------------------------------------------------|
50-
| `HARDRT_PORT` | `null` | Select build port: `null`, `posix`, or `cortex_m` |
51+
| `HARDRT_PORT` | `null` | Select build port: `null`, `posix`, or `cortex_m` |
5152
| `HARDRT_ENABLE_CPP` | `OFF` | Build C++17 header-only wrapper (`hardrtpp`) |
5253
| `HARDRT_BUILD_EXAMPLES` | `ON` | Build bundled demo projects |
5354
| `HARDRT_STRICT` | `OFF` | Enable strict warnings on POSIX builds |
5455
| `HARDRT_SANITIZE` | `OFF` | Enable ASan/UBSan on POSIX tests |
55-
| `HARDRT_STALL_ON_ERROR` | `OFF` | Stalls in an infinite loop if an error occurs. |
56-
| `HARDRT_DEBUG` | `OFF` | Enables debug settings (see [debug variables](#Debug-variables)). |
57-
| `HARDRT_CFG_MAX_TASKS` | `8` | Maximum number of concurrent tasks supported by the kernel (maps to `HARDRT_MAX_TASKS`) |
58-
| `HARDRT_CFG_MAX_PRIO` | `4` | Number of scheduler priority classes (0..N-1; maps to `HARDRT_MAX_PRIO`) |
56+
| `HARDRT_STALL_ON_ERROR` | `OFF` | Stalls in an infinite loop if an error occurs |
57+
| `HARDRT_DEBUG` | `OFF` | Enables debug settings |
58+
| `HARDRT_CFG_MAX_TASKS` | `8` | Maximum concurrent tasks supported by the kernel (maps to `HARDRT_MAX_TASKS`) |
59+
| `HARDRT_CFG_MAX_PRIO` | `4` | Number of scheduler priority classes (0..N-1; maps to `HARDRT_MAX_PRIO`) |
5960

6061
Constraints and notes:
61-
- Priority levels have a physical cap of 12 in this release (`HRT_PRIO0..HRT_PRIO11`).
62-
- There is no hard cap on the number of tasks in the source; practical limits depend on system memory.
63-
- CMake validates at configuration time: `HARDRT_CFG_MAX_PRIO` must be in [1, 12] and `HARDRT_CFG_MAX_TASKS >= HARDRT_CFG_MAX_PRIO` (and `>= 1`).
64-
- `HARDRT_STALL_ON_ERROR` is disabled for `posix` port as it breaks ctests.
62+
- Priority levels have a symbolic cap of 12 in this release (`HRT_PRIO0..HRT_PRIO11`).
63+
- CMake validates at configuration time: `HARDRT_CFG_MAX_PRIO` must be in `[1, 12]` and `HARDRT_CFG_MAX_TASKS >= HARDRT_CFG_MAX_PRIO`.
64+
- `HARDRT_STALL_ON_ERROR` is disabled for the `posix` port as it breaks `ctest`.
6565

6666
Examples:
6767
```bash
68-
# POSIX tests with 12 priority levels and 12 tasks
6968
cmake -DHARDRT_PORT=posix -DHARDRT_BUILD_TESTS=ON \
7069
-DHARDRT_CFG_MAX_PRIO=12 -DHARDRT_CFG_MAX_TASKS=12 ..
7170
cmake --build . --target hardrt_tests -j && ./hardrt_tests
7271

73-
# Defaults (4 priorities, 8 tasks) with C++ wrapper
7472
cmake -DHARDRT_PORT=posix -DHARDRT_ENABLE_CPP=ON ..
7573
```
7674

7775
## Install (optional)
7876
Install the library, headers, and CMake package files to a prefix:
7977
```bash
80-
# from the build directory
8178
cmake --install . --prefix "$PWD/install"
82-
# or system-wide
83-
sudo cmake --install .
8479
```
80+
8581
This installs:
86-
- archive `libhardrt.a`
82+
- `libhardrt.a`
8783
- public headers from `inc/`
8884
- generated header `hardrt_version.h`
85+
- generated header `hardrt_port.h`
8986
- CMake package files under `lib/cmake/HardRT`
9087

9188
## Consume from another CMake project
@@ -94,7 +91,3 @@ find_package(HardRT REQUIRED)
9491
add_executable(app main.c)
9592
target_link_libraries(app PRIVATE HardRT::hardrt)
9693
```
97-
98-
## Debug variables
99-
100-
...

0 commit comments

Comments
 (0)