//! Thread synchronizes through the acquisition and release of semaphore and mutexes
//!
//! RT-Thread uses thread semaphores, mutexes, and event sets to achieve inter-thread synchronization. Thread synchronizes through the acquisition and release of semaphore and mutexes; the mutex uses priority inheritance to solve the common priority inversion problem in the real-time system. The thread synchronization mechanism allows threads to wait according to priorities or to acquire semaphores or mutexes following the first-in first-out method. Threads synchronize through sending and receiving of events; event sets allows "or trigger" and "and trigger" for multiple events, suitable for situations where threads are waiting for multiple events.
//! The concepts of semaphores, mutexes, and event sets are detailed in the "Inter-Thread Synchronization" chapter.
//! ### TODO
//! 1. rt_event
pub mod mutex;
pub mod sem;
use crate::ffi::{rt_enter_critical, rt_exit_critical, RT_IPC_FLAG_FIFO, RT_IPC_FLAG_PRIO};
use crate::Result;
use core::{
cell::UnsafeCell,
fmt,
mem::MaybeUninit,
ops::{Deref, DerefMut},
pin::Pin,
sync::atomic::{AtomicUsize, Ordering},
};
#[derive(Copy, Clone)]
pub enum IpcFlag {
Fifo,
Priority,
}
impl From<IpcFlag> for u8 {
#[inline]
fn from(flag: IpcFlag) -> Self {
(match flag {
IpcFlag::Fifo => RT_IPC_FLAG_FIFO,
IpcFlag::Priority => RT_IPC_FLAG_PRIO,
}) as u8
}
}
#[must_use = "if unused the SchedulerLock will immediately unlock"]
pub struct SchedulerLock<T: ?Sized> {
data: UnsafeCell<T>,
}
pub struct SchedulerLockGuard<'a, T: ?Sized + 'a> {
lock: &'a SchedulerLock<T>,
}
unsafe impl<T: ?Sized + Send> Send for SchedulerLock<T> {}
unsafe impl<T: ?Sized + Send> Sync for SchedulerLock<T> {}
impl<T> SchedulerLock<T> {
pub const fn new(data: T) -> Self {
Self {
data: UnsafeCell::new(data),
}
}
pub fn lock(&self) -> SchedulerLockGuard<'_, T> {
unsafe {
rt_enter_critical();
}
SchedulerLockGuard { lock: self }
}
pub fn into_inner(self) -> Result<T>
where
T: Sized,
{
// We know statically that there are no outstanding references to
// `self` so there's no need to lock the inner mutex.
Ok(self.data.into_inner())
}
pub fn get_mut(&mut self) -> Result<&mut T> {
// We know statically that there are no other references to `self`, so
// there's no need to lock the inner mutex.
Ok(unsafe { &mut *self.data.get() })
}
}
impl<T: ?Sized> Deref for SchedulerLockGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.lock.data.get() }
}
}
impl<T: ?Sized> DerefMut for SchedulerLockGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.lock.data.get() }
}
}
impl<T: ?Sized> Drop for SchedulerLockGuard<'_, T> {
#[inline]
fn drop(&mut self) {
unsafe {
rt_exit_critical();
}
}
}
const UNINIT: usize = 0;
const UNOWEND: usize = 1;
const OWEND: usize = 2;
pub struct Static<T> {
state: AtomicUsize,
data: UnsafeCell<MaybeUninit<T>>,
}
unsafe impl<T: Send> Send for Static<T> {}
unsafe impl<T: Send> Sync for Static<T> {}
#[must_use = "if unused the StaticOwned will immediately unlock"]
pub struct StaticOwned<'lock, T> {
lock: &'lock Static<T>,
}
impl<T> Static<T> {
pub const fn new() -> Self {
Self {
state: AtomicUsize::new(UNINIT),
data: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn try_own(&self) -> Option<StaticOwned<T>>
where
T: Default,
{
let state = self.state.load(Ordering::SeqCst);
if state == OWEND {
return None;
}
let state = self.state.compare_and_swap(state, OWEND, Ordering::SeqCst);
match state {
OWEND => return None,
UNINIT => unsafe {
*self.data.get() = MaybeUninit::new(T::default());
},
_ => (),
}
Some(StaticOwned::new(self))
}
pub fn try_own_uninit(&self) -> Option<StaticOwned<T>> {
let state = self.state.load(Ordering::SeqCst);
if state == OWEND {
return None;
}
let state = self.state.compare_and_swap(state, OWEND, Ordering::SeqCst);
match state {
OWEND => return None,
_ => (),
}
Some(StaticOwned::new(self))
}
}
impl<'lock, T> StaticOwned<'lock, T> {
fn new(lock: &'lock Static<T>) -> Self {
Self { lock }
}
pub fn get_ref(&self) -> Pin<&'lock T> {
unsafe { Pin::new_unchecked(&*(&*self.lock.data.get()).as_ptr()) }
}
pub fn get_mut(&mut self) -> Pin<&'lock mut T> {
unsafe { Pin::new_unchecked(&mut *(&mut *self.lock.data.get()).as_mut_ptr()) }
}
}
impl<T> Drop for StaticOwned<'_, T> {
#[inline]
fn drop(&mut self) {
self.lock.state.store(UNOWEND, Ordering::SeqCst)
}
}
impl<T: fmt::Debug> fmt::Debug for StaticOwned<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get_ref().fmt(f)
}
}
impl<T: fmt::Display> fmt::Display for StaticOwned<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get_ref().fmt(f)
}
}