Halt the idle CPUs

This commit is contained in:
Zhang Junyang 2025-03-05 11:31:56 +08:00 committed by Tate, Hongliang Tian
parent 265bc25dd7
commit 30ec0be210
6 changed files with 48 additions and 12 deletions

View File

@ -39,10 +39,7 @@ use ostd::{
use process::Process;
use sched::SchedPolicy;
use crate::{
prelude::*,
thread::{kernel_thread::ThreadOptions, Thread},
};
use crate::{prelude::*, thread::kernel_thread::ThreadOptions};
extern crate alloc;
extern crate lru;
@ -112,8 +109,10 @@ fn ap_init() {
let cpu_id = preempt_guard.current_cpu();
drop(preempt_guard);
log::info!("Kernel idle thread for CPU #{} started.", cpu_id.as_usize());
loop {
Thread::yield_now();
crate::thread::Thread::yield_now();
ostd::cpu::sleep_for_interrupt();
}
}
let preempt_guard = ostd::task::disable_preempt();
@ -154,9 +153,8 @@ fn init_thread() {
.expect("Run init process failed.");
// Wait till initproc become zombie.
while !initproc.status().is_zombie() {
// We don't have preemptive scheduler now.
// The long running init thread should yield its own execution to allow other tasks to go on.
Thread::yield_now();
crate::thread::Thread::yield_now();
ostd::cpu::sleep_for_interrupt();
}
// TODO: exit via qemu isa debug device should not be the only way.

View File

@ -213,9 +213,18 @@ impl Scheduler for ClassScheduler {
return None;
}
// Preempt if the new task has a higher priority.
let should_preempt = rq
.current
.as_ref()
.is_none_or(|((_, rq_current_thread), _)| {
thread.sched_attr().policy() < rq_current_thread.sched_attr().policy()
});
thread.sched_attr().set_last_cpu(cpu);
rq.enqueue_entity((task, thread), Some(flags));
Some(cpu)
should_preempt.then_some(cpu)
}
fn local_mut_rq_with(&self, f: &mut dyn FnMut(&mut dyn LocalRunQueue)) {

View File

@ -4,3 +4,17 @@
pub mod context;
pub mod local;
/// Halts the CPU.
///
/// This function halts the CPU until the next interrupt is received. By
/// halting, the CPU might consume less power. Internally it is implemented
/// using the `wfi` instruction.
///
/// Since the function sleeps the CPU, it should not be used within an atomic
/// mode ([`crate::task::atomic_mode`]).
#[track_caller]
pub fn sleep_for_interrupt() {
crate::task::atomic_mode::might_sleep();
riscv::asm::wfi();
}

View File

@ -4,3 +4,16 @@
pub mod context;
pub mod local;
/// Halts the CPU.
///
/// This function halts the CPU until the next interrupt is received. By
/// halting, the CPU will enter the C-0 state and consume less power.
///
/// Since the function sleeps the CPU, it should not be used within an atomic
/// mode ([`crate::task::atomic_mode`]).
#[track_caller]
pub fn sleep_for_interrupt() {
crate::task::atomic_mode::might_sleep();
x86_64::instructions::hlt();
}

View File

@ -2,7 +2,7 @@
//! Tasks are the unit of code execution.
pub(crate) mod atomic_mode;
pub mod atomic_mode;
mod kernel_stack;
mod preempt;
mod processor;

View File

@ -12,7 +12,7 @@ use spin::Once;
use super::{preempt::cpu_local, processor, Task};
use crate::{
cpu::{CpuId, PinCurrentCpu},
cpu::{CpuId, CpuSet, PinCurrentCpu},
prelude::*,
task::disable_preempt,
timer,
@ -195,7 +195,9 @@ fn set_need_preempt(cpu_id: CpuId) {
if preempt_guard.current_cpu() == cpu_id {
cpu_local::set_need_preempt();
} else {
// TODO: Send IPIs to set remote CPU's `need_preempt`
crate::smp::inter_processor_call(&CpuSet::from(cpu_id), || {
cpu_local::set_need_preempt();
});
}
}