use core::intrinsics::likely;

use crate::{
    arch::driver::apic::{apic_timer::APIC_TIMER_IRQ_NUM, CurrentApic, LocalAPIC},
    exception::{irqdesc::irq_desc_manager, softirq::do_softirq, IrqNumber},
    process::{
        utils::{current_pcb_flags, current_pcb_preempt_count},
        ProcessFlags,
    },
    sched::{SchedMode, __schedule},
};

use super::TrapFrame;

#[no_mangle]
unsafe extern "C" fn x86_64_do_irq(trap_frame: &mut TrapFrame, vector: u32) {
    // swapgs

    if trap_frame.is_from_user() {
        x86_64::registers::segmentation::GS::swap();
    }

    // 由于x86上面,虚拟中断号与物理中断号是一一对应的,所以这里直接使用vector作为中断号来查询irqdesc

    let desc = irq_desc_manager().lookup(IrqNumber::new(vector));

    if likely(desc.is_some()) {
        let desc = desc.unwrap();
        let handler = desc.handler();
        if likely(handler.is_some()) {
            handler.unwrap().handle(&desc, trap_frame);
        } else {
            CurrentApic.send_eoi();
        }
    } else {
        CurrentApic.send_eoi();
    }

    do_softirq();

    if current_pcb_preempt_count() > 0 {
        return;
    }
    // 检测当前进程是否可被调度
    if (current_pcb_flags().contains(ProcessFlags::NEED_SCHEDULE))
        || vector == APIC_TIMER_IRQ_NUM.data()
    {
        __schedule(SchedMode::SM_PREEMPT);
    }
}