-
-
Notifications
You must be signed in to change notification settings - Fork 194
Expand file tree
/
Copy pathipi.rs
More file actions
107 lines (94 loc) · 3.59 KB
/
Copy pathipi.rs
File metadata and controls
107 lines (94 loc) · 3.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
use alloc::sync::Arc;
use system_error::SystemError;
#[cfg(target_arch = "x86_64")]
use crate::arch::driver::apic::{CurrentApic, LocalAPIC};
use crate::{
sched::cpu_rq,
smp::{core::smp_get_processor_id, cpu::ProcessorId},
};
use super::{
irqdata::IrqHandlerData,
irqdesc::{IrqHandler, IrqReturn},
HardwareIrqNumber, IrqNumber,
};
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IpiKind {
KickCpu,
/// TLB shootdown IPI.
///
/// Do NOT directly `send_ipi(IpiKind::FlushTLB, ..)` in new code:
///
/// - On x86_64 this IPI is issued by [`crate::mm::tlb::flush_tlb_multi`] via the per-CPU CSD
/// protocol; the receiving end [`FlushTLBIpiHandler`] reads `FlushTlbInfo` from the CSD
/// and performs a synchronous ack. A bare send provides no context and won't be waited
/// on by the initiator, inevitably breaking the "shootdown before free" ordering.
/// - On RISC-V `send_ipi(IpiKind::FlushTLB, ..)` is completed synchronously via SBI
/// `remote_sfence_vma` without going through `FlushTLBIpiHandler`; it is still
/// restricted to be called only from the `mm::tlb` layer to keep the interface
/// consistent with future per-mm range flush support.
///
/// All subsystems (mmap/munmap/mprotect/mremap/madvise/zap_file_mappings/...) must go
/// through [`crate::mm::mmu_gather::MmuGather`] + [`crate::mm::ucontext::AddressSpace::flush_tlb_range`].
FlushTLB,
/// 指定中断向量号
SpecVector(HardwareIrqNumber),
}
/// IPI投递目标
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[allow(dead_code)]
pub enum IpiTarget {
/// 当前CPU
Current,
/// 所有CPU
All,
/// 除了当前CPU以外的所有CPU
Other,
/// 指定的CPU
Specified(ProcessorId),
}
/// 处理跨核心CPU唤醒的IPI
#[derive(Debug)]
pub struct KickCpuIpiHandler;
impl IrqHandler for KickCpuIpiHandler {
fn handle(
&self,
_irq: IrqNumber,
_static_data: Option<&dyn IrqHandlerData>,
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
) -> Result<IrqReturn, SystemError> {
#[cfg(target_arch = "x86_64")]
CurrentApic.send_eoi();
let cpu = smp_get_processor_id();
let rq = cpu_rq(cpu.data() as usize);
// scheduler_ipi() + sched_ttwu_pending():
// IPI handler 中仅 try_lock,若 rq 锁被持有(如 load_balance 的 double_rq_lock)
// 则跳过,任务留在 WakeQueue 中,由下一次 scheduler_tick 或 __schedule 排空。
// Linux 的 scheduler_ipi() 完全不操作 rq 锁,实际唤醒延迟到 softirq / schedule 路径。
if let Some((rq, _guard)) = rq.try_self_lock() {
rq.update_rq_clock();
rq.drain_wake_queue();
}
Ok(IrqReturn::Handled)
}
}
/// IPI handler for TLB flushing.
///
/// This handler is only invoked via the per-CPU CSD protocol by `crate::mm::tlb::flush_tlb_multi`.
/// Direct bare sends of `IpiKind::FlushTLB` are forbidden.
#[derive(Debug)]
pub struct FlushTLBIpiHandler;
impl IrqHandler for FlushTLBIpiHandler {
fn handle(
&self,
_irq: IrqNumber,
_static_data: Option<&dyn IrqHandlerData>,
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
) -> Result<IrqReturn, SystemError> {
// Read the FlushTlbInfo context written by the initiator from the per-CPU CSD slot,
// perform TLB invalidation for the corresponding range, and finally set `done` so
// the initiator can synchronously wait.
crate::mm::tlb::remote_flush_tlb_on_ipi();
Ok(IrqReturn::Handled)
}
}