mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-08 21:06:48 +00:00
Make current_cpu_racy
a method of CpuId
This commit is contained in:
parent
758c80c321
commit
56e9824dd1
@ -33,7 +33,7 @@ use kcmdline::KCmdlineArg;
|
|||||||
use ostd::{
|
use ostd::{
|
||||||
arch::qemu::{exit_qemu, QemuExitCode},
|
arch::qemu::{exit_qemu, QemuExitCode},
|
||||||
boot::boot_info,
|
boot::boot_info,
|
||||||
cpu::{CpuId, CpuSet, PinCurrentCpu},
|
cpu::{CpuId, CpuSet},
|
||||||
};
|
};
|
||||||
use process::{spawn_init_process, Process};
|
use process::{spawn_init_process, Process};
|
||||||
use sched::SchedPolicy;
|
use sched::SchedPolicy;
|
||||||
@ -104,22 +104,21 @@ pub fn init() {
|
|||||||
|
|
||||||
fn ap_init() {
|
fn ap_init() {
|
||||||
fn ap_idle_thread() {
|
fn ap_idle_thread() {
|
||||||
let preempt_guard = ostd::task::disable_preempt();
|
log::info!(
|
||||||
let cpu_id = preempt_guard.current_cpu();
|
"Kernel idle thread for CPU #{} started.",
|
||||||
drop(preempt_guard);
|
// No races because `ap_idle_thread` runs on a certain AP.
|
||||||
log::info!("Kernel idle thread for CPU #{} started.", cpu_id.as_usize());
|
CpuId::current_racy().as_usize(),
|
||||||
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
crate::thread::Thread::yield_now();
|
crate::thread::Thread::yield_now();
|
||||||
ostd::cpu::sleep_for_interrupt();
|
ostd::cpu::sleep_for_interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let preempt_guard = ostd::task::disable_preempt();
|
|
||||||
let cpu_id = preempt_guard.current_cpu();
|
|
||||||
drop(preempt_guard);
|
|
||||||
|
|
||||||
ThreadOptions::new(ap_idle_thread)
|
ThreadOptions::new(ap_idle_thread)
|
||||||
.cpu_affinity(cpu_id.into())
|
// No races because `ap_init` runs on a certain AP.
|
||||||
|
.cpu_affinity(CpuId::current_racy().into())
|
||||||
.sched_policy(SchedPolicy::Idle)
|
.sched_policy(SchedPolicy::Idle)
|
||||||
.spawn();
|
.spawn();
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ static APIC_TYPE: Once<ApicType> = Once::new();
|
|||||||
/// let ticks = apic.timer_current_count();
|
/// let ticks = apic.timer_current_count();
|
||||||
/// apic.set_timer_init_count(0);
|
/// apic.set_timer_init_count(0);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_or_init(guard: &dyn PinCurrentCpu) -> &(dyn Apic + 'static) {
|
pub fn get_or_init(_guard: &dyn PinCurrentCpu) -> &(dyn Apic + 'static) {
|
||||||
struct ForceSyncSend<T>(T);
|
struct ForceSyncSend<T>(T);
|
||||||
|
|
||||||
// SAFETY: `ForceSyncSend` is `Sync + Send`, but accessing its contained value is unsafe.
|
// SAFETY: `ForceSyncSend` is `Sync + Send`, but accessing its contained value is unsafe.
|
||||||
@ -59,7 +59,9 @@ pub fn get_or_init(guard: &dyn PinCurrentCpu) -> &(dyn Apic + 'static) {
|
|||||||
static APIC_INSTANCE: Once<ForceSyncSend<Box<dyn Apic + 'static>>> = Once::new();
|
static APIC_INSTANCE: Once<ForceSyncSend<Box<dyn Apic + 'static>>> = Once::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
let apic_instance = APIC_INSTANCE.get_on_cpu(guard.current_cpu());
|
// No races due to `_guard`, but use `current_racy` to avoid calling via the vtable.
|
||||||
|
// TODO: Find a better way to make `dyn PinCurrentCpu` easy to use?
|
||||||
|
let apic_instance = APIC_INSTANCE.get_on_cpu(crate::cpu::CpuId::current_racy());
|
||||||
|
|
||||||
// The APIC instance has already been initialized.
|
// The APIC instance has already been initialized.
|
||||||
if let Some(apic) = apic_instance.get() {
|
if let Some(apic) = apic_instance.get() {
|
||||||
|
@ -27,16 +27,34 @@ impl CpuId {
|
|||||||
pub const fn as_usize(self) -> usize {
|
pub const fn as_usize(self) -> usize {
|
||||||
self.0 as usize
|
self.0 as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the ID of the current CPU.
|
||||||
|
///
|
||||||
|
/// This function is safe to call, but is vulnerable to races. The returned CPU
|
||||||
|
/// ID may be outdated if the task migrates to another CPU.
|
||||||
|
///
|
||||||
|
/// To ensure that the CPU ID is up-to-date, do it under any guards that
|
||||||
|
/// implement the [`PinCurrentCpu`] trait.
|
||||||
|
pub fn current_racy() -> Self {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
assert!(IS_CURRENT_CPU_INITED.load());
|
||||||
|
|
||||||
|
Self(CURRENT_CPU.load())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The error type returned when converting an out-of-range integer to [`CpuId`].
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct CpuIdFromIntError;
|
||||||
|
|
||||||
impl TryFrom<usize> for CpuId {
|
impl TryFrom<usize> for CpuId {
|
||||||
type Error = &'static str;
|
type Error = CpuIdFromIntError;
|
||||||
|
|
||||||
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
fn try_from(value: usize) -> Result<Self, Self::Error> {
|
||||||
if value < num_cpus() {
|
if value < num_cpus() {
|
||||||
Ok(CpuId(value as u32))
|
Ok(CpuId(value as u32))
|
||||||
} else {
|
} else {
|
||||||
Err("The given CPU ID is out of range")
|
Err(CpuIdFromIntError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,24 +141,10 @@ unsafe fn set_this_cpu_id(id: u32) {
|
|||||||
pub unsafe trait PinCurrentCpu {
|
pub unsafe trait PinCurrentCpu {
|
||||||
/// Returns the ID of the current CPU.
|
/// Returns the ID of the current CPU.
|
||||||
fn current_cpu(&self) -> CpuId {
|
fn current_cpu(&self) -> CpuId {
|
||||||
current_cpu_racy()
|
CpuId::current_racy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the ID of the current CPU.
|
|
||||||
///
|
|
||||||
/// This function is safe to call, but is vulnerable to races. The returned CPU
|
|
||||||
/// ID may be outdated if the task migrates to another CPU.
|
|
||||||
///
|
|
||||||
/// To ensure that the CPU ID is up-to-date, do it under any guards that
|
|
||||||
/// implements the [`PinCurrentCpu`] trait.
|
|
||||||
pub fn current_cpu_racy() -> CpuId {
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
assert!(IS_CURRENT_CPU_INITED.load());
|
|
||||||
|
|
||||||
CpuId(CURRENT_CPU.load())
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: A guard that enforces the atomic mode requires disabling any
|
// SAFETY: A guard that enforces the atomic mode requires disabling any
|
||||||
// context switching. So naturally, the current task is pinned on the CPU.
|
// context switching. So naturally, the current task is pinned on the CPU.
|
||||||
unsafe impl<T: InAtomicMode> PinCurrentCpu for T {}
|
unsafe impl<T: InAtomicMode> PinCurrentCpu for T {}
|
||||||
|
@ -195,8 +195,8 @@ cpu_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_remote_flush() {
|
fn do_remote_flush() {
|
||||||
// No races because we are in IRQs/have disabled preempts.
|
// No races because we are in IRQs or have disabled preemption.
|
||||||
let current_cpu = crate::cpu::current_cpu_racy();
|
let current_cpu = crate::cpu::CpuId::current_racy();
|
||||||
|
|
||||||
let mut new_op_queue = OpsStack::new();
|
let mut new_op_queue = OpsStack::new();
|
||||||
{
|
{
|
||||||
|
@ -78,16 +78,15 @@ cpu_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn do_inter_processor_call(_trapframe: &TrapFrame) {
|
fn do_inter_processor_call(_trapframe: &TrapFrame) {
|
||||||
// TODO: in interrupt context, disabling interrupts is not necessary.
|
// No races because we are in IRQs.
|
||||||
let preempt_guard = trap::disable_local();
|
let this_cpu_id = crate::cpu::CpuId::current_racy();
|
||||||
let cur_cpu = preempt_guard.current_cpu();
|
|
||||||
|
|
||||||
let mut queue = CALL_QUEUES.get_on_cpu(cur_cpu).lock();
|
let mut queue = CALL_QUEUES.get_on_cpu(this_cpu_id).lock();
|
||||||
while let Some(f) = queue.pop_front() {
|
while let Some(f) = queue.pop_front() {
|
||||||
log::trace!(
|
log::trace!(
|
||||||
"Performing inter-processor call to {:#?} on CPU {:#?}",
|
"Performing inter-processor call to {:#?} on CPU {:#?}",
|
||||||
f,
|
f,
|
||||||
cur_cpu
|
this_cpu_id,
|
||||||
);
|
);
|
||||||
f();
|
f();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user