//! 系统时钟信息实现
#![allow(static_mut_refs)]

use crate::{
    processor::barrier,
    sync::seqlock::SeqCount,
    time::{NSEC_PER_SEC, clocksource::ClockSource},
};

struct TkReadBase {
    clock: ClockSource,
    mask: u64,
    cycle_last: u64,
    mult: u32,
    shift: u32,
    ktime_nsec: u64,
}

#[repr(align(64))]
struct TimeKeeper {
    tkr_mono: TkReadBase,
    ktime_sec: u64,
    seqcount: SeqCount,
}

impl TimeKeeper {
    #[inline(always)]
    fn tk_clock_read(&self) -> u64 {
        self.tkr_mono.clock.read()
    }

    fn tk_setup_internals(&mut self) {
        self.tkr_mono.mask = self.tkr_mono.clock.mask();
        self.tkr_mono.mult = self.tkr_mono.clock.mult();
        self.tkr_mono.shift = self.tkr_mono.clock.shift();
        self.tkr_mono.cycle_last = self.tk_clock_read();
        self.tkr_mono.ktime_nsec = 0;
        self.ktime_sec = 0;
    }

    #[inline(always)]
    fn tk_normalize_xtime(&mut self) {
        while self.tkr_mono.ktime_nsec >= NSEC_PER_SEC << self.tkr_mono.shift {
            self.tkr_mono.ktime_nsec -= NSEC_PER_SEC << self.tkr_mono.shift;
            self.ktime_sec += 1;
        }
    }

    fn timekeeping_forward_now(&mut self) {
        let cycle_now = self.tk_clock_read();
        let delta = clocksource_delta(cycle_now, self.tkr_mono.cycle_last, self.tkr_mono.mask);
        self.tkr_mono.cycle_last = cycle_now;
        self.tkr_mono.ktime_nsec += delta * u64::from(self.tkr_mono.mult);

        self.tk_normalize_xtime();
    }

    #[inline(always)]
    fn timekeeping_get_delta(&self) -> u64 {
        // 当中断里更新 cycle_last 时, 将会出现 now < cycle_last 情况, 因此这里提前获取 cycle_last,
        // 即便 cycle_last 被更新了, seqcount 将会保证重新读取最新 cycles.
        let cycle_last = self.tkr_mono.cycle_last;
        barrier();
        let cycle_now = self.tk_clock_read();
        clocksource_delta(cycle_now, cycle_last, self.tkr_mono.mask)
    }

    #[inline(always)]
    fn timekeeping_delta_to_ns(&self, delta: u64) -> u64 {
        let mut nsec = delta * u64::from(self.tkr_mono.mult) + self.tkr_mono.ktime_nsec;
        nsec >>= self.tkr_mono.shift;
        nsec
    }

    #[inline(always)]
    fn timekeeping_get_ns(&self) -> u64 {
        let delta = self.timekeeping_get_delta();
        self.timekeeping_delta_to_ns(delta)
    }
}

#[inline(always)]
fn clocksource_delta(now: u64, last: u64, mask: u64) -> u64 {
    (now - last) & mask
}

static mut TIMEKEEPER: TimeKeeper = TimeKeeper {
    tkr_mono: TkReadBase {
        clock: ClockSource::new(),
        mask: 0,
        cycle_last: 0,
        mult: 0,
        shift: 0,
        ktime_nsec: 0,
    },
    ktime_sec: 0,
    seqcount: SeqCount::new(),
};

pub(super) fn timekeeping_init(clocksource: ClockSource) {
    let tk = unsafe { &mut TIMEKEEPER };
    tk.seqcount.write_seqcount_begin();
    tk.tkr_mono.clock = clocksource;
    tk.tk_setup_internals();
    tk.seqcount.write_seqcount_end();
}

// 中断中使用, 周期更新系统时钟
pub(super) fn update_wall_time() {
    let tk = unsafe { &mut TIMEKEEPER };

    tk.seqcount.write_seqcount_begin();
    tk.timekeeping_forward_now();
    tk.seqcount.write_seqcount_end();
}

/// 获取系统tick
pub fn ktime_get_cycles() -> u64 {
    unsafe { TIMEKEEPER.tk_clock_read() }
}

/// 获取系统秒数
pub fn ktime_get_seconds() -> u64 {
    unsafe { TIMEKEEPER.ktime_sec }
}

/// 获取系统纳秒数
pub fn ktime_get() -> u64 {
    let tk = unsafe { &TIMEKEEPER };

    loop {
        let seq = tk.seqcount.read_seqcount_begin();
        let base = tk.ktime_sec;
        let nsecs = tk.timekeeping_get_ns();
        if !tk.seqcount.read_seqcount_retry(seq) {
            return base * NSEC_PER_SEC + nsecs;
        }
    }
}

/// 获取系统时钟精度(ns)
pub fn ktime_get_resolution_ns() -> u32 {
    let tk = unsafe { &TIMEKEEPER };
    tk.tkr_mono.mult >> tk.tkr_mono.shift
}
