Skip to main content

ove/async_runtime/
semaphore.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::Semaphore`] using
8//! `ove_sem_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::sync::Semaphore;
17
18/// Async wrapper around an [`ove::Semaphore`](crate::Semaphore).
19pub struct AsyncSemaphore {
20    inner: Semaphore,
21    waker: AtomicWaker,
22}
23
24// SAFETY: `AsyncSemaphore` wraps a `Semaphore` (whose own Send/Sync
25// reflects the substrate's atomic counter + waiter list).  The
26// `AtomicWaker` is `Sync` by construction.
27unsafe impl Send for AsyncSemaphore {}
28unsafe impl Sync for AsyncSemaphore {}
29
30impl AsyncSemaphore {
31    pub const fn new(inner: Semaphore) -> 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(sem_notify_trampoline),
42                &self.waker as *const AtomicWaker as *mut core::ffi::c_void,
43            )
44        }
45    }
46
47    /// Acquire one permit. Awaits until the count is non-zero.
48    pub async fn acquire(&'static self) -> Result<()> {
49        poll_fn(|cx| {
50            match self.inner.try_acquire() {
51                Ok(()) => return Poll::Ready(Ok(())),
52                Err(Error::WouldBlock) | Err(Error::Timeout) => {}
53                Err(e) => return Poll::Ready(Err(e)),
54            }
55            self.waker.register(cx.waker());
56            match self.inner.try_acquire() {
57                Ok(()) => Poll::Ready(Ok(())),
58                Err(Error::WouldBlock) | Err(Error::Timeout) => Poll::Pending,
59                Err(e) => Poll::Ready(Err(e)),
60            }
61        })
62        .await
63    }
64
65    #[inline]
66    pub fn inner(&self) -> &Semaphore {
67        &self.inner
68    }
69}
70
71unsafe extern "C" fn sem_notify_trampoline(user_data: *mut core::ffi::c_void) {
72    let waker = unsafe { &*(user_data as *const AtomicWaker) };
73    waker.wake();
74}