CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Loading...
Searching...
No Matches
semphr.h
Go to the documentation of this file.
1#pragma once
2/**
3 * \file
4 * FreeRTOS semaphore compatibility layer. This maps FreeRTOS semaphore types
5 * to their CHERIoT RTOS equivalents.
6 *
7 * There is some overhead from dynamic dispatch that can be avoided if only one
8 * of the FreeRTOS semaphore types needs to be supported in a particular
9 * component. You can enable individual semaphore types by defining the
10 * following macros:
11 *
12 * - `CHERIOT_EXPOSE_FREERTOS_SEMAPHORE`: Enable counting and binary semaphores.
13 * - `CHERIOT_EXPOSE_FREERTOS_MUTEX`: Enable non-recursive, priority-inheriting
14 * mutexes.
15 * - `CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX`: Enable recursive mutexes.
16 */
17#include "FreeRTOS.h"
18#include <locks.h>
19#include <stdatomic.h>
20
21#if !defined(CHERIOT_EXPOSE_FREERTOS_SEMAPHORE) && \
22 !defined(CHERIOT_EXPOSE_FREERTOS_MUTEX) && \
23 !defined(CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX)
24# error At least one out of CHERIOT_EXPOSE_FREERTOS_SEMAPHORE, \
25 CHERIOT_EXPOSE_FREERTOS_MUTEX, or CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX \
26 must be defined.
27#endif
28
29#ifdef CHERIOT_EXPOSE_FREERTOS_SEMAPHORE
30# define CHERIOT_FREERTOS_SEMAPHORE_CASE(x) \
31 case CheriotFreeRTOS_Semaphore: \
32 x; \
33 break;
34#else
35# define CHERIOT_FREERTOS_SEMAPHORE_CASE(x)
36#endif
37
38#ifdef CHERIOT_EXPOSE_FREERTOS_MUTEX
39# define CHERIOT_FREERTOS_MUTEX_CASE(x) \
40 case CheriotFreeRTOS_Mutex: \
41 x; \
42 break;
43#else
44# define CHERIOT_FREERTOS_MUTEX_CASE(x)
45#endif
46
47#ifdef CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX
48# define CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(x) \
49 case CheriotFreeRTOS_RecursiveMutex: \
50 x; \
51 break;
52#else
53# define CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(x)
54#endif
55
56/**
57 * Enumeration used to differentiate the different kinds of FreeRTOS semaphores
58 * in this compatibility layer.
59 */
61{
62#ifdef CHERIOT_EXPOSE_FREERTOS_SEMAPHORE
63 /**
64 * A FreeRTOS counting or binary semaphore.
65 */
67#endif
68#ifdef CHERIOT_EXPOSE_FREERTOS_MUTEX
69 /**
70 * A non-recursive, priority-inheriting mutex.
71 */
73#endif
74#ifdef CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX
75 /**
76 * A recursive mutex.
77 */
79#endif
80};
81
82/**
83 * Type used to define space for storing any of the exposed FreeRTOS semaphore
84 * types.
85 */
86typedef struct
87{
88 /**
89 * The state for the various kinds of FreeRTOS semaphores.
90 */
91 union
92 {
93#ifdef CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX
94 struct RecursiveMutexState recursiveMutex;
95#endif
96#ifdef CHERIOT_EXPOSE_FREERTOS_MUTEX
97 struct FlagLockState mutex;
98#endif
99#ifdef CHERIOT_EXPOSE_FREERTOS_SEMAPHORE
100 struct CountingSemaphoreState semaphore;
101#endif
102 };
103#if (defined(CHERIOT_EXPOSE_FREERTOS_SEMAPHORE) + \
104 defined(CHERIOT_EXPOSE_FREERTOS_MUTEX) + \
105 defined(CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX)) > 1
106# define CHERIOT_FREERTOS_SEMAPHORE_SWITCH(x) switch (x->kind)
107 /**
108 * The discriminator for the union above. If only one kind of semaphore is
109 * supported, this is omitted.
110 */
112# define CHERIOT_FREERTOS_SEMAPHORE_KIND_SET(x, y) x->kind = y
113#else
114# if defined(CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX)
115# define CHERIOT_FREERTOS_SEMAPHORE_SWITCH(x) \
116 switch (CheriotFreeRTOS_RecursiveMutex)
117# elif defined(CHERIOT_EXPOSE_FREERTOS_MUTEX)
118# define CHERIOT_FREERTOS_SEMAPHORE_SWITCH(x) \
119 switch (CheriotFreeRTOS_Mutex)
120# elif defined(CHERIOT_EXPOSE_FREERTOS_SEMAPHORE)
121# define CHERIOT_FREERTOS_SEMAPHORE_SWITCH(x) \
122 switch (CheriotFreeRTOS_Semaphore)
123# endif
124
125# define CHERIOT_FREERTOS_SEMAPHORE_KIND_SET(x, y)
126#endif
128
129/**
130 * Type for a handle to a counting semaphore.
131 */
133
134#ifdef CHERIOT_EXPOSE_FREERTOS_SEMAPHORE
135/**
136 * Initialise a statically allocated semaphore. The initial value and maximum
137 * are specified with `uxInitialCount` and `uxMaxCount` respectively.
138 *
139 * Returns a pointer to the semaphore.
140 */
141__always_inline static inline SemaphoreHandle_t
143 UBaseType_t uxInitialCount,
144 StaticSemaphore_t *pxSemaphoreBuffer)
145{
146 pxSemaphoreBuffer->semaphore.maxCount = uxMaxCount;
147# ifdef __cplusplus
148 pxSemaphoreBuffer->semaphore.count = uxInitialCount;
149# else
150 // In C mode, we don't want a variable-sized atomic store here!
151 atomic_init(&pxSemaphoreBuffer->semaphore.count, uxInitialCount);
152# endif
153 CHERIOT_FREERTOS_SEMAPHORE_KIND_SET(pxSemaphoreBuffer,
155 return pxSemaphoreBuffer;
156}
157
158# ifndef CHERIOT_NO_AMBIENT_MALLOC
159/**
160 * Allocate a counting semaphore on the heap. The initial value and maximum are
161 * specified with `uxInitialCount` and `uxMaxCount` respectively.
162 *
163 * Returns a pointer to the semaphore on success, NULL on allocation failure.
164 */
165__always_inline static inline SemaphoreHandle_t
167{
168 SemaphoreHandle_t semaphore =
169 (SemaphoreHandle_t)malloc(sizeof(StaticSemaphore_t));
170 if (semaphore != NULL)
171 {
172 xSemaphoreCreateCountingStatic(uxMaxCount, uxInitialCount, semaphore);
173 }
174 return semaphore;
175}
176# endif
177
178/**
179 * Create a heap-allocated binary semaphore.
180 *
181 * Binary semaphores are implemented as counting semaphores with a maximum count
182 * of 1.
183 */
184__always_inline static inline SemaphoreHandle_t xSemaphoreCreateBinary()
185{
186 return xSemaphoreCreateCounting(1, 0);
187}
188
189/**
190 * Create a statically allocated binary semaphore.
191 *
192 * Binary semaphores are implemented as counting semaphores with a maximum count
193 * of 1.
194 */
195__always_inline static inline SemaphoreHandle_t
197{
198 return xSemaphoreCreateCountingStatic(1, 0, pxSemaphoreBuffer);
199}
200#endif
201
202#ifdef CHERIOT_EXPOSE_FREERTOS_MUTEX
203/**
204 * Create statically allocated mutex.
205 */
206__always_inline static inline SemaphoreHandle_t
208{
209 pxMutexBuffer->mutex.lockWord = 0;
210 CHERIOT_FREERTOS_SEMAPHORE_KIND_SET(pxMutexBuffer, CheriotFreeRTOS_Mutex);
211 return pxMutexBuffer;
212}
213
214# ifndef CHERIOT_NO_AMBIENT_MALLOC
215/**
216 * Create a heap-allocated mutex.
217 */
218__always_inline static inline SemaphoreHandle_t xSemaphoreCreateMutex()
219{
220 SemaphoreHandle_t semaphore =
221 (SemaphoreHandle_t)malloc(sizeof(StaticSemaphore_t));
222 if (semaphore != NULL)
223 {
225 }
226 return semaphore;
227}
228# endif
229#endif
230
231#ifdef CHERIOT_EXPOSE_FREERTOS_RECURSIVE_MUTEX
232
233/**
234 * Create a statically allocated recursive mutex.
235 */
236__always_inline static inline SemaphoreHandle_t
238{
239 pxMutexBuffer->recursiveMutex.lock.lockWord = 0;
240 pxMutexBuffer->recursiveMutex.depth = 0;
241 CHERIOT_FREERTOS_SEMAPHORE_KIND_SET(pxMutexBuffer,
243 return pxMutexBuffer;
244}
245
246# ifndef CHERIOT_NO_AMBIENT_MALLOC
247/**
248 * Create a heap-allocated recursive mutex.
249 */
250__always_inline static inline SemaphoreHandle_t
252{
253 SemaphoreHandle_t semaphore =
254 (SemaphoreHandle_t)malloc(sizeof(StaticSemaphore_t));
255 if (semaphore != NULL)
256 {
258 }
259 return semaphore;
260}
261# endif
262#endif
263
264/**
265 * Delete a heap-allocated semaphore, of any kind.
266 *
267 * Note: As on FreeRTOS, if there are waiters blocked on this semaphore then
268 * they will remain blocked until their timeout (if ever).
269 */
270__always_inline static inline void
272{
273 free(xSemaphore);
274}
275
276/**
277 * Get the current owner (thread ID) of a mutex. If this is a counting
278 * semaphore, or if the lock is not held, returns zero.
279 *
280 * Note: This API is inherently somewhat racy. If this returns the current
281 * thread's thread ID, then it cannot change, but any other return value may
282 * change between the time it is returned and the time the caller inspects it.
283 */
284__always_inline static inline TaskHandle_t
286{
287 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xMutex)
288 {
289 CHERIOT_FREERTOS_SEMAPHORE_CASE(return 0;)
290 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(
291 return xMutex->recursiveMutex.lock.lockWord & 0xffff;)
292 CHERIOT_FREERTOS_MUTEX_CASE(return xMutex->mutex.lockWord & 0xffff;)
293 }
294 return 0;
295}
296
297/**
298 * Returns the current count of a counting semaphore, or whether a mutex or
299 * binary semaphore is available
300 *
301 * Note: This API is inherently racy. Unless run with interrupts disabled,
302 * there is no guarantee that the value returned is still valid by the time the
303 * caller inspects it.
304 */
306{
307 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xSemaphore)
308 {
309 CHERIOT_FREERTOS_SEMAPHORE_CASE(return xSemaphore->semaphore.count;)
310 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(
311 return xSemaphore->recursiveMutex.lock.lockWord != 0;)
312 CHERIOT_FREERTOS_MUTEX_CASE(return xSemaphore->mutex.lockWord != 0;)
313 }
314 return 0;
315}
316
317/**
318 * A semaphore get (down) operation. If the semaphore value is zero, this can
319 * block for up to `xTicksToWait` ticks. Returns true if the semaphore was
320 * obtained, false if the timeout expired.
321 */
322static inline _Bool xSemaphoreTake(SemaphoreHandle_t xSemaphore,
323 TickType_t xTicksToWait)
324{
325 Timeout t = {0, xTicksToWait};
326 int ret = -1;
327 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xSemaphore)
328 {
329 CHERIOT_FREERTOS_SEMAPHORE_CASE(
330 ret = semaphore_get(&t, &xSemaphore->semaphore);)
331 CHERIOT_FREERTOS_MUTEX_CASE(
332 ret = flaglock_priority_inheriting_trylock(&t, &xSemaphore->mutex);)
333 // Recursive mutexes are not supposed to use this interface.
334 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(;);
335 }
336 return ret == 0;
337}
338
339/**
340 * Take a semaphore from code that may run in an ISR. CHERIoT RTOS does not
341 * permit code to run in ISRs and so this simply calls the normal code paths.
342 *
343 * The second parameter is a pointer to a variable that will be set to true if
344 * the caller needs to yield to wake a higher-priority task. This is
345 * unconditionally false on CHERIoT RTOS because the scheduler will wake any
346 * threads that are waiting on a semaphore. It is necessary on FreeRTOS
347 * because code in ISRs cannot call into the scheduler.
348 */
349__always_inline static inline _Bool __attribute__((overloadable))
351 BaseType_t *pxHigherPriorityTaskWoken)
352{
353 *pxHigherPriorityTaskWoken = 0;
354 return xSemaphoreTake(xSemaphore, 0);
355}
356
357/*
358 * Take a semaphore from code that may run in an ISR. CHERIoT RTOS does not
359 * permit code to run in ISRs and so this simply calls the normal code paths.
360 */
361__always_inline static inline _Bool __attribute__((overloadable))
363{
364 return xSemaphoreTake(xSemaphore, 0);
365}
366
367/**
368 * A semaphore put (up) operation. If there are tasks blocked on the semaphore,
369 * this will unblock one of them. Otherwise, the semaphore value is incremented
370 * by one.
371 */
372__always_inline static inline _Bool xSemaphoreGive(SemaphoreHandle_t xSemaphore)
373{
374 int ret = -1;
375 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xSemaphore)
376 {
377 CHERIOT_FREERTOS_SEMAPHORE_CASE(
378 ret = semaphore_put(&xSemaphore->semaphore);)
379 CHERIOT_FREERTOS_MUTEX_CASE(flaglock_unlock(&xSemaphore->mutex);
380 ret = 0;)
381 // Recursive mutexes are not supposed to use this interface.
382 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(;);
383 }
384 return ret == 0;
385}
386
387/**
388 * Give a semaphore from code that may run in an ISR. CHERIoT RTOS does not
389 * permit code to run in ISRs and so this simply calls the normal code paths.
390 *
391 * The second parameter is a pointer to a variable that will be set to true if
392 * the caller needs to yield to wake a higher-priority task. This is
393 * unconditionally false on CHERIoT RTOS.
394 */
395__always_inline static inline _Bool __attribute__((overloadable))
397 BaseType_t *pxHigherPriorityTaskWoken)
398{
399 *pxHigherPriorityTaskWoken = 0;
400 return xSemaphoreGive(xSemaphore);
401}
402
403/*
404 * Give a semaphore from code that may run in an ISR. CHERIoT RTOS does not
405 * permit code to run in ISRs and so this simply calls the normal code paths.
406 */
407__always_inline static inline _Bool __attribute__((overloadable))
409{
410 return xSemaphoreGive(xSemaphore);
411}
412
413/**
414 * Try to acquire a recursive mutex. Returns true on success, false on
415 * failure.
416 */
417__always_inline static inline _Bool
419{
420 Timeout t = {0, xTicksToWait};
421 int ret = -1;
422 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xMutex)
423 {
424 CHERIOT_FREERTOS_SEMAPHORE_CASE(;)
425 CHERIOT_FREERTOS_MUTEX_CASE(;)
426 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(
427 ret = recursivemutex_trylock(&t, &xMutex->recursiveMutex);)
428 }
429 return ret == 0;
430}
431
432/**
433 * Release a recursive mutex.
434 */
435__always_inline static inline _Bool
437{
438 int ret = -1;
439 CHERIOT_FREERTOS_SEMAPHORE_SWITCH(xMutex)
440 {
441 CHERIOT_FREERTOS_SEMAPHORE_CASE(;)
442 CHERIOT_FREERTOS_MUTEX_CASE(;)
443 CHERIOT_FREERTOS_RECURSIVE_MUTEX_CASE(
444 ret = recursivemutex_unlock(&xMutex->recursiveMutex);)
445 }
446 return ret == 0;
447}
448
449/**
450 * Launder a semaphore back into the type used to initialise it.
451 */
452__always_inline static inline BaseType_t
454 StaticSemaphore_t **ppxSemaphoreBuffer)
455{
456 *ppxSemaphoreBuffer = xSemaphore;
457 return pdTRUE;
458}
FreeRTOS porting layer.
int32_t BaseType_t
FreeRTOS default signed integer type.
Definition FreeRTOS.h:179
Ticks TickType_t
FreeRTOS type for durations expressed in ticks.
Definition FreeRTOS.h:175
uint32_t UBaseType_t
FreeRTOS default unsigned integer type.
Definition FreeRTOS.h:183
uint16_t TaskHandle_t
FreeRTOS type representing a task handle, mapped to a thread ID in CHERIoT RTOS.
Definition FreeRTOS.h:188
#define pdTRUE
FreeRTOS definition of true.
Definition FreeRTOS.h:52
C compatible interface to synchronisation primitives.
int __cheri_libcall semaphore_get(TimeoutArgument timeout, struct CountingSemaphoreState *semaphore)
Semaphore get operation, decrements the semaphore count.
int __cheri_libcall recursivemutex_unlock(struct RecursiveMutexState *mutex)
Unlock a recursive mutex.
void __cheri_libcall flaglock_unlock(struct FlagLockState *lock)
Unlock a flag lock.
int __cheri_libcall flaglock_priority_inheriting_trylock(TimeoutArgument timeout, struct FlagLockState *lock)
Try to lock a flag lock.
int __cheri_libcall recursivemutex_trylock(TimeoutArgument timeout, struct RecursiveMutexState *lock)
Try to acquire a recursive mutex.
int __cheri_libcall semaphore_put(struct CountingSemaphoreState *semaphore)
Semaphore put operation.
static SemaphoreHandle_t xSemaphoreCreateBinary()
Create a heap-allocated binary semaphore.
Definition semphr.h:184
static SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount)
Allocate a counting semaphore on the heap.
Definition semphr.h:166
static _Bool xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex, TickType_t xTicksToWait)
Try to acquire a recursive mutex.
Definition semphr.h:418
static BaseType_t xSemaphoreGetStaticBuffer(SemaphoreHandle_t xSemaphore, StaticSemaphore_t **ppxSemaphoreBuffer)
Launder a semaphore back into the type used to initialise it.
Definition semphr.h:453
static void vSemaphoreDelete(SemaphoreHandle_t xSemaphore)
Delete a heap-allocated semaphore, of any kind.
Definition semphr.h:271
static UBaseType_t uxSemaphoreGetCount(SemaphoreHandle_t xSemaphore)
Returns the current count of a counting semaphore, or whether a mutex or binary semaphore is availabl...
Definition semphr.h:305
static SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void)
Create a heap-allocated recursive mutex.
Definition semphr.h:251
static SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic(StaticSemaphore_t *pxMutexBuffer)
Create a statically allocated recursive mutex.
Definition semphr.h:237
static SemaphoreHandle_t xSemaphoreCreateCountingStatic(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer)
Initialise a statically allocated semaphore.
Definition semphr.h:142
static _Bool xSemaphoreGive(SemaphoreHandle_t xSemaphore)
A semaphore put (up) operation.
Definition semphr.h:372
static SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer)
Create statically allocated mutex.
Definition semphr.h:207
static TaskHandle_t xSemaphoreGetMutexHolder(SemaphoreHandle_t xMutex)
Get the current owner (thread ID) of a mutex.
Definition semphr.h:285
static _Bool xSemaphoreTakeFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken)
Take a semaphore from code that may run in an ISR.
Definition semphr.h:350
static _Bool xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t *pxHigherPriorityTaskWoken)
Give a semaphore from code that may run in an ISR.
Definition semphr.h:396
static SemaphoreHandle_t xSemaphoreCreateMutex()
Create a heap-allocated mutex.
Definition semphr.h:218
static SemaphoreHandle_t xSemaphoreCreateBinaryStatic(StaticSemaphore_t *pxSemaphoreBuffer)
Create a statically allocated binary semaphore.
Definition semphr.h:196
static _Bool xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait)
A semaphore get (down) operation.
Definition semphr.h:322
StaticSemaphore_t * SemaphoreHandle_t
Type for a handle to a counting semaphore.
Definition semphr.h:132
CheriotFreeRTOS_SemaphoreKind
Enumeration used to differentiate the different kinds of FreeRTOS semaphores in this compatibility la...
Definition semphr.h:61
@ CheriotFreeRTOS_Mutex
A non-recursive, priority-inheriting mutex.
Definition semphr.h:72
@ CheriotFreeRTOS_Semaphore
A FreeRTOS counting or binary semaphore.
Definition semphr.h:66
@ CheriotFreeRTOS_RecursiveMutex
A recursive mutex.
Definition semphr.h:78
static _Bool xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex)
Release a recursive mutex.
Definition semphr.h:436
This file implements the C11 and C++23 C atomics interfaces.
State for a counting semaphore.
Definition locks.h:64
uint32_t maxCount
The maximum value for the counter.
Definition locks.h:73
State for a flag lock.
Definition locks.h:18
State for a recursive mutex.
Definition locks.h:48
uint16_t depth
The count of the times the lock has been acquired by the same thread.
Definition locks.h:57
struct FlagLockState lock
The underlying lock.
Definition locks.h:52
Type used to define space for storing any of the exposed FreeRTOS semaphore types.
Definition semphr.h:87
enum CheriotFreeRTOS_SemaphoreKind kind
The discriminator for the union above.
Definition semphr.h:111
Structure representing a timeout.
Definition timeout.h:47