1use 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#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
27pub struct Instant(u64);
28
29impl Instant {
30 #[inline]
31 pub fn from_micros(micros: u64) -> Self {
34 Self(micros)
35 }
36
37 #[inline]
38 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 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 pub fn as_millis(&self) -> u64 {
64 self.0 / 1000
65 }
66
67 #[inline]
68 pub fn as_secs(&self) -> u64 {
71 self.0 / 1000000
72 }
73
74 #[inline]
75 pub fn as_micros(&self) -> u64 {
78 self.0
79 }
80
81 #[inline]
82 pub fn subsec_millis(&self) -> u64 {
88 self.0 % 1000000 / 1000
89 }
90
91 #[inline]
92 pub fn subsec_micros(&self) -> u64 {
98 self.0 % 1000000
99 }
100
101 #[inline]
102 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 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 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 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]
215pub fn time_since_start() -> Instant {
218 Instant::from_micros(unsafe { bindings::micros() })
219}
220
221#[derive(PartialEq, Eq, PartialOrd, Ord, Clone)]
222pub struct Task(bindings::task_t);
224
225impl Task {
226 pub const DEFAULT_PRIORITY: u32 = bindings::TASK_PRIORITY_DEFAULT;
228
229 pub const DEFAULT_STACK_DEPTH: u16 = bindings::TASK_STACK_DEPTH_DEFAULT as u16;
231
232 #[inline]
233 pub fn delay(dur: Duration) {
235 unsafe {
236 bindings::task_delay(dur.as_millis() as u32);
237 }
238 }
239
240 #[inline]
241 pub fn current() -> Self {
243 Self(unsafe { bindings::task_get_current() })
244 }
245
246 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 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 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 drop(Box::from_raw(arg));
285 }
286 r
287 }
288 }
289
290 #[inline]
291 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 pub fn name(&self) -> String {
315 unsafe { from_cstring_raw(bindings::task_get_name(self.0)) }
316 }
317
318 #[inline]
319 pub fn priority(&self) -> u32 {
321 unsafe { bindings::task_get_priority(self.0) }
322 }
323
324 #[inline]
325 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 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
366pub enum TaskState {
368 Running,
370 Ready,
372 Blocked,
374 Suspended,
376 Deleted,
378}
379
380#[derive(Copy, Clone, Debug)]
381pub enum GenericSleep {
383 NotifyTake(Option<Instant>),
386 Timestamp(Instant),
388}
389
390impl GenericSleep {
391 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 pub fn timeout(self) -> Option<Instant> {
415 match self {
416 GenericSleep::NotifyTake(v) => v,
417 GenericSleep::Timestamp(v) => Some(v),
418 }
419 }
420
421 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
436pub trait Selectable<T = ()>: Sized {
439 fn poll(self) -> Result<T, Self>;
442 fn sleep(&self) -> GenericSleep;
444}
445
446#[inline]
447pub 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]
478pub 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]
509pub 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]
540pub 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]
552pub fn delay(time: Duration) -> impl Selectable {
555 delay_until(time_since_start() + time)
556}
557
558#[inline]
559pub 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::*;