blob: 0fa3d41ff2dc4894b7e6b016b98fc17c8ccb8c38 [file] [log] [blame]
#pragma once
/**
* This file contains the interface for an event-group API, implemented in the
* `event_group` library, which provides a mechanism for wait for one or more
* events from a set of 24 to occur.
*
* This API is provided to ease porting from FreeRTOS. The event group
* abstraction is not a good design and is difficult to use correctly. It is
* not recommended for new code. CHERIoT RTOS provides a futex as the
* low-level primitive on which event groups are implemented. For new code,
* you will almost certainly be able to build a cleaner and less error-prone
* abstraction on top of futexes directly.
*/
#include "cdefs.h"
#include "thread.h"
#include <compartment-macros.h>
#include <stdint.h>
#include <stdlib.h>
#include <timeout.h>
struct EventGroup;
struct SObjStruct;
/**
* Create a new event group, allocated using `heapCapability`. The event group
* is returned via `outGroup`.
*
* This returns zero on success. Otherwise it returns a negative error code.
* If the timeout expires then this returns `-ETIMEDOUT`, if memory cannot be
* allocated it returns `-ENOMEM`.
*/
int __cheri_libcall eventgroup_create(struct Timeout *timeout,
struct SObjStruct *heapCapability,
struct EventGroup **outGroup);
/**
* Wait for events in an event group. The `bitsWanted` argument must contain
* at least one bit set in the low 24 bits (and none in the high bits). This
* indicates the specific events to wait for. If `waitForAll` is true then all
* of the bits in `bitsWanted` must be set in the event group before this
* returns. If `waitForAll` is false then any of the bits in `bitsWanted`
* being set in the event group will cause this to return.
*
* If this returns zero then `outBits` will contain the bits that were set at
* the time that the condition became true. If this returns `-ETIMEDOUT` then
* `outBits` will contain the bits that were set at the time that the timeout
* expired.
*
* Note: `waitForAll` requires all bits to be set *at the same time*. This
* makes it trivial to introduce race conditions if used with multiple waiters
* and `clearOnExit`, or if different threads clear bits different bits in the
* waited set.
*
* If `clearOnExit` is true and this returns successfully then the bits in
* `bitsWanted` will be cleared in the event group before this returns.
*/
int __cheri_libcall eventgroup_wait(Timeout *timeout,
struct EventGroup *group,
uint32_t *outBits,
uint32_t bitsWanted,
_Bool waitForAll,
_Bool clearOnExit);
/**
* Set one or more bits in an event group. The `bitsToSet` argument contains
* the bits to set. Any thread waiting with `eventgroup_wait` will be woken if
* the bits that it is waiting for are set.
*
* This returns zero on success. If the timeout expires before this returns
* then it returns `-ETIMEDOUT`.
*
* Independent of success or failure, `outBits` will be used to return the set
* of currently set bits in this event group.
*/
int __cheri_libcall eventgroup_set(Timeout *timeout,
struct EventGroup *group,
uint32_t *outBits,
uint32_t bitsToSet);
/**
* Clear one or more bits in an event group. The `bitsToClear` argument
* contains the set of bits to clear. This does not wake any threads.
*
* This returns zero on success. If the timeout expires before this returns
* then it returns `-ETIMEDOUT`.
*
* Independent of success or failure, `outBits` will be used to return the set
* of currently set bits in this event group.
*/
int __cheri_libcall eventgroup_clear(Timeout *timeout,
struct EventGroup *group,
uint32_t *outBits,
uint32_t bitsToClear);
/**
* Returns the current value of the event bits via `outBits`. Returns 0 on
* success (there is currently no way in which this call can fail).
*
* This API is inherently racy. Any arbitrary set of bits may be set or
* cleared in between this call reading from the event group and returning.
*/
int __cheri_libcall eventgroup_get(struct EventGroup *group, uint32_t *outBits);
/**
* Destroy an event group. This forces all waiters to wake and frees the
* underlying memory.
*/
int __cheri_libcall eventgroup_destroy(struct SObjStruct *heapCapability,
struct EventGroup *group);
/**
* Destroy an event group without tacking the lock.
*
* This API is inherently racy. Its main purpose is to cleanup the event group
* in an error handler context, when taking lock may be impossible.
*/
int __cheri_libcall eventgroup_destroy_force(struct SObjStruct *heapCapability,
struct EventGroup *group);