//! 序列锁

use core::{hint::unlikely, ptr::read_volatile};

use crate::processor::{cpu_relax, smp_rmb, smp_wmb};

/// 序列计数
#[derive(Default)]
pub struct SeqCount {
    seqence: u32,
}

impl SeqCount {
    /// 创建序列锁
    pub const fn new() -> Self {
        Self { seqence: 0 }
    }

    #[inline(always)]
    fn __read_seqcount_begin(&self) -> u32 {
        loop {
            let ret = unsafe { read_volatile(&raw const self.seqence) };
            if unlikely((ret & 1) != 0) {
                cpu_relax();
                continue;
            }
            return ret;
        }
    }

    /// 读序列化开始
    #[inline(always)]
    pub fn read_seqcount_begin(&self) -> u32 {
        let ret = self.__read_seqcount_begin();
        smp_rmb();
        ret
    }

    #[inline(always)]
    fn __read_seqcount_retry(&self, start: u32) -> bool {
        unlikely(self.seqence != start)
    }

    /// 是否需要重新序列化
    #[inline(always)]
    pub fn read_seqcount_retry(&self, start: u32) -> bool {
        smp_rmb();
        self.__read_seqcount_retry(start)
    }

    /// 读取当前seqcount
    #[inline(always)]
    pub fn read_seqcount(&self) -> u32 {
        let ret = unsafe { read_volatile(&raw const self.seqence) };
        smp_rmb();
        ret
    }

    /// 写序列化开始
    #[inline(always)]
    pub fn write_seqcount_begin(&mut self) {
        self.seqence += 1;
        smp_wmb();
    }

    /// 写序列化结束
    #[inline(always)]
    pub fn write_seqcount_end(&mut self) {
        smp_wmb();
        self.seqence += 1;
    }

    /// 重定向读者序列化
    #[inline(always)]
    pub fn write_seqcount_latch(&mut self) {
        smp_wmb();
        self.seqence += 1;
        smp_wmb();
    }

    /// 做一个写序列化屏障
    #[inline(always)]
    pub fn write_seqcount_barrier(&mut self) {
        self.seqence += 1;
        smp_wmb();
        self.seqence += 1;
    }
}
