use foundation_nostd::comp::condvar_comp::{CondVar, Mutex};
use std::panic::{RefUnwindSafe, UnwindSafe};
use super::Waker;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LockState {
Free,
Locked,
Released,
}
pub struct LockSignal {
event: CondVar,
lock: Mutex<LockState>,
}
impl UnwindSafe for LockSignal {}
impl RefUnwindSafe for LockSignal {}
pub enum NotifyDirective {
One,
All,
}
impl Waker for LockSignal {
fn wake(&self) {
self.signal_all();
}
}
impl Default for LockSignal {
fn default() -> Self {
Self::new()
}
}
impl LockSignal {
#[must_use]
pub fn new() -> Self {
Self {
event: CondVar::new(),
lock: Mutex::new(LockState::Free),
}
}
pub fn signal(&self, directive: NotifyDirective) {
let mut state = self.lock.lock().unwrap();
*state = LockState::Released;
drop(state);
match directive {
NotifyDirective::One => self.event.notify_one(),
NotifyDirective::All => self.event.notify_all(),
}
}
pub fn probe(&self) -> LockState {
let current_state_guard = self.lock.lock().unwrap();
let current_state = current_state_guard.clone();
drop(current_state_guard);
current_state
}
pub fn probe_locked(&self) -> bool {
let current_state = self.lock.lock().unwrap();
let is_locked = *current_state == LockState::Locked;
drop(current_state);
is_locked
}
pub fn try_lock(&self) -> bool {
let mut current_state = self.lock.lock().unwrap();
if *current_state == LockState::Locked {
return false;
}
*current_state = LockState::Locked;
drop(current_state);
true
}
pub fn lock(&self) {
let mut current_state = self.lock.lock().unwrap();
if *current_state != LockState::Locked {
*current_state = LockState::Locked;
}
drop(current_state);
}
pub fn signal_one(&self) {
self.signal(NotifyDirective::One);
}
pub fn signal_all(&self) {
self.signal(NotifyDirective::All);
}
pub fn lock_and_wait(&self) {
if self.try_lock() {
tracing::debug!("LockSignal was locked");
}
self.wait();
}
pub fn wait(&self) {
let mut current_state = self.lock.lock().unwrap();
if *current_state == LockState::Free {
tracing::debug!("Lock is free");
return;
}
loop {
if *current_state == LockState::Released {
*current_state = LockState::Free;
tracing::debug!("Lock is now free");
return;
}
if *current_state == LockState::Free {
tracing::debug!("Lock already freed by another thread");
return;
}
tracing::debug!("Waiting for event signal to be received");
current_state = self.event.wait(current_state).unwrap();
}
}
}