commit
324b64c2ed
@ -0,0 +1,40 @@
|
||||
/// Interface for inter-processor interrupt.
|
||||
/// This module wraps inter-processor interrupt into a broadcast-calling style.
|
||||
|
||||
use crate::consts::KERNEL_OFFSET;
|
||||
use alloc::boxed::{Box, FnBox};
|
||||
use alloc::sync::Arc;
|
||||
use apic::{LocalApic, XApic, LAPIC_ADDR};
|
||||
use core::sync::atomic::{spin_loop_hint, AtomicU8, Ordering};
|
||||
|
||||
pub type IPIEventItem = Box<FnBox()>;
|
||||
|
||||
unsafe fn get_apic() -> XApic {
|
||||
let mut lapic = unsafe { XApic::new(KERNEL_OFFSET + LAPIC_ADDR) };
|
||||
lapic
|
||||
}
|
||||
|
||||
pub fn invoke_on_allcpu(f: impl Fn() + 'static, wait: bool) {
|
||||
// Step 1: initialize
|
||||
use super::interrupt::consts::IPIFuncCall;
|
||||
let mut apic = unsafe { get_apic() };
|
||||
let func = Arc::new(f);
|
||||
let cpu_count = super::gdt::Cpu::iter().count();
|
||||
let rest_count = Arc::new(AtomicU8::new(cpu_count as u8));
|
||||
// Step 2: invoke
|
||||
for cpu in super::gdt::Cpu::iter() {
|
||||
let func_clone = func.clone();
|
||||
let rest_clone = rest_count.clone();
|
||||
cpu.notify_event(Box::new(move || {
|
||||
func_clone();
|
||||
rest_clone.fetch_sub(1, Ordering::Relaxed);
|
||||
}));
|
||||
apic.send_ipi(cpu.id() as u8, IPIFuncCall);
|
||||
}
|
||||
if wait {
|
||||
// spin if remote invocation do not complete
|
||||
while rest_count.load(Ordering::Relaxed) != 0 {
|
||||
spin_loop_hint();
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
Subproject commit bb73d6ecce1ab0e6fae692c51e4335772b0335d4
|
||||
Subproject commit 9fb1d459b50bc14c7ac56d9fd94b4b8485620730
|
Loading…
Reference in new issue