Skip to main content

ove/async_runtime/
eventgroup.rs

1// Copyright (C) 2026 Kamil Lulko <kamil.lulko@gmail.com>
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4//
5// This file is part of oveRTOS.
6
7//! Async wrapper around [`crate::EventGroup`] using
8//! `ove_eventgroup_set_notify`.
9
10use core::future::poll_fn;
11use core::task::Poll;
12
13use embassy_sync::waitqueue::AtomicWaker;
14
15use crate::error::{Error, Result};
16use crate::eventgroup::{EventGroup, WaitFlags};
17
18/// Async wrapper around an [`ove::EventGroup`](crate::EventGroup).
19pub struct AsyncEventGroup {
20    inner: EventGroup,
21    waker: AtomicWaker,
22}
23
24// SAFETY: `AsyncEventGroup` wraps an `ove_event_group_t` FFI handle.  The
25// substrate serialises concurrent waiters via its own internal lock, so
26// cross-thread `&self` access is sound.
27unsafe impl Send for AsyncEventGroup {}
28unsafe impl Sync for AsyncEventGroup {}
29
30impl AsyncEventGroup {
31    pub const fn new(inner: EventGroup) -> Self {
32        Self {
33            inner,
34            waker: AtomicWaker::new(),
35        }
36    }
37
38    pub fn arm(&'static self) -> Result<()> {
39        unsafe {
40            self.inner.set_notify(
41                Some(eg_notify_trampoline),
42                &self.waker as *const AtomicWaker as *mut core::ffi::c_void,
43            )
44        }
45    }
46
47    /// Await one or more of the bits in `mask`. Returns the bit pattern
48    /// that satisfied the wait.
49    pub async fn wait_bits(&'static self, mask: u32, flags: WaitFlags) -> Result<u32> {
50        poll_fn(|cx| {
51            match self.inner.try_wait_bits(mask, flags) {
52                Ok(v) => return Poll::Ready(Ok(v)),
53                Err(Error::WouldBlock) | Err(Error::Timeout) => {}
54                Err(e) => return Poll::Ready(Err(e)),
55            }
56            self.waker.register(cx.waker());
57            match self.inner.try_wait_bits(mask, flags) {
58                Ok(v) => Poll::Ready(Ok(v)),
59                Err(Error::WouldBlock) | Err(Error::Timeout) => Poll::Pending,
60                Err(e) => Poll::Ready(Err(e)),
61            }
62        })
63        .await
64    }
65
66    #[inline]
67    pub fn inner(&self) -> &EventGroup {
68        &self.inner
69    }
70}
71
72unsafe extern "C" fn eg_notify_trampoline(user_data: *mut core::ffi::c_void) {
73    let waker = unsafe { &*(user_data as *const AtomicWaker) };
74    waker.wake();
75}