use super::{Attr, THREADS_MASK, THREADS_MAX};
use core::sync::atomic::{
AtomicU32,
Ordering::{self, Acquire, Relaxed, Release},
};
#[repr(C)]
pub(crate) struct AtomicStatus {
wcnt: AtomicU32,
rcnt: AtomicU32,
pcnt: u64,
stat: AtomicU32,
worker: u16,
wexp: u8,
wexp_next: u8,
group: u8,
pri: u8,
is_yield: bool,
}
pub(crate) const STAT_RUN: u32 = 0;
pub(crate) const STAT_JOIN: u32 = 1;
pub(crate) const STAT_RETURN: u32 = 2;
pub(crate) const STAT_FINISH: u32 = 3;
pub(crate) const STAT_ABORT: u32 = 4;
pub(crate) const STAT_EXIT: u32 = 5;
impl AtomicStatus {
pub(crate) fn new(attr: &Attr) -> Self {
Self {
rcnt: AtomicU32::new(1),
wcnt: AtomicU32::new(1),
stat: AtomicU32::new(STAT_RUN),
wexp: 1,
wexp_next: 1,
group: attr.group_id,
pri: attr.priority,
worker: 0,
pcnt: 0,
is_yield: false,
}
}
pub(crate) fn yield_now(&mut self) {
self.is_yield = true;
}
pub(crate) fn set_wake_expect(&mut self, wexp: u8) {
self.wexp_next = wexp;
}
pub(crate) fn test_dec_wake(&mut self, cnt: u32) -> bool {
if !self.is_yield {
return self.test_dec_wake_do(cnt);
}
self.is_yield = false;
true
}
fn test_dec_wake_do(&mut self, cnt: u32) -> bool {
if self.wexp != self.wexp_next {
self.wexp = self.wexp_next;
self.wexp_next = 1;
}
let cnt = self.wcnt.fetch_sub(cnt, Release) - cnt;
cnt >= self.wexp as u32
}
pub(crate) fn test_inc_wake(&self) -> bool {
let cnt = self.wcnt.fetch_add(1, Acquire);
cnt == self.wexp as u32 - 1
}
pub(crate) fn wake_count(&self) -> u32 {
self.wcnt.load(Relaxed)
}
pub(crate) fn poll_inc(&mut self) {
self.pcnt += 1;
}
pub(crate) fn poll_cnt(&self) -> u64 {
self.pcnt
}
pub(crate) fn inc_ref(&self) {
let _ = self.rcnt.fetch_add(1, Relaxed);
}
pub(crate) fn test_dec_ref(&self) -> bool {
self.rcnt.fetch_sub(1, Relaxed) == 1
}
pub(crate) fn status(&self, order: Ordering) -> u32 {
self.stat.load(order)
}
pub(crate) fn set_status(&self, new: u32, order: Ordering) {
self.stat.store(new, order);
}
pub(crate) fn cmp_xchg_status(
&self,
current: u32,
new: u32,
set_order: Ordering,
) -> Result<u32, u32> {
self.stat.compare_exchange(current, new, set_order, Relaxed)
}
pub(crate) fn priority(&self) -> u8 {
self.pri
}
pub(crate) fn group(&self) -> u8 {
self.group
}
pub(crate) fn get_local(&self) -> Option<u16> {
if self.worker >= THREADS_MAX as u16 {
return Some(self.worker & THREADS_MASK as u16);
}
None
}
pub(crate) fn set_local(&mut self, id: u16) {
self.worker = id | 0x8000;
}
pub(crate) fn freeze_local(&mut self, id: u16) {
self.worker += 0x0400;
self.worker |= id;
}
pub(crate) fn unfreeze_local(&mut self) {
self.worker -= 0x0400;
if self.worker < THREADS_MAX as u16 {
self.worker = 0;
}
}
}