vex_rt/rtos/
mod.rs

1//! Multitasking primitives.
2
3use alloc::{boxed::Box, format, string::String};
4use core::{
5    cmp::min,
6    convert::TryInto,
7    fmt::{self, Debug, Display, Formatter},
8    marker::PhantomData,
9    ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign},
10    time::Duration,
11};
12use cstring_interop::{from_cstring_raw, with_cstring};
13use libc::c_void;
14
15use crate::{
16    bindings,
17    error::{Error, SentinelError},
18};
19
20const TIMEOUT_MAX: u32 = 0xffffffff;
21
22/// Represents a time on a monotonically increasing clock (i.e., time since
23/// program start).
24///
25/// This type has a precision of 1 microsecond.
26#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
27pub struct Instant(u64);
28
29impl Instant {
30    #[inline]
31    /// Creates a new `Instant` from the specified number of *whole*
32    /// microseconds since program start.
33    pub fn from_micros(micros: u64) -> Self {
34        Self(micros)
35    }
36
37    #[inline]
38    /// Creates a new `Instant` from the specified number of whole milliseconds
39    /// since program start.
40    pub fn from_millis(millis: u64) -> Self {
41        Self(
42            millis
43                .checked_mul(1000)
44                .expect("overflow when creating Instant from milliseconds"),
45        )
46    }
47
48    /// Creates a new `Instant` from the specified number of whole seconds since
49    /// program start.
50    pub fn from_secs(secs: u64) -> Self {
51        Self(
52            secs.checked_mul(1000000)
53                .expect("overflow when creating Instant from seconds"),
54        )
55    }
56
57    #[inline]
58    /// Returns the number of *whole* seconds since program start contained by
59    /// this `Instant`.
60    ///
61    /// The returned value does not include the fractional (milliseconds) part
62    /// of the time value.
63    pub fn as_millis(&self) -> u64 {
64        self.0 / 1000
65    }
66
67    #[inline]
68    /// Returns the number of *whole* seconds since program start contained by
69    /// this `Instant`.
70    pub fn as_secs(&self) -> u64 {
71        self.0 / 1000000
72    }
73
74    #[inline]
75    /// Returns the number of whole microseconds since program start contained
76    /// by this `Instant`.
77    pub fn as_micros(&self) -> u64 {
78        self.0
79    }
80
81    #[inline]
82    /// Returns the fractional part of this `Instant`, in *whole* milliseconds.
83    ///
84    /// This method does **not** return the time value in milliseconds. The
85    /// returned number always represents a fractional portion of a second
86    /// (i.e., it is less than one thousand).
87    pub fn subsec_millis(&self) -> u64 {
88        self.0 % 1000000 / 1000
89    }
90
91    #[inline]
92    /// Returns the fractional part of this `Instant`, in whole microseconds.
93    ///
94    /// This method does **not** return the time value in microseconds. The
95    /// returned number always represents a fractional portion of a second
96    /// (i.e., it is less than one million).
97    pub fn subsec_micros(&self) -> u64 {
98        self.0 % 1000000
99    }
100
101    #[inline]
102    /// Checked addition of a [`Duration`] to an `Instant`. Computes `self +
103    /// rhs`, returning [`None`] if overflow occurred.
104    pub fn checked_add(self, rhs: Duration) -> Option<Self> {
105        Some(Self(self.0.checked_add(rhs.as_micros().try_into().ok()?)?))
106    }
107
108    #[inline]
109    /// Checked subtraction of a [`Duration`] from an `Instant`. Computes
110    /// `self - rhs`, returning [`None`] if the result would be negative or
111    /// overflow occurred.
112    pub fn checked_sub(self, rhs: Duration) -> Option<Instant> {
113        Some(Self(self.0.checked_sub(rhs.as_micros().try_into().ok()?)?))
114    }
115
116    #[inline]
117    /// Checked subtraction of two `Instant`s. Computes `self - rhs`, returning
118    /// [`None`] if the result would be negative or overflow occurred.
119    pub fn checked_sub_instant(self, rhs: Self) -> Option<Duration> {
120        Some(Duration::from_micros(self.0.checked_sub(rhs.0)?))
121    }
122
123    #[inline]
124    /// Checked multiplication of an `Instant` by a scalar. Computes `self *
125    /// rhs`, returning [`None`] if an overflow occurred.
126    pub fn checked_mul(self, rhs: u64) -> Option<Instant> {
127        Some(Self(self.0.checked_mul(rhs)?))
128    }
129}
130
131impl Add<Duration> for Instant {
132    type Output = Instant;
133
134    fn add(self, rhs: Duration) -> Self::Output {
135        self.checked_add(rhs)
136            .expect("overflow when adding duration to instant")
137    }
138}
139
140impl Sub<Duration> for Instant {
141    type Output = Instant;
142
143    fn sub(self, rhs: Duration) -> Self::Output {
144        self.checked_sub(rhs)
145            .expect("overflow when subtracting duration from instant")
146    }
147}
148
149impl Sub for Instant {
150    type Output = Duration;
151
152    fn sub(self, rhs: Self) -> Self::Output {
153        self.checked_sub_instant(rhs)
154            .expect("overflow when subtracting instants")
155    }
156}
157
158impl Mul<u64> for Instant {
159    type Output = Instant;
160
161    fn mul(self, rhs: u64) -> Self::Output {
162        self.checked_mul(rhs)
163            .expect("overflow when multiplying instant by scalar")
164    }
165}
166
167impl Div<u64> for Instant {
168    type Output = Instant;
169
170    #[inline]
171    fn div(self, rhs: u64) -> Self::Output {
172        Self(self.0 / rhs)
173    }
174}
175
176impl AddAssign<Duration> for Instant {
177    fn add_assign(&mut self, rhs: Duration) {
178        *self = *self + rhs;
179    }
180}
181
182impl SubAssign<Duration> for Instant {
183    fn sub_assign(&mut self, rhs: Duration) {
184        *self = *self - rhs;
185    }
186}
187
188impl MulAssign<u64> for Instant {
189    fn mul_assign(&mut self, rhs: u64) {
190        *self = *self * rhs;
191    }
192}
193
194impl DivAssign<u64> for Instant {
195    fn div_assign(&mut self, rhs: u64) {
196        *self = *self / rhs;
197    }
198}
199
200impl Debug for Instant {
201    #[inline]
202    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
203        write!(f, "{}.{:06}s", self.0 / 1000000, self.0 % 1000000)
204    }
205}
206
207impl Display for Instant {
208    #[inline]
209    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
210        write!(f, "{}.{:06}s", self.0 / 1000000, self.0 % 1000000)
211    }
212}
213
214#[inline]
215/// Gets the current timestamp (i.e., the time which has passed since program
216/// start).
217pub fn time_since_start() -> Instant {
218    Instant::from_micros(unsafe { bindings::micros() })
219}
220
221#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
222/// Represents a FreeRTOS task.
223pub struct Task(bindings::task_t);
224
225impl Task {
226    /// The default priority for new tasks.
227    pub const DEFAULT_PRIORITY: u32 = bindings::TASK_PRIORITY_DEFAULT;
228
229    /// The default stack depth for new tasks.
230    pub const DEFAULT_STACK_DEPTH: u16 = bindings::TASK_STACK_DEPTH_DEFAULT as u16;
231
232    #[inline]
233    /// Delays the current task by the specified duration.
234    pub fn delay(dur: Duration) {
235        unsafe {
236            bindings::task_delay(dur.as_millis() as u32);
237        }
238    }
239
240    #[inline]
241    /// Gets the current task.
242    pub fn current() -> Self {
243        Self(unsafe { bindings::task_get_current() })
244    }
245
246    /// Finds a task by its name.
247    pub fn find_by_name(name: &str) -> Result<Self, Error> {
248        let ptr = (with_cstring(name.into(), |name| unsafe {
249            bindings::task_get_by_name(name.into_raw()).check()
250        }) as Result<*mut c_void, Error>)?;
251        if ptr.is_null() {
252            Err(Error::Custom(format!("task not found: {}", name)))
253        } else {
254            Ok(Self(ptr))
255        }
256    }
257
258    #[inline]
259    /// Spawns a new task with no name and the default priority and stack depth.
260    pub fn spawn<F>(f: F) -> Result<Self, Error>
261    where
262        F: FnOnce() + Send + 'static,
263    {
264        Self::spawn_ext("", Self::DEFAULT_PRIORITY, Self::DEFAULT_STACK_DEPTH, f)
265    }
266
267    /// Spawns a new task with the specified name, priority and stack depth.
268    pub fn spawn_ext<F>(name: &str, priority: u32, stack_depth: u16, f: F) -> Result<Self, Error>
269    where
270        F: FnOnce() + Send + 'static,
271    {
272        extern "C" fn run<F: FnOnce()>(arg: *mut libc::c_void) {
273            let cb_box: Box<F> = unsafe { Box::from_raw(arg as *mut F) };
274            cb_box()
275        }
276
277        let cb = Box::new(f);
278        unsafe {
279            let arg = Box::into_raw(cb);
280            let r = Self::spawn_raw(name, priority, stack_depth, run::<F>, arg as *mut _);
281            if r.is_err() {
282                // We need to re-box the pointer if the task could not be created, to avoid a
283                // memory leak.
284                drop(Box::from_raw(arg));
285            }
286            r
287        }
288    }
289
290    #[inline]
291    /// Spawns a new task from a C function pointer and an arbitrary data
292    /// pointer.
293    ///
294    /// # Safety
295    ///
296    /// This is unsafe because it
297    pub unsafe fn spawn_raw(
298        name: &str,
299        priority: u32,
300        stack_depth: u16,
301        f: unsafe extern "C" fn(arg1: *mut libc::c_void),
302        arg: *mut libc::c_void,
303    ) -> Result<Self, Error> {
304        with_cstring(name.into(), |cname| {
305            Ok(Self(
306                bindings::task_create(Some(f), arg, priority, stack_depth, cname.into_raw())
307                    .check()?,
308            ))
309        })
310    }
311
312    #[inline]
313    /// Gets the name of the task.
314    pub fn name(&self) -> String {
315        unsafe { from_cstring_raw(bindings::task_get_name(self.0)) }
316    }
317
318    #[inline]
319    /// Gets the priority of the task.
320    pub fn priority(&self) -> u32 {
321        unsafe { bindings::task_get_priority(self.0) }
322    }
323
324    #[inline]
325    /// Gets the state of the task.
326    pub fn state(&self) -> TaskState {
327        match unsafe { bindings::task_get_state(self.0) } {
328            bindings::task_state_e_t_E_TASK_STATE_RUNNING => TaskState::Running,
329            bindings::task_state_e_t_E_TASK_STATE_READY => TaskState::Ready,
330            bindings::task_state_e_t_E_TASK_STATE_BLOCKED => TaskState::Blocked,
331            bindings::task_state_e_t_E_TASK_STATE_SUSPENDED => TaskState::Suspended,
332            bindings::task_state_e_t_E_TASK_STATE_DELETED => TaskState::Deleted,
333            bindings::task_state_e_t_E_TASK_STATE_INVALID => {
334                panic!("invalid task handle: {:#010x}", self.0 as usize)
335            }
336            x => panic!("bindings::task_get_state returned unexpected value: {}", x),
337        }
338    }
339
340    #[inline]
341    /// Unsafely deletes the task.
342    ///
343    /// # Safety
344    ///
345    /// This is unsafe because it does not guarantee that the task's code safely
346    /// unwinds (i.e., that destructors are called, memory is freed and other
347    /// resources are released).
348    pub unsafe fn delete(&self) {
349        bindings::task_delete(self.0)
350    }
351}
352
353impl Debug for Task {
354    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
355        f.debug_struct("Task")
356            .field("name", &self.name())
357            .field("priority", &self.priority())
358            .finish()
359    }
360}
361
362unsafe impl Send for Task {}
363
364unsafe impl Sync for Task {}
365
366/// Represents the state of a [`Task`].
367pub enum TaskState {
368    /// The task is actively executing.
369    Running,
370    /// The task exists and is available to run, but is not currently running.
371    Ready,
372    /// The task is delayed or blocked by a mutex, semaphore or I/O operation.
373    Blocked,
374    /// The task is suspended.
375    Suspended,
376    /// The task has been deleted.
377    Deleted,
378}
379
380#[derive(Copy, Clone, Debug)]
381/// Represents a future time to sleep until.
382pub enum GenericSleep {
383    /// Represents a future time when a notification occurs. If a timestamp is
384    /// present, then it represents whichever is earlier.
385    NotifyTake(Option<Instant>),
386    /// Represents an explicit future timestamp.
387    Timestamp(Instant),
388}
389
390impl GenericSleep {
391    /// Sleeps until the future time represented by `self`. The result is the
392    /// number of notifications which were present, if the sleep ended due to
393    /// notification.
394    pub fn sleep(self) -> u32 {
395        match self {
396            GenericSleep::NotifyTake(timeout) => {
397                let timeout = timeout.map_or(TIMEOUT_MAX, |v| {
398                    v.checked_sub_instant(time_since_start())
399                        .map_or(0, |d| d.as_millis() as u32)
400                });
401                unsafe { bindings::task_notify_take(true, timeout) }
402            }
403            GenericSleep::Timestamp(v) => {
404                if let Some(d) = v.checked_sub_instant(time_since_start()) {
405                    Task::delay(d);
406                }
407                0
408            }
409        }
410    }
411
412    #[inline]
413    /// Get the timestamp represented by `self`, if it is present.
414    pub fn timeout(self) -> Option<Instant> {
415        match self {
416            GenericSleep::NotifyTake(v) => v,
417            GenericSleep::Timestamp(v) => Some(v),
418        }
419    }
420
421    /// Combine two `GenericSleep` objects to one which represents the earliest
422    /// possible time of the two.
423    pub fn combine(self, other: Self) -> Self {
424        match (self, other) {
425            (GenericSleep::Timestamp(a), GenericSleep::Timestamp(b)) => {
426                GenericSleep::Timestamp(core::cmp::min(a, b))
427            }
428            (a, b) => GenericSleep::NotifyTake(
429                a.timeout()
430                    .map_or(b.timeout(), |a| Some(b.timeout().map_or(a, |b| min(a, b)))),
431            ),
432        }
433    }
434}
435
436/// Represents a future event which can be used with the
437/// [`select!`](crate::select!) macro.
438pub trait Selectable<T = ()>: Sized {
439    /// Processes the event if it is ready, consuming the event object;
440    /// otherwise, it provides a replacement event object.
441    fn poll(self) -> Result<T, Self>;
442    /// Gets the earliest time that the event could be ready.
443    fn sleep(&self) -> GenericSleep;
444}
445
446#[inline]
447/// Creates a new [`Selectable`] event by mapping the result of a given one.
448pub fn select_map<'a, T: 'a, U: 'a>(
449    event: impl Selectable<T> + 'a,
450    f: impl 'a + FnOnce(T) -> U,
451) -> impl Selectable<U> + 'a {
452    struct MapSelect<T, U, E: Selectable<T>, F: FnOnce(T) -> U> {
453        event: E,
454        f: F,
455        _t: PhantomData<T>,
456    }
457
458    impl<T, U, E: Selectable<T>, F: FnOnce(T) -> U> Selectable<U> for MapSelect<T, U, E, F> {
459        fn poll(self) -> Result<U, Self> {
460            match self.event.poll() {
461                Ok(r) => Ok((self.f)(r)),
462                Err(event) => Err(Self { event, ..self }),
463            }
464        }
465        fn sleep(&self) -> GenericSleep {
466            self.event.sleep()
467        }
468    }
469
470    MapSelect {
471        event,
472        f,
473        _t: PhantomData,
474    }
475}
476
477#[inline]
478/// Creates a new [`Selectable`] event which processes exactly one of the given
479/// events.
480pub fn select_either<'a, T: 'a>(
481    fst: impl Selectable<T> + 'a,
482    snd: impl Selectable<T> + 'a,
483) -> impl Selectable<T> + 'a {
484    struct EitherSelect<T, E1: Selectable<T>, E2: Selectable<T>>(E1, E2, PhantomData<T>);
485
486    impl<T, E1: Selectable<T>, E2: Selectable<T>> Selectable<T> for EitherSelect<T, E1, E2> {
487        fn poll(self) -> Result<T, Self> {
488            Err(Self(
489                match self.0.poll() {
490                    Ok(r) => return Ok(r),
491                    Err(e) => e,
492                },
493                match self.1.poll() {
494                    Ok(r) => return Ok(r),
495                    Err(e) => e,
496                },
497                PhantomData,
498            ))
499        }
500        fn sleep(&self) -> GenericSleep {
501            self.0.sleep().combine(self.1.sleep())
502        }
503    }
504
505    EitherSelect(fst, snd, PhantomData)
506}
507
508#[inline]
509/// Creates a new [`Selectable`] event which never completes if the given base
510/// event is None.
511pub fn select_option<'a, T: 'a>(base: Option<impl Selectable<T> + 'a>) -> impl Selectable<T> + 'a {
512    struct OptionSelect<T, E: Selectable<T>>(Option<E>, PhantomData<T>);
513
514    impl<T, E: Selectable<T>> Selectable<T> for OptionSelect<T, E> {
515        fn poll(self) -> Result<T, Self> {
516            Err(Self(
517                if let Some(e) = self.0 {
518                    match e.poll() {
519                        Ok(r) => return Ok(r),
520                        Err(e) => Some(e),
521                    }
522                } else {
523                    None
524                },
525                PhantomData,
526            ))
527        }
528
529        fn sleep(&self) -> GenericSleep {
530            self.0
531                .as_ref()
532                .map_or(GenericSleep::NotifyTake(None), Selectable::sleep)
533        }
534    }
535
536    OptionSelect(base, PhantomData)
537}
538
539#[inline]
540/// Awaits a [`Selectable`] event.
541pub fn select<'a, T: 'a>(mut event: impl Selectable<T> + 'a) -> T {
542    loop {
543        event.sleep().sleep();
544        event = match event.poll() {
545            Ok(r) => return r,
546            Err(e) => e,
547        }
548    }
549}
550
551#[inline]
552/// Creates a new [`Selectable`] event which completes after the given duration
553/// of time.
554pub fn delay(time: Duration) -> impl Selectable {
555    delay_until(time_since_start() + time)
556}
557
558#[inline]
559/// Creates a new [`Selectable`] event which completes at the given timestamp.
560pub fn delay_until(timestamp: Instant) -> impl Selectable {
561    struct DelaySelect(Instant);
562
563    impl Selectable for DelaySelect {
564        fn poll(self) -> Result<(), Self> {
565            if time_since_start() >= self.0 {
566                Ok(())
567            } else {
568                Err(self)
569            }
570        }
571        fn sleep(&self) -> GenericSleep {
572            GenericSleep::Timestamp(self.0)
573        }
574    }
575
576    DelaySelect(timestamp)
577}
578
579mod broadcast;
580mod channel;
581mod context;
582mod event;
583mod r#loop;
584mod mutex;
585mod promise;
586mod queue;
587mod semaphore;
588
589pub use broadcast::*;
590pub use channel::*;
591pub use context::*;
592pub use event::*;
593pub use mutex::*;
594pub use promise::*;
595pub use queue::*;
596pub use r#loop::*;
597pub use semaphore::*;