#[cfg(feature = "smp")]
use crossbeam_utils::Backoff;
use hermit_sync::InterruptTicketMutex;
use crate::arch::core_local::*;
use crate::scheduler::task::TaskHandlePriorityQueue;
struct SemaphoreState {
count: isize,
queue: TaskHandlePriorityQueue,
}
pub struct Semaphore {
state: InterruptTicketMutex<SemaphoreState>,
}
impl Semaphore {
pub const fn new(count: isize) -> Self {
Self {
state: InterruptTicketMutex::new(SemaphoreState {
count,
queue: TaskHandlePriorityQueue::new(),
}),
}
}
pub fn acquire(&self, time: Option<u64>) -> bool {
#[cfg(feature = "smp")]
let backoff = Backoff::new();
let core_scheduler = core_scheduler();
let wakeup_time = time.map(|ms| crate::arch::processor::get_timer_ticks() + ms * 1000);
loop {
let mut locked_state = self.state.lock();
if locked_state.count > 0 {
locked_state.count -= 1;
return true;
} else if let Some(t) = wakeup_time {
if t < crate::arch::processor::get_timer_ticks() {
locked_state
.queue
.remove(core_scheduler.get_current_task_handle());
return false;
}
}
#[cfg(feature = "smp")]
if backoff.is_completed() {
core_scheduler.block_current_task(wakeup_time);
locked_state
.queue
.push(core_scheduler.get_current_task_handle());
drop(locked_state);
core_scheduler.reschedule();
} else {
drop(locked_state);
backoff.snooze();
}
#[cfg(not(feature = "smp"))]
{
core_scheduler.block_current_task(wakeup_time);
locked_state
.queue
.push(core_scheduler.get_current_task_handle());
drop(locked_state);
core_scheduler.reschedule();
}
}
}
pub fn try_acquire(&self) -> bool {
let mut locked_state = self.state.lock();
if locked_state.count > 0 {
locked_state.count -= 1;
true
} else {
false
}
}
pub fn release(&self) {
if let Some(task) = {
let mut locked_state = self.state.lock();
locked_state.count += 1;
locked_state.queue.pop()
} {
core_scheduler().custom_wakeup(task);
};
}
}