mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
重写调度模块 (#679)
## PR:重写调度模块 --- ### 完成的部分 - 实现cfs调度策略 - 搭建框架,后续功能可以迭代开发 - 目前能跑,未测试性能 ### 需要后续接力的部分 - 实现组内调度(task_group) - 实现跨核负载均衡(pelt算法) - 接入sysfs,实现参数动态调节(sched_stat等) - nice值以及priority等参数的设置及调优
This commit is contained in:
parent
e8eab1ac82
commit
f0c87a897f
@ -1,4 +1,5 @@
|
||||
use core::cell::RefCell;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use crate::arch::driver::tsc::TSCManager;
|
||||
use crate::arch::interrupt::TrapFrame;
|
||||
@ -12,7 +13,7 @@ use crate::exception::IrqNumber;
|
||||
|
||||
use crate::kdebug;
|
||||
use crate::mm::percpu::PerCpu;
|
||||
use crate::sched::core::sched_update_jiffies;
|
||||
use crate::process::ProcessManager;
|
||||
use crate::smp::core::smp_get_processor_id;
|
||||
use crate::smp::cpu::ProcessorId;
|
||||
use crate::time::clocksource::HZ;
|
||||
@ -66,9 +67,10 @@ impl IrqHandler for LocalApicTimerHandler {
|
||||
struct LocalApicTimerIrqFlowHandler;
|
||||
|
||||
impl IrqFlowHandler for LocalApicTimerIrqFlowHandler {
|
||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||
LocalApicTimer::handle_irq().ok();
|
||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, trap_frame: &mut TrapFrame) {
|
||||
LocalApicTimer::handle_irq(trap_frame).ok();
|
||||
CurrentApic.send_eoi();
|
||||
fence(Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,8 +276,9 @@ impl LocalApicTimer {
|
||||
return (res.ecx & (1 << 24)) != 0;
|
||||
}
|
||||
|
||||
pub(super) fn handle_irq() -> Result<IrqReturn, SystemError> {
|
||||
sched_update_jiffies();
|
||||
pub(super) fn handle_irq(trap_frame: &TrapFrame) -> Result<IrqReturn, SystemError> {
|
||||
// sched_update_jiffies();
|
||||
ProcessManager::update_process_times(trap_frame.is_from_user());
|
||||
return Ok(IrqReturn::Handled);
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use x86::msr::{
|
||||
rdmsr, wrmsr, IA32_APIC_BASE, IA32_X2APIC_APICID, IA32_X2APIC_EOI, IA32_X2APIC_SIVR,
|
||||
IA32_X2APIC_VERSION,
|
||||
@ -62,9 +64,12 @@ impl LocalAPIC for X2Apic {
|
||||
|
||||
/// 发送 EOI (End Of Interrupt)
|
||||
fn send_eoi(&self) {
|
||||
fence(Ordering::SeqCst);
|
||||
unsafe {
|
||||
wrmsr(IA32_X2APIC_EOI, 0);
|
||||
}
|
||||
|
||||
fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
/// 获取 x2APIC 版本
|
||||
|
@ -1,15 +1,13 @@
|
||||
use core::intrinsics::likely;
|
||||
|
||||
use crate::{
|
||||
arch::{
|
||||
driver::apic::{apic_timer::APIC_TIMER_IRQ_NUM, CurrentApic, LocalAPIC},
|
||||
sched::sched,
|
||||
},
|
||||
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;
|
||||
@ -47,6 +45,6 @@ unsafe extern "C" fn x86_64_do_irq(trap_frame: &mut TrapFrame, vector: u32) {
|
||||
if (current_pcb_flags().contains(ProcessFlags::NEED_SCHEDULE))
|
||||
&& vector == APIC_TIMER_IRQ_NUM.data()
|
||||
{
|
||||
sched();
|
||||
__schedule(SchedMode::SM_PREEMPT);
|
||||
}
|
||||
}
|
||||
|
@ -254,12 +254,12 @@ impl IrqFlowHandler for X86_64IpiIrqFlowHandler {
|
||||
}
|
||||
IPI_NUM_FLUSH_TLB => {
|
||||
FlushTLBIpiHandler.handle(irq, None, None).ok();
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
_ => {
|
||||
kerror!("Unknown IPI: {}", irq.data());
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
||||
CurrentApic.send_eoi();
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ use crate::{
|
||||
fpu::FpState,
|
||||
interrupt::TrapFrame,
|
||||
process::table::{USER_CS, USER_DS},
|
||||
sched::sched,
|
||||
CurrentIrqArch, MMArch,
|
||||
},
|
||||
exception::InterruptArch,
|
||||
@ -18,6 +17,7 @@ use crate::{
|
||||
kerror,
|
||||
mm::MemoryManagementArch,
|
||||
process::ProcessManager,
|
||||
sched::{schedule, SchedMode},
|
||||
syscall::{user_access::UserBufferWriter, Syscall},
|
||||
};
|
||||
|
||||
@ -715,7 +715,7 @@ fn sig_stop(sig: Signal) {
|
||||
);
|
||||
});
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
// TODO 暂停进程
|
||||
}
|
||||
/// 信号默认处理函数——继续进程
|
||||
|
@ -1,11 +1,21 @@
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use crate::{arch::CurrentIrqArch, exception::InterruptArch, kBUG, process::ProcessManager};
|
||||
use crate::{
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
kBUG,
|
||||
process::{ProcessFlags, ProcessManager},
|
||||
sched::{SchedMode, __schedule},
|
||||
};
|
||||
|
||||
impl ProcessManager {
|
||||
/// 每个核的idle进程
|
||||
pub fn arch_idle_func() -> ! {
|
||||
loop {
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
if pcb.flags().contains(ProcessFlags::NEED_SCHEDULE) {
|
||||
__schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
if CurrentIrqArch::is_irq_enabled() {
|
||||
unsafe {
|
||||
x86::halt();
|
||||
|
@ -563,6 +563,8 @@ pub unsafe fn arch_switch_to_user(path: String, argv: Vec<String>, envp: Vec<Str
|
||||
current_pcb.flags().remove(ProcessFlags::KTHREAD);
|
||||
current_pcb.worker_private().take();
|
||||
|
||||
*current_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::CFS;
|
||||
|
||||
let mut trap_frame = TrapFrame::new();
|
||||
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
@ -591,6 +593,7 @@ unsafe extern "sysv64" fn ready_to_switch_to_user(
|
||||
new_rip: usize,
|
||||
) -> ! {
|
||||
*(trapframe_vaddr as *mut TrapFrame) = trap_frame;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
asm!(
|
||||
"swapgs",
|
||||
"mov rsp, {trapframe_vaddr}",
|
||||
@ -601,3 +604,35 @@ unsafe extern "sysv64" fn ready_to_switch_to_user(
|
||||
);
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
// bitflags! {
|
||||
// pub struct ProcessThreadFlags: u32 {
|
||||
// /*
|
||||
// * thread information flags
|
||||
// * - these are process state flags that various assembly files
|
||||
// * may need to access
|
||||
// */
|
||||
// const TIF_NOTIFY_RESUME = 1 << 1; /* callback before returning to user */
|
||||
// const TIF_SIGPENDING = 1 << 2; /* signal pending */
|
||||
// const TIF_NEED_RESCHED = 1 << 3; /* rescheduling necessary */
|
||||
// const TIF_SINGLESTEP = 1 << 4; /* reenable singlestep on user return*/
|
||||
// const TIF_SSBD = 1 << 5; /* Speculative store bypass disable */
|
||||
// const TIF_SPEC_IB = 1 << 9; /* Indirect branch speculation mitigation */
|
||||
// const TIF_SPEC_L1D_FLUSH = 1 << 10; /* Flush L1D on mm switches (processes) */
|
||||
// const TIF_USER_RETURN_NOTIFY = 1 << 11; /* notify kernel of userspace return */
|
||||
// const TIF_UPROBE = 1 << 12; /* breakpointed or singlestepping */
|
||||
// const TIF_PATCH_PENDING = 1 << 13; /* pending live patching update */
|
||||
// const TIF_NEED_FPU_LOAD = 1 << 14; /* load FPU on return to userspace */
|
||||
// const TIF_NOCPUID = 1 << 15; /* CPUID is not accessible in userland */
|
||||
// const TIF_NOTSC = 1 << 16; /* TSC is not accessible in userland */
|
||||
// const TIF_NOTIFY_SIGNAL = 1 << 17; /* signal notifications exist */
|
||||
// const TIF_MEMDIE = 1 << 20; /* is terminating due to OOM killer */
|
||||
// const TIF_POLLING_NRFLAG = 1 << 21; /* idle is polling for TIF_NEED_RESCHED */
|
||||
// const TIF_IO_BITMAP = 1 << 22; /* uses I/O bitmap */
|
||||
// const TIF_SPEC_FORCE_UPDATE = 1 << 23; /* Force speculation MSR update in context switch */
|
||||
// const TIF_FORCED_TF = 1 << 24; /* true if TF in eflags artificially */
|
||||
// const TIF_BLOCKSTEP = 1 << 25; /* set when we want DEBUGCTLMSR_BTF */
|
||||
// const TIF_LAZY_MMU_UPDATES = 1 << 27; /* task is updating the mmu lazily */
|
||||
// const TIF_ADDR32 = 1 << 29; /* 32-bit address space on 64 bits */
|
||||
// }
|
||||
// }
|
||||
|
@ -1,20 +1,19 @@
|
||||
use core::hint::spin_loop;
|
||||
|
||||
use crate::{
|
||||
exception::InterruptArch, include::bindings::bindings::enter_syscall_int, sched::SchedArch,
|
||||
smp::core::smp_get_processor_id, syscall::SYS_SCHED,
|
||||
};
|
||||
use crate::{exception::InterruptArch, sched::SchedArch, smp::core::smp_get_processor_id};
|
||||
|
||||
use super::{driver::apic::apic_timer::apic_timer_init, CurrentIrqArch};
|
||||
|
||||
/// @brief 若内核代码不处在中断上下文中,那么将可以使用本函数,发起一个sys_sched系统调用,然后运行调度器。
|
||||
/// 由于只能在中断上下文中进行进程切换,因此需要发起一个系统调用SYS_SCHED。
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sched() {
|
||||
unsafe {
|
||||
enter_syscall_int(SYS_SCHED as u64, 0, 0, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
// /// @brief 若内核代码不处在中断上下文中,那么将可以使用本函数,发起一个sys_sched系统调用,然后运行调度器。
|
||||
// /// 由于只能在中断上下文中进行进程切换,因此需要发起一个系统调用SYS_SCHED。
|
||||
// #[no_mangle]
|
||||
// pub extern "C" fn sched() {
|
||||
// let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
// __schedule(SchedMode::SM_NONE);
|
||||
// // unsafe {
|
||||
// // enter_syscall_int(SYS_SCHED as u64, 0, 0, 0, 0, 0, 0);
|
||||
// // }
|
||||
// }
|
||||
|
||||
static mut BSP_INIT_OK: bool = false;
|
||||
|
||||
|
@ -4,12 +4,14 @@ use alloc::{string::ToString, sync::Arc};
|
||||
use kdepends::thingbuf::StaticThingBuf;
|
||||
|
||||
use crate::{
|
||||
arch::sched::sched,
|
||||
arch::CurrentIrqArch,
|
||||
driver::tty::virtual_terminal::virtual_console::CURRENT_VCNUM,
|
||||
exception::InterruptArch,
|
||||
process::{
|
||||
kthread::{KernelThreadClosure, KernelThreadMechanism},
|
||||
ProcessControlBlock, ProcessFlags,
|
||||
ProcessControlBlock, ProcessManager,
|
||||
},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::tty_port::current_tty_port;
|
||||
@ -35,15 +37,9 @@ fn tty_refresh_thread() -> i32 {
|
||||
loop {
|
||||
if KEYBUF.is_empty() {
|
||||
// 如果缓冲区为空,就休眠
|
||||
unsafe {
|
||||
TTY_REFRESH_THREAD
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.flags()
|
||||
.insert(ProcessFlags::NEED_SCHEDULE)
|
||||
};
|
||||
|
||||
sched();
|
||||
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
ProcessManager::mark_sleep(true).expect("TTY_REFRESH_THREAD can not mark sleep");
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
let to_dequeue = core::cmp::min(KEYBUF.len(), TO_DEQUEUE_MAX);
|
||||
@ -69,4 +65,5 @@ pub fn send_to_tty_refresh_thread(data: &[u8]) {
|
||||
for item in data {
|
||||
KEYBUF.push(*item).ok();
|
||||
}
|
||||
let _ = ProcessManager::wakeup(unsafe { TTY_REFRESH_THREAD.as_ref().unwrap() });
|
||||
}
|
||||
|
@ -1,9 +1,13 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::driver::apic::{CurrentApic, LocalAPIC};
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, MMArch},
|
||||
arch::MMArch,
|
||||
mm::MemoryManagementArch,
|
||||
sched::{SchedMode, __schedule},
|
||||
smp::cpu::ProcessorId,
|
||||
};
|
||||
|
||||
@ -47,7 +51,11 @@ impl IrqHandler for KickCpuIpiHandler {
|
||||
_static_data: Option<&dyn IrqHandlerData>,
|
||||
_dynamic_data: Option<Arc<dyn IrqHandlerData>>,
|
||||
) -> Result<IrqReturn, SystemError> {
|
||||
sched();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
CurrentApic.send_eoi();
|
||||
|
||||
// 被其他cpu kick时应该是抢占调度
|
||||
__schedule(SchedMode::SM_PREEMPT);
|
||||
Ok(IrqReturn::Handled)
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use core::{
|
||||
intrinsics::unlikely,
|
||||
mem::{self, MaybeUninit},
|
||||
ptr::null_mut,
|
||||
sync::atomic::{compiler_fence, AtomicI16, Ordering},
|
||||
sync::atomic::{compiler_fence, fence, AtomicI16, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
@ -17,6 +17,7 @@ use crate::{
|
||||
libs::rwlock::RwLock,
|
||||
mm::percpu::{PerCpu, PerCpuVar},
|
||||
process::ProcessManager,
|
||||
sched::cputime::IrqTime,
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
time::timer::clock,
|
||||
};
|
||||
@ -286,6 +287,11 @@ impl<'a> Drop for RunningCountGuard<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
pub fn do_softirq() {
|
||||
fence(Ordering::SeqCst);
|
||||
IrqTime::irqtime_start();
|
||||
softirq_vectors().do_softirq();
|
||||
IrqTime::irqtime_account_irq(ProcessManager::current_pcb());
|
||||
fence(Ordering::SeqCst);
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ impl ProcFSInode {
|
||||
.map(|cpu| cpu.data() as i32)
|
||||
.unwrap_or(-1);
|
||||
|
||||
let priority = sched_info_guard.priority();
|
||||
let vrtime = sched_info_guard.virtual_runtime();
|
||||
let priority = sched_info_guard.policy();
|
||||
let vrtime = sched_info_guard.sched_entity.vruntime;
|
||||
|
||||
pdata.append(&mut format!("\nState:\t{:?}", state).as_bytes().to_owned());
|
||||
pdata.append(
|
||||
@ -183,11 +183,7 @@ impl ProcFSInode {
|
||||
.to_owned(),
|
||||
);
|
||||
pdata.append(&mut format!("\ncpu_id:\t{}", cpu_id).as_bytes().to_owned());
|
||||
pdata.append(
|
||||
&mut format!("\npriority:\t{}", priority.data())
|
||||
.as_bytes()
|
||||
.to_owned(),
|
||||
);
|
||||
pdata.append(&mut format!("\npriority:\t{:?}", priority).as_bytes().to_owned());
|
||||
pdata.append(
|
||||
&mut format!("\npreempt:\t{}", pcb.preempt_count())
|
||||
.as_bytes()
|
||||
|
@ -24,6 +24,5 @@
|
||||
#include <mm/mmio.h>
|
||||
#include <mm/slab.h>
|
||||
#include <process/process.h>
|
||||
#include <sched/sched.h>
|
||||
#include <time/sleep.h>
|
||||
#include <common/errno.h>
|
||||
|
@ -17,7 +17,7 @@ use crate::{
|
||||
},
|
||||
mm::init::mm_init,
|
||||
process::{kthread::kthread_init, process_init, ProcessManager},
|
||||
sched::{core::sched_init, SchedArch},
|
||||
sched::SchedArch,
|
||||
smp::{early_smp_init, SMPArch},
|
||||
syscall::Syscall,
|
||||
time::{
|
||||
@ -59,13 +59,14 @@ fn do_start_kernel() {
|
||||
unsafe {
|
||||
acpi_init()
|
||||
};
|
||||
crate::sched::sched_init();
|
||||
process_init();
|
||||
early_smp_init().expect("early smp init failed");
|
||||
irq_init().expect("irq init failed");
|
||||
setup_arch().expect("setup_arch failed");
|
||||
CurrentSMPArch::prepare_cpus().expect("prepare_cpus failed");
|
||||
|
||||
sched_init();
|
||||
// sched_init();
|
||||
softirq_init().expect("softirq init failed");
|
||||
Syscall::init().expect("syscall init failed");
|
||||
timekeeping_init();
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
filesystem::vfs::{
|
||||
core::generate_inode_id, file::FileMode, syscall::ModeType, FilePrivateData, FileSystem,
|
||||
@ -11,6 +11,7 @@ use crate::{
|
||||
},
|
||||
net::event_poll::{EPollEventType, EPollItem, EventPoll},
|
||||
process::ProcessState,
|
||||
sched::{schedule, SchedMode},
|
||||
time::TimeSpec,
|
||||
};
|
||||
|
||||
@ -197,7 +198,7 @@ impl IndexNode for LockedPipeInode {
|
||||
self.read_wait_queue.sleep_without_schedule();
|
||||
drop(irq_guard);
|
||||
}
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
inode = self.inner.lock();
|
||||
}
|
||||
|
||||
@ -354,7 +355,7 @@ impl IndexNode for LockedPipeInode {
|
||||
self.write_wait_queue.sleep_without_schedule();
|
||||
drop(irq_guard);
|
||||
}
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
inode = self.inner.lock();
|
||||
}
|
||||
|
||||
|
@ -8,11 +8,12 @@ use hashbrown::HashMap;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch, MMArch},
|
||||
arch::{CurrentIrqArch, MMArch},
|
||||
exception::InterruptArch,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
mm::{ucontext::AddressSpace, MemoryManagementArch, VirtAddr},
|
||||
process::{ProcessControlBlock, ProcessManager},
|
||||
sched::{schedule, SchedMode},
|
||||
syscall::user_access::UserBufferReader,
|
||||
time::{
|
||||
timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
|
||||
@ -287,7 +288,7 @@ impl Futex {
|
||||
})?;
|
||||
drop(futex_map_guard);
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
|
||||
// 被唤醒后的检查
|
||||
let mut futex_map_guard = FutexData::futex_map();
|
||||
|
@ -7,10 +7,11 @@ use alloc::{collections::LinkedList, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
libs::spinlock::SpinLockGuard,
|
||||
process::{Pid, ProcessControlBlock, ProcessManager},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::spinlock::SpinLock;
|
||||
@ -106,7 +107,7 @@ impl<T> Mutex<T> {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
ProcessManager::mark_sleep(true).ok();
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 放锁。
|
||||
|
@ -32,7 +32,7 @@ enum Color {
|
||||
}
|
||||
|
||||
/*****************RBTreeNode***************************/
|
||||
struct RBTreeNode<K: Ord, V> {
|
||||
struct RBTreeNode<K: Ord + Debug, V: Debug> {
|
||||
color: Color,
|
||||
left: NodePtr<K, V>,
|
||||
right: NodePtr<K, V>,
|
||||
@ -41,7 +41,7 @@ struct RBTreeNode<K: Ord, V> {
|
||||
value: V,
|
||||
}
|
||||
|
||||
impl<K: Ord, V> RBTreeNode<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> RBTreeNode<K, V> {
|
||||
#[inline]
|
||||
fn pair(self) -> (K, V) {
|
||||
(self.key, self.value)
|
||||
@ -60,37 +60,37 @@ where
|
||||
|
||||
/*****************NodePtr***************************/
|
||||
#[derive(Debug)]
|
||||
struct NodePtr<K: Ord, V>(*mut RBTreeNode<K, V>);
|
||||
struct NodePtr<K: Ord + Debug, V: Debug>(*mut RBTreeNode<K, V>);
|
||||
|
||||
impl<K: Ord, V> Clone for NodePtr<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Clone for NodePtr<K, V> {
|
||||
fn clone(&self) -> NodePtr<K, V> {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> Copy for NodePtr<K, V> {}
|
||||
impl<K: Ord + Debug, V: Debug> Copy for NodePtr<K, V> {}
|
||||
|
||||
impl<K: Ord, V> Ord for NodePtr<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Ord for NodePtr<K, V> {
|
||||
fn cmp(&self, other: &NodePtr<K, V>) -> Ordering {
|
||||
unsafe { (*self.0).key.cmp(&(*other.0).key) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> PartialOrd for NodePtr<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> PartialOrd for NodePtr<K, V> {
|
||||
fn partial_cmp(&self, other: &NodePtr<K, V>) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> PartialEq for NodePtr<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> PartialEq for NodePtr<K, V> {
|
||||
fn eq(&self, other: &NodePtr<K, V>) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> Eq for NodePtr<K, V> {}
|
||||
impl<K: Ord + Debug, V: Debug> Eq for NodePtr<K, V> {}
|
||||
|
||||
impl<K: Ord, V> NodePtr<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> NodePtr<K, V> {
|
||||
fn new(k: K, v: V) -> NodePtr<K, V> {
|
||||
let node = RBTreeNode {
|
||||
color: Color::Black,
|
||||
@ -270,7 +270,7 @@ impl<K: Ord, V> NodePtr<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord + Clone, V: Clone> NodePtr<K, V> {
|
||||
impl<K: Ord + Clone + Debug, V: Clone + Debug> NodePtr<K, V> {
|
||||
unsafe fn deep_clone(&self) -> NodePtr<K, V> {
|
||||
let mut node = NodePtr::new((*self.0).key.clone(), (*self.0).value.clone());
|
||||
if !self.left().is_null() {
|
||||
@ -339,16 +339,16 @@ impl<K: Ord + Clone, V: Clone> NodePtr<K, V> {
|
||||
/// .iter().cloned().collect();
|
||||
/// // use the values stored in rbtree
|
||||
/// ```
|
||||
pub struct RBTree<K: Ord, V> {
|
||||
pub struct RBTree<K: Ord + Debug, V: Debug> {
|
||||
root: NodePtr<K, V>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
unsafe impl<K: Ord, V> Send for RBTree<K, V> {}
|
||||
unsafe impl<K: Ord, V> Sync for RBTree<K, V> {}
|
||||
unsafe impl<K: Ord + Debug, V: Debug> Send for RBTree<K, V> {}
|
||||
unsafe impl<K: Ord + Debug, V: Debug> Sync for RBTree<K, V> {}
|
||||
|
||||
// Drop all owned pointers if the tree is dropped
|
||||
impl<K: Ord, V> Drop for RBTree<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Drop for RBTree<K, V> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
self.clear();
|
||||
@ -356,7 +356,7 @@ impl<K: Ord, V> Drop for RBTree<K, V> {
|
||||
}
|
||||
|
||||
/// If key and value are both impl Clone, we can call clone to get a copy.
|
||||
impl<K: Ord + Clone, V: Clone> Clone for RBTree<K, V> {
|
||||
impl<K: Ord + Clone + Debug, V: Clone + Debug> Clone for RBTree<K, V> {
|
||||
fn clone(&self) -> RBTree<K, V> {
|
||||
unsafe {
|
||||
let mut new = RBTree::new();
|
||||
@ -417,8 +417,8 @@ impl<K: Ord + Debug, V: Debug> RBTree<K, V> {
|
||||
/// all key be same, but it has multi key, if has multi key, it perhaps no correct
|
||||
impl<K, V> PartialEq for RBTree<K, V>
|
||||
where
|
||||
K: Eq + Ord,
|
||||
V: PartialEq,
|
||||
K: Eq + Ord + Debug,
|
||||
V: PartialEq + Debug,
|
||||
{
|
||||
fn eq(&self, other: &RBTree<K, V>) -> bool {
|
||||
if self.len() != other.len() {
|
||||
@ -430,17 +430,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> Eq for RBTree<K, V>
|
||||
where
|
||||
K: Eq + Ord,
|
||||
V: Eq,
|
||||
{
|
||||
}
|
||||
impl<K: Eq + Ord + Debug, V: Eq + Debug> Eq for RBTree<K, V> {}
|
||||
|
||||
impl<'a, K, V> Index<&'a K> for RBTree<K, V>
|
||||
where
|
||||
K: Ord,
|
||||
{
|
||||
impl<'a, K: Ord + Debug, V: Debug> Index<&'a K> for RBTree<K, V> {
|
||||
type Output = V;
|
||||
|
||||
#[inline]
|
||||
@ -449,7 +441,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> FromIterator<(K, V)> for RBTree<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> FromIterator<(K, V)> for RBTree<K, V> {
|
||||
fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> RBTree<K, V> {
|
||||
let mut tree = RBTree::new();
|
||||
tree.extend(iter);
|
||||
@ -458,7 +450,7 @@ impl<K: Ord, V> FromIterator<(K, V)> for RBTree<K, V> {
|
||||
}
|
||||
|
||||
/// RBTree into iter
|
||||
impl<K: Ord, V> Extend<(K, V)> for RBTree<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Extend<(K, V)> for RBTree<K, V> {
|
||||
fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
|
||||
let iter = iter.into_iter();
|
||||
for (k, v) in iter {
|
||||
@ -479,11 +471,11 @@ impl<K: Ord, V> Extend<(K, V)> for RBTree<K, V> {
|
||||
/// let key_vec: Vec<_> = m.keys().cloned().collect();
|
||||
/// assert_eq!(vec, key_vec);
|
||||
/// ```
|
||||
pub struct Keys<'a, K: Ord + 'a, V: 'a> {
|
||||
pub struct Keys<'a, K: Ord + Debug + 'a, V: Debug + 'a> {
|
||||
inner: Iter<'a, K, V>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Clone for Keys<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Clone for Keys<'a, K, V> {
|
||||
fn clone(&self) -> Keys<'a, K, V> {
|
||||
Keys {
|
||||
inner: self.inner.clone(),
|
||||
@ -491,13 +483,13 @@ impl<'a, K: Ord, V> Clone for Keys<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + Debug, V> fmt::Debug for Keys<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> fmt::Debug for Keys<'a, K, V> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_list().entries(self.clone()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Iterator for Keys<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Iterator for Keys<'a, K, V> {
|
||||
type Item = &'a K;
|
||||
|
||||
#[inline]
|
||||
@ -524,11 +516,11 @@ impl<'a, K: Ord, V> Iterator for Keys<'a, K, V> {
|
||||
/// let key_vec: Vec<_> = m.values().cloned().collect();
|
||||
/// assert_eq!(vec, key_vec);
|
||||
/// ```
|
||||
pub struct Values<'a, K: 'a + Ord, V: 'a> {
|
||||
pub struct Values<'a, K: Ord + Debug, V: Debug> {
|
||||
inner: Iter<'a, K, V>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Clone for Values<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Clone for Values<'a, K, V> {
|
||||
fn clone(&self) -> Values<'a, K, V> {
|
||||
Values {
|
||||
inner: self.inner.clone(),
|
||||
@ -542,7 +534,7 @@ impl<'a, K: Ord + Debug, V: Debug> fmt::Debug for Values<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Iterator for Values<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Iterator for Values<'a, K, V> {
|
||||
type Item = &'a V;
|
||||
|
||||
#[inline]
|
||||
@ -572,11 +564,11 @@ impl<'a, K: Ord, V> Iterator for Values<'a, K, V> {
|
||||
/// assert_eq!(m.get(&i).unwrap(), &(i * 2));
|
||||
/// }
|
||||
/// ```
|
||||
pub struct ValuesMut<'a, K: 'a + Ord, V: 'a> {
|
||||
pub struct ValuesMut<'a, K: Ord + Debug + 'a, V: Debug + 'a> {
|
||||
inner: IterMut<'a, K, V>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Clone for ValuesMut<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Clone for ValuesMut<'a, K, V> {
|
||||
fn clone(&self) -> ValuesMut<'a, K, V> {
|
||||
ValuesMut {
|
||||
inner: self.inner.clone(),
|
||||
@ -590,7 +582,7 @@ impl<'a, K: Ord + Debug, V: Debug> fmt::Debug for ValuesMut<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord, V> Iterator for ValuesMut<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug, V: Debug> Iterator for ValuesMut<'a, K, V> {
|
||||
type Item = &'a mut V;
|
||||
|
||||
#[inline]
|
||||
@ -605,21 +597,21 @@ impl<'a, K: Ord, V> Iterator for ValuesMut<'a, K, V> {
|
||||
}
|
||||
|
||||
/// Convert RBTree to iter, move out the tree.
|
||||
pub struct IntoIter<K: Ord, V> {
|
||||
pub struct IntoIter<K: Ord + Debug, V: Debug> {
|
||||
head: NodePtr<K, V>,
|
||||
tail: NodePtr<K, V>,
|
||||
len: usize,
|
||||
}
|
||||
|
||||
// Drop all owned pointers if the collection is dropped
|
||||
impl<K: Ord, V> Drop for IntoIter<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Drop for IntoIter<K, V> {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
for (_, _) in self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> Iterator for IntoIter<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> Iterator for IntoIter<K, V> {
|
||||
type Item = (K, V);
|
||||
|
||||
fn next(&mut self) -> Option<(K, V)> {
|
||||
@ -648,7 +640,7 @@ impl<K: Ord, V> Iterator for IntoIter<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> DoubleEndedIterator for IntoIter<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> DoubleEndedIterator for IntoIter<K, V> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(K, V)> {
|
||||
if self.len == 0 {
|
||||
@ -684,14 +676,14 @@ impl<K: Ord, V> DoubleEndedIterator for IntoIter<K, V> {
|
||||
/// }
|
||||
/// assert_eq!(observed, 0xFFFF_FFFF);
|
||||
/// ```
|
||||
pub struct Iter<'a, K: Ord + 'a, V: 'a> {
|
||||
pub struct Iter<'a, K: Ord + Debug + 'a, V: Debug + 'a> {
|
||||
head: NodePtr<K, V>,
|
||||
tail: NodePtr<K, V>,
|
||||
len: usize,
|
||||
_marker: marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> Clone for Iter<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> Clone for Iter<'a, K, V> {
|
||||
fn clone(&self) -> Iter<'a, K, V> {
|
||||
Iter {
|
||||
head: self.head,
|
||||
@ -702,7 +694,7 @@ impl<'a, K: Ord + 'a, V: 'a> Clone for Iter<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> Iterator for Iter<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
@ -725,7 +717,7 @@ impl<'a, K: Ord + 'a, V: 'a> Iterator for Iter<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
// kdebug!("len = {:?}", self.len);
|
||||
@ -733,10 +725,6 @@ impl<'a, K: Ord + 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
return None;
|
||||
}
|
||||
|
||||
if self.tail == self.head {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (k, v) = unsafe { (&(*self.tail.0).key, &(*self.tail.0).value) };
|
||||
self.tail = self.tail.prev();
|
||||
self.len -= 1;
|
||||
@ -760,14 +748,14 @@ impl<'a, K: Ord + 'a, V: 'a> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
/// assert_eq!(m.get(&i).unwrap(), &(i * 2));
|
||||
/// }
|
||||
/// ```
|
||||
pub struct IterMut<'a, K: Ord + 'a, V: 'a> {
|
||||
pub struct IterMut<'a, K: Ord + Debug + 'a, V: Debug + 'a> {
|
||||
head: NodePtr<K, V>,
|
||||
tail: NodePtr<K, V>,
|
||||
len: usize,
|
||||
_marker: marker::PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> Clone for IterMut<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> Clone for IterMut<'a, K, V> {
|
||||
fn clone(&self) -> IterMut<'a, K, V> {
|
||||
IterMut {
|
||||
head: self.head,
|
||||
@ -778,7 +766,7 @@ impl<'a, K: Ord + 'a, V: 'a> Clone for IterMut<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> Iterator for IterMut<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
@ -801,7 +789,7 @@ impl<'a, K: Ord + 'a, V: 'a> Iterator for IterMut<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K: Ord + 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
impl<'a, K: Ord + Debug + 'a, V: Debug + 'a> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
if self.len == 0 {
|
||||
@ -819,7 +807,7 @@ impl<'a, K: Ord + 'a, V: 'a> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> IntoIterator for RBTree<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> IntoIterator for RBTree<K, V> {
|
||||
type Item = (K, V);
|
||||
type IntoIter = IntoIter<K, V>;
|
||||
|
||||
@ -843,7 +831,7 @@ impl<K: Ord, V> IntoIterator for RBTree<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Ord, V> RBTree<K, V> {
|
||||
impl<K: Ord + Debug, V: Debug> RBTree<K, V> {
|
||||
/// Creates an empty `RBTree`.
|
||||
pub fn new() -> RBTree<K, V> {
|
||||
RBTree {
|
||||
@ -1200,17 +1188,31 @@ impl<K: Ord, V> RBTree<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
/// clear all red back tree elements.
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use rbtree::RBTree;
|
||||
/// let mut m = RBTree::new();
|
||||
/// for i in 0..6 {
|
||||
/// m.insert(i, i);
|
||||
/// }
|
||||
/// assert_eq!(m.len(), 6);
|
||||
/// m.clear();
|
||||
/// assert_eq!(m.len(), 0);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
let root = self.root;
|
||||
self.root = NodePtr::null();
|
||||
self.clear_recurse(root);
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
/// Empties the `RBTree` without freeing objects in it.
|
||||
#[inline]
|
||||
fn fast_clear(&mut self) {
|
||||
self.root = NodePtr::null();
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -1814,4 +1816,19 @@ mod tests {
|
||||
assert_eq!(a[&2], "two");
|
||||
assert_eq!(a[&3], "three");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rev_iter() {
|
||||
let mut a = RBTree::new();
|
||||
a.insert(1, 1);
|
||||
a.insert(2, 2);
|
||||
a.insert(3, 3);
|
||||
|
||||
assert_eq!(a.len(), 3);
|
||||
let mut cache = vec![];
|
||||
for e in a.iter().rev() {
|
||||
cache.push(e.0.clone());
|
||||
}
|
||||
assert_eq!(&cache, &vec![3, 2, 1]);
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +167,10 @@ impl<T> SpinLock<T> {
|
||||
self.lock.store(false, Ordering::SeqCst);
|
||||
ProcessManager::preempt_enable();
|
||||
}
|
||||
|
||||
pub fn is_locked(&self) -> bool {
|
||||
self.lock.load(Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
/// 实现Deref trait,支持通过获取SpinLockGuard来获取临界区数据的不可变引用
|
||||
|
@ -4,10 +4,11 @@ use core::intrinsics::unlikely;
|
||||
use alloc::{collections::LinkedList, sync::Arc, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
kerror,
|
||||
process::{ProcessControlBlock, ProcessManager, ProcessState},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -40,7 +41,7 @@ impl WaitQueue {
|
||||
});
|
||||
guard.wait_list.push_back(ProcessManager::current_pcb());
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待,并且,在释放waitqueue的锁之前,执行f函数闭包
|
||||
@ -59,7 +60,7 @@ impl WaitQueue {
|
||||
f();
|
||||
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待. 但是,在释放waitqueue的锁之后,不会调用调度函数。
|
||||
@ -110,7 +111,7 @@ impl WaitQueue {
|
||||
drop(irq_guard);
|
||||
guard.wait_list.push_back(ProcessManager::current_pcb());
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
|
||||
@ -126,7 +127,7 @@ impl WaitQueue {
|
||||
guard.wait_list.push_back(ProcessManager::current_pcb());
|
||||
drop(to_unlock);
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待,并且,允许被信号打断。
|
||||
@ -142,7 +143,7 @@ impl WaitQueue {
|
||||
guard.wait_list.push_back(ProcessManager::current_pcb());
|
||||
drop(to_unlock);
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
|
||||
@ -158,7 +159,7 @@ impl WaitQueue {
|
||||
guard.wait_list.push_back(ProcessManager::current_pcb());
|
||||
drop(to_unlock);
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 让当前进程在等待队列上进行等待,并且,不允许被信号打断。
|
||||
@ -176,7 +177,7 @@ impl WaitQueue {
|
||||
|
||||
drop(to_unlock);
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// @brief 唤醒在队列中等待的第一个进程。
|
||||
@ -306,7 +307,7 @@ impl EventWaitQueue {
|
||||
});
|
||||
guard.push((events, ProcessManager::current_pcb()));
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
pub unsafe fn sleep_without_schedule(&self, events: u64) {
|
||||
@ -330,7 +331,7 @@ impl EventWaitQueue {
|
||||
guard.push((events, ProcessManager::current_pcb()));
|
||||
drop(to_unlock);
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
/// ### 唤醒该队列上等待events的进程
|
||||
|
@ -11,7 +11,6 @@ use alloc::{
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::sched::sched,
|
||||
filesystem::vfs::{
|
||||
file::{File, FileMode},
|
||||
FilePrivateData, IndexNode, Metadata,
|
||||
@ -24,6 +23,7 @@ use crate::{
|
||||
wait_queue::WaitQueue,
|
||||
},
|
||||
process::ProcessManager,
|
||||
sched::{schedule, SchedMode},
|
||||
time::{
|
||||
timer::{next_n_us_timer_jiffies, Timer, WakeUpHelper},
|
||||
TimeSpec,
|
||||
@ -489,7 +489,7 @@ impl EventPoll {
|
||||
let guard = epoll.0.lock_irqsave();
|
||||
unsafe { guard.epoll_wq.sleep_without_schedule() };
|
||||
drop(guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
// 被唤醒后,检查是否有事件可读
|
||||
available = epoll.0.lock_irqsave().ep_events_available();
|
||||
if let Some(timer) = timer {
|
||||
|
@ -15,7 +15,7 @@ use smoltcp::{
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{rand::rand, sched::sched},
|
||||
arch::rand::rand,
|
||||
filesystem::vfs::{
|
||||
file::FileMode, syscall::ModeType, FilePrivateData, FileSystem, FileType, IndexNode,
|
||||
Metadata,
|
||||
@ -25,6 +25,7 @@ use crate::{
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
wait_queue::EventWaitQueue,
|
||||
},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use self::{
|
||||
@ -337,8 +338,9 @@ impl IndexNode for SocketInode {
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
drop(data);
|
||||
self.0.lock_no_preempt().read(&mut buf[0..len]).0
|
||||
}
|
||||
|
||||
@ -347,8 +349,9 @@ impl IndexNode for SocketInode {
|
||||
_offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
_data: SpinLockGuard<FilePrivateData>,
|
||||
data: SpinLockGuard<FilePrivateData>,
|
||||
) -> Result<usize, SystemError> {
|
||||
drop(data);
|
||||
self.0.lock_no_preempt().write(&buf[0..len], None)
|
||||
}
|
||||
|
||||
@ -417,7 +420,7 @@ impl SocketHandleItem {
|
||||
.sleep_without_schedule(events)
|
||||
};
|
||||
drop(handle_map_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
pub fn shutdown_type(&self) -> ShutdownType {
|
||||
|
@ -6,10 +6,10 @@ use system_error::SystemError;
|
||||
use crate::{
|
||||
arch::{
|
||||
ipc::signal::{SigChildCode, Signal},
|
||||
sched::sched,
|
||||
CurrentIrqArch,
|
||||
},
|
||||
exception::InterruptArch,
|
||||
sched::{schedule, SchedMode},
|
||||
syscall::user_access::UserBufferWriter,
|
||||
};
|
||||
|
||||
@ -164,7 +164,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
|
||||
}
|
||||
}
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
} else {
|
||||
// todo: 对于pgid的处理
|
||||
kwarn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
|
||||
|
@ -10,6 +10,8 @@ use crate::{
|
||||
libs::rwlock::RwLock,
|
||||
mm::VirtAddr,
|
||||
process::ProcessFlags,
|
||||
sched::{sched_cgroup_fork, sched_fork},
|
||||
smp::core::smp_get_processor_id,
|
||||
syscall::user_access::UserBufferWriter,
|
||||
};
|
||||
|
||||
@ -185,6 +187,8 @@ impl ProcessManager {
|
||||
)
|
||||
});
|
||||
|
||||
pcb.sched_info().set_on_cpu(Some(smp_get_processor_id()));
|
||||
|
||||
ProcessManager::wakeup(&pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to wakeup new process, pid: [{:?}]. Error: {:?}",
|
||||
@ -388,6 +392,13 @@ impl ProcessManager {
|
||||
writer.copy_one_to_user(&(pcb.pid().0 as i32), 0)?;
|
||||
}
|
||||
|
||||
sched_fork(pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"fork: Failed to set sched info from current process, current pid: [{:?}], new pid: [{:?}]. Error: {:?}",
|
||||
current_pcb.pid(), pcb.pid(), e
|
||||
)
|
||||
});
|
||||
|
||||
// 拷贝标志位
|
||||
Self::copy_flags(&clone_flags, pcb).unwrap_or_else(|e| {
|
||||
panic!(
|
||||
@ -474,6 +485,8 @@ impl ProcessManager {
|
||||
|
||||
// todo: 增加线程组相关的逻辑。 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/fork.c#2437
|
||||
|
||||
sched_cgroup_fork(pcb);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use alloc::{sync::Arc, vec::Vec};
|
||||
use crate::{
|
||||
mm::{percpu::PerCpu, VirtAddr, IDLE_PROCESS_ADDRESS_SPACE},
|
||||
process::KernelStack,
|
||||
sched::{cpu_rq, OnRq},
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
@ -58,6 +59,21 @@ impl ProcessManager {
|
||||
|
||||
assert!(idle_pcb.sched_info().on_cpu().is_none());
|
||||
idle_pcb.sched_info().set_on_cpu(Some(ProcessorId::new(i)));
|
||||
*idle_pcb.sched_info().sched_policy.write_irqsave() = crate::sched::SchedPolicy::IDLE;
|
||||
|
||||
let rq = cpu_rq(i as usize);
|
||||
let (rq, _guard) = rq.self_lock();
|
||||
rq.set_current(Arc::downgrade(&idle_pcb));
|
||||
rq.set_idle(Arc::downgrade(&idle_pcb));
|
||||
|
||||
*idle_pcb.sched_info().on_rq.lock_irqsave() = OnRq::Queued;
|
||||
|
||||
idle_pcb
|
||||
.sched_info()
|
||||
.sched_entity()
|
||||
.force_mut()
|
||||
.set_cfs(Arc::downgrade(&rq.cfs_rq()));
|
||||
|
||||
v.push(idle_pcb);
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::{
|
||||
hint::spin_loop,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
sync::atomic::{compiler_fence, AtomicBool, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
@ -13,12 +13,13 @@ use atomic_enum::atomic_enum;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::{irqdesc::IrqAction, InterruptArch},
|
||||
init::initial_kthread::initial_kernel_thread,
|
||||
kinfo,
|
||||
libs::{once::Once, spinlock::SpinLock},
|
||||
process::{ProcessManager, ProcessState},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::{fork::CloneFlags, Pid, ProcessControlBlock, ProcessFlags};
|
||||
@ -302,6 +303,8 @@ impl KernelThreadMechanism {
|
||||
// 初始化kthreadd
|
||||
let closure = KernelThreadClosure::EmptyClosure((Box::new(Self::kthread_daemon), ()));
|
||||
let info = KernelThreadCreateInfo::new(closure, "kthreadd".to_string());
|
||||
info.set_to_mark_sleep(false)
|
||||
.expect("kthreadadd should be run first");
|
||||
let kthreadd_pid: Pid = Self::__inner_create(
|
||||
&info,
|
||||
CloneFlags::CLONE_VM | CloneFlags::CLONE_FS | CloneFlags::CLONE_SIGNAL,
|
||||
@ -334,6 +337,7 @@ impl KernelThreadMechanism {
|
||||
spin_loop()
|
||||
}
|
||||
KTHREAD_CREATE_LIST.lock().push_back(info.clone());
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
ProcessManager::wakeup(unsafe { KTHREAD_DAEMON_PCB.as_ref().unwrap() })
|
||||
.expect("Failed to wakeup kthread daemon");
|
||||
return info.poll_result();
|
||||
@ -470,7 +474,7 @@ impl KernelThreadMechanism {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
ProcessManager::mark_sleep(true).ok();
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -495,7 +499,7 @@ pub unsafe extern "C" fn kernel_thread_bootstrap_stage2(ptr: *const KernelThread
|
||||
let irq_guard = CurrentIrqArch::save_and_disable_irq();
|
||||
ProcessManager::mark_sleep(true).expect("Failed to mark sleep");
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
|
||||
let mut retval = SystemError::EINTR.to_posix_errno();
|
||||
|
@ -3,7 +3,7 @@ use core::{
|
||||
hint::spin_loop,
|
||||
intrinsics::{likely, unlikely},
|
||||
mem::ManuallyDrop,
|
||||
sync::atomic::{compiler_fence, AtomicBool, AtomicIsize, AtomicUsize, Ordering},
|
||||
sync::atomic::{compiler_fence, fence, AtomicBool, AtomicUsize, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
@ -18,7 +18,6 @@ use crate::{
|
||||
arch::{
|
||||
ipc::signal::{AtomicSignal, SigSet, Signal},
|
||||
process::ArchPCBInfo,
|
||||
sched::sched,
|
||||
CurrentIrqArch,
|
||||
},
|
||||
driver::tty::tty_core::TtyCore,
|
||||
@ -37,7 +36,7 @@ use crate::{
|
||||
futex::Futex,
|
||||
},
|
||||
lock_free_flags::LockFreeFlags,
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockUpgradableGuard, RwLockWriteGuard},
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
wait_queue::WaitQueue,
|
||||
},
|
||||
@ -48,12 +47,13 @@ use crate::{
|
||||
VirtAddr,
|
||||
},
|
||||
net::socket::SocketInode,
|
||||
sched::completion::Completion,
|
||||
sched::{
|
||||
completion::Completion,
|
||||
core::{sched_enqueue, CPU_EXECUTING},
|
||||
SchedPolicy, SchedPriority,
|
||||
cpu_rq, fair::FairSchedEntity, prio::MAX_PRIO, DequeueFlag, EnqueueFlag, OnRq, SchedMode,
|
||||
WakeupFlags, __schedule,
|
||||
},
|
||||
smp::{
|
||||
core::smp_get_processor_id,
|
||||
cpu::{AtomicProcessorId, ProcessorId},
|
||||
kick_cpu,
|
||||
},
|
||||
@ -225,10 +225,23 @@ impl ProcessManager {
|
||||
let state = writer.state();
|
||||
if state.is_blocked() {
|
||||
writer.set_state(ProcessState::Runnable);
|
||||
writer.set_wakeup();
|
||||
|
||||
// avoid deadlock
|
||||
drop(writer);
|
||||
|
||||
sched_enqueue(pcb.clone(), true);
|
||||
let rq = cpu_rq(pcb.sched_info().on_cpu().unwrap().data() as usize);
|
||||
|
||||
let (rq, _guard) = rq.self_lock();
|
||||
rq.update_rq_clock();
|
||||
rq.activate_task(
|
||||
pcb,
|
||||
EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK,
|
||||
);
|
||||
|
||||
rq.check_preempt_currnet(pcb, WakeupFlags::empty());
|
||||
|
||||
// sched_enqueue(pcb.clone(), true);
|
||||
return Ok(());
|
||||
} else if state.is_exited() {
|
||||
return Err(SystemError::EINVAL);
|
||||
@ -254,7 +267,18 @@ impl ProcessManager {
|
||||
// avoid deadlock
|
||||
drop(writer);
|
||||
|
||||
sched_enqueue(pcb.clone(), true);
|
||||
let rq = cpu_rq(pcb.sched_info().on_cpu().unwrap().data() as usize);
|
||||
|
||||
let (rq, _guard) = rq.self_lock();
|
||||
rq.update_rq_clock();
|
||||
rq.activate_task(
|
||||
pcb,
|
||||
EnqueueFlag::ENQUEUE_WAKEUP | EnqueueFlag::ENQUEUE_NOCLOCK,
|
||||
);
|
||||
|
||||
rq.check_preempt_currnet(pcb, WakeupFlags::empty());
|
||||
|
||||
// sched_enqueue(pcb.clone(), true);
|
||||
return Ok(());
|
||||
} else if state.is_runnable() {
|
||||
return Ok(());
|
||||
@ -280,14 +304,14 @@ impl ProcessManager {
|
||||
!CurrentIrqArch::is_irq_enabled(),
|
||||
"interrupt must be disabled before enter ProcessManager::mark_sleep()"
|
||||
);
|
||||
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let mut writer = pcb.sched_info().inner_lock_write_irqsave();
|
||||
if !matches!(writer.state(), ProcessState::Exited(_)) {
|
||||
writer.set_state(ProcessState::Blocked(interruptable));
|
||||
writer.set_sleep();
|
||||
pcb.flags().insert(ProcessFlags::NEED_SCHEDULE);
|
||||
fence(Ordering::SeqCst);
|
||||
drop(writer);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
return Err(SystemError::EINTR);
|
||||
@ -351,7 +375,7 @@ impl ProcessManager {
|
||||
/// - `exit_code` : 进程的退出码
|
||||
pub fn exit(exit_code: usize) -> ! {
|
||||
// 关中断
|
||||
unsafe { CurrentIrqArch::interrupt_disable() };
|
||||
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
let pcb = ProcessManager::current_pcb();
|
||||
let pid = pcb.pid();
|
||||
pcb.sched_info
|
||||
@ -359,6 +383,14 @@ impl ProcessManager {
|
||||
.set_state(ProcessState::Exited(exit_code));
|
||||
pcb.wait_queue.wakeup(Some(ProcessState::Blocked(true)));
|
||||
|
||||
let rq = cpu_rq(smp_get_processor_id().data() as usize);
|
||||
let (rq, guard) = rq.self_lock();
|
||||
rq.deactivate_task(
|
||||
pcb.clone(),
|
||||
DequeueFlag::DEQUEUE_SLEEP | DequeueFlag::DEQUEUE_NOCLOCK,
|
||||
);
|
||||
drop(guard);
|
||||
|
||||
// 进行进程退出后的工作
|
||||
let thread = pcb.thread.write_irqsave();
|
||||
if let Some(addr) = thread.set_child_tid {
|
||||
@ -381,9 +413,8 @@ impl ProcessManager {
|
||||
unsafe { pcb.basic_mut().set_user_vm(None) };
|
||||
drop(pcb);
|
||||
ProcessManager::exit_notify();
|
||||
unsafe { CurrentIrqArch::interrupt_enable() };
|
||||
|
||||
sched();
|
||||
// unsafe { CurrentIrqArch::interrupt_enable() };
|
||||
__schedule(SchedMode::SM_NONE);
|
||||
kerror!("pid {pid:?} exited but sched again!");
|
||||
#[allow(clippy::empty_loop)]
|
||||
loop {
|
||||
@ -446,7 +477,7 @@ impl ProcessManager {
|
||||
let cpu_id = pcb.sched_info().on_cpu();
|
||||
|
||||
if let Some(cpu_id) = cpu_id {
|
||||
if pcb.pid() == CPU_EXECUTING.get(cpu_id) {
|
||||
if pcb.pid() == cpu_rq(cpu_id.data() as usize).current().pid() {
|
||||
kick_cpu(cpu_id).expect("ProcessManager::kick(): Failed to kick cpu");
|
||||
}
|
||||
}
|
||||
@ -672,6 +703,10 @@ impl ProcessControlBlock {
|
||||
|
||||
let pcb = Arc::new(pcb);
|
||||
|
||||
pcb.sched_info()
|
||||
.sched_entity()
|
||||
.force_mut()
|
||||
.set_pcb(Arc::downgrade(&pcb));
|
||||
// 设置进程的arc指针到内核栈和系统调用栈的最低地址处
|
||||
unsafe {
|
||||
pcb.kernel_stack
|
||||
@ -1038,14 +1073,51 @@ pub struct ProcessSchedulerInfo {
|
||||
on_cpu: AtomicProcessorId,
|
||||
/// 如果当前进程等待被迁移到另一个cpu核心上(也就是flags中的PF_NEED_MIGRATE被置位),
|
||||
/// 该字段存储要被迁移到的目标处理器核心号
|
||||
migrate_to: AtomicProcessorId,
|
||||
// migrate_to: AtomicProcessorId,
|
||||
inner_locked: RwLock<InnerSchedInfo>,
|
||||
/// 进程的调度优先级
|
||||
priority: SchedPriority,
|
||||
// priority: SchedPriority,
|
||||
/// 当前进程的虚拟运行时间
|
||||
virtual_runtime: AtomicIsize,
|
||||
// virtual_runtime: AtomicIsize,
|
||||
/// 由实时调度器管理的时间片
|
||||
rt_time_slice: AtomicIsize,
|
||||
// rt_time_slice: AtomicIsize,
|
||||
pub sched_stat: RwLock<SchedInfo>,
|
||||
/// 调度策略
|
||||
pub sched_policy: RwLock<crate::sched::SchedPolicy>,
|
||||
/// cfs调度实体
|
||||
pub sched_entity: Arc<FairSchedEntity>,
|
||||
pub on_rq: SpinLock<OnRq>,
|
||||
|
||||
pub prio_data: RwLock<PrioData>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SchedInfo {
|
||||
/// 记录任务在特定 CPU 上运行的次数
|
||||
pub pcount: usize,
|
||||
/// 记录任务等待在运行队列上的时间
|
||||
pub run_delay: usize,
|
||||
/// 记录任务上次在 CPU 上运行的时间戳
|
||||
pub last_arrival: u64,
|
||||
/// 记录任务上次被加入到运行队列中的时间戳
|
||||
pub last_queued: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PrioData {
|
||||
pub prio: i32,
|
||||
pub static_prio: i32,
|
||||
pub normal_prio: i32,
|
||||
}
|
||||
|
||||
impl Default for PrioData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
prio: MAX_PRIO - 20,
|
||||
static_prio: MAX_PRIO - 20,
|
||||
normal_prio: MAX_PRIO - 20,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -1053,7 +1125,7 @@ pub struct InnerSchedInfo {
|
||||
/// 当前进程的状态
|
||||
state: ProcessState,
|
||||
/// 进程的调度策略
|
||||
sched_policy: SchedPolicy,
|
||||
sleep: bool,
|
||||
}
|
||||
|
||||
impl InnerSchedInfo {
|
||||
@ -1065,8 +1137,16 @@ impl InnerSchedInfo {
|
||||
self.state = state;
|
||||
}
|
||||
|
||||
pub fn policy(&self) -> SchedPolicy {
|
||||
return self.sched_policy;
|
||||
pub fn set_sleep(&mut self) {
|
||||
self.sleep = true;
|
||||
}
|
||||
|
||||
pub fn set_wakeup(&mut self) {
|
||||
self.sleep = false;
|
||||
}
|
||||
|
||||
pub fn is_mark_sleep(&self) -> bool {
|
||||
self.sleep
|
||||
}
|
||||
}
|
||||
|
||||
@ -1076,17 +1156,26 @@ impl ProcessSchedulerInfo {
|
||||
let cpu_id = on_cpu.unwrap_or(ProcessorId::INVALID);
|
||||
return Self {
|
||||
on_cpu: AtomicProcessorId::new(cpu_id),
|
||||
migrate_to: AtomicProcessorId::new(ProcessorId::INVALID),
|
||||
// migrate_to: AtomicProcessorId::new(ProcessorId::INVALID),
|
||||
inner_locked: RwLock::new(InnerSchedInfo {
|
||||
state: ProcessState::Blocked(false),
|
||||
sched_policy: SchedPolicy::CFS,
|
||||
sleep: false,
|
||||
}),
|
||||
virtual_runtime: AtomicIsize::new(0),
|
||||
rt_time_slice: AtomicIsize::new(0),
|
||||
priority: SchedPriority::new(100).unwrap(),
|
||||
// virtual_runtime: AtomicIsize::new(0),
|
||||
// rt_time_slice: AtomicIsize::new(0),
|
||||
// priority: SchedPriority::new(100).unwrap(),
|
||||
sched_stat: RwLock::new(SchedInfo::default()),
|
||||
sched_policy: RwLock::new(crate::sched::SchedPolicy::CFS),
|
||||
sched_entity: FairSchedEntity::new(),
|
||||
on_rq: SpinLock::new(OnRq::None),
|
||||
prio_data: RwLock::new(PrioData::default()),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sched_entity(&self) -> Arc<FairSchedEntity> {
|
||||
return self.sched_entity.clone();
|
||||
}
|
||||
|
||||
pub fn on_cpu(&self) -> Option<ProcessorId> {
|
||||
let on_cpu = self.on_cpu.load(Ordering::SeqCst);
|
||||
if on_cpu == ProcessorId::INVALID {
|
||||
@ -1104,23 +1193,23 @@ impl ProcessSchedulerInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn migrate_to(&self) -> Option<ProcessorId> {
|
||||
let migrate_to = self.migrate_to.load(Ordering::SeqCst);
|
||||
if migrate_to == ProcessorId::INVALID {
|
||||
return None;
|
||||
} else {
|
||||
return Some(migrate_to);
|
||||
}
|
||||
}
|
||||
// pub fn migrate_to(&self) -> Option<ProcessorId> {
|
||||
// let migrate_to = self.migrate_to.load(Ordering::SeqCst);
|
||||
// if migrate_to == ProcessorId::INVALID {
|
||||
// return None;
|
||||
// } else {
|
||||
// return Some(migrate_to);
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn set_migrate_to(&self, migrate_to: Option<ProcessorId>) {
|
||||
if let Some(data) = migrate_to {
|
||||
self.migrate_to.store(data, Ordering::SeqCst);
|
||||
} else {
|
||||
self.migrate_to
|
||||
.store(ProcessorId::INVALID, Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
// pub fn set_migrate_to(&self, migrate_to: Option<ProcessorId>) {
|
||||
// if let Some(data) = migrate_to {
|
||||
// self.migrate_to.store(data, Ordering::SeqCst);
|
||||
// } else {
|
||||
// self.migrate_to
|
||||
// .store(ProcessorId::INVALID, Ordering::SeqCst)
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn inner_lock_write_irqsave(&self) -> RwLockWriteGuard<InnerSchedInfo> {
|
||||
return self.inner_locked.write_irqsave();
|
||||
@ -1130,58 +1219,58 @@ impl ProcessSchedulerInfo {
|
||||
return self.inner_locked.read_irqsave();
|
||||
}
|
||||
|
||||
pub fn inner_lock_try_read_irqsave(
|
||||
&self,
|
||||
times: u8,
|
||||
) -> Option<RwLockReadGuard<InnerSchedInfo>> {
|
||||
for _ in 0..times {
|
||||
if let Some(r) = self.inner_locked.try_read_irqsave() {
|
||||
return Some(r);
|
||||
}
|
||||
}
|
||||
// pub fn inner_lock_try_read_irqsave(
|
||||
// &self,
|
||||
// times: u8,
|
||||
// ) -> Option<RwLockReadGuard<InnerSchedInfo>> {
|
||||
// for _ in 0..times {
|
||||
// if let Some(r) = self.inner_locked.try_read_irqsave() {
|
||||
// return Some(r);
|
||||
// }
|
||||
// }
|
||||
|
||||
return None;
|
||||
}
|
||||
// return None;
|
||||
// }
|
||||
|
||||
pub fn inner_lock_try_upgradable_read_irqsave(
|
||||
&self,
|
||||
times: u8,
|
||||
) -> Option<RwLockUpgradableGuard<InnerSchedInfo>> {
|
||||
for _ in 0..times {
|
||||
if let Some(r) = self.inner_locked.try_upgradeable_read_irqsave() {
|
||||
return Some(r);
|
||||
}
|
||||
}
|
||||
// pub fn inner_lock_try_upgradable_read_irqsave(
|
||||
// &self,
|
||||
// times: u8,
|
||||
// ) -> Option<RwLockUpgradableGuard<InnerSchedInfo>> {
|
||||
// for _ in 0..times {
|
||||
// if let Some(r) = self.inner_locked.try_upgradeable_read_irqsave() {
|
||||
// return Some(r);
|
||||
// }
|
||||
// }
|
||||
|
||||
return None;
|
||||
}
|
||||
// return None;
|
||||
// }
|
||||
|
||||
pub fn virtual_runtime(&self) -> isize {
|
||||
return self.virtual_runtime.load(Ordering::SeqCst);
|
||||
}
|
||||
// pub fn virtual_runtime(&self) -> isize {
|
||||
// return self.virtual_runtime.load(Ordering::SeqCst);
|
||||
// }
|
||||
|
||||
pub fn set_virtual_runtime(&self, virtual_runtime: isize) {
|
||||
self.virtual_runtime
|
||||
.store(virtual_runtime, Ordering::SeqCst);
|
||||
}
|
||||
pub fn increase_virtual_runtime(&self, delta: isize) {
|
||||
self.virtual_runtime.fetch_add(delta, Ordering::SeqCst);
|
||||
}
|
||||
// pub fn set_virtual_runtime(&self, virtual_runtime: isize) {
|
||||
// self.virtual_runtime
|
||||
// .store(virtual_runtime, Ordering::SeqCst);
|
||||
// }
|
||||
// pub fn increase_virtual_runtime(&self, delta: isize) {
|
||||
// self.virtual_runtime.fetch_add(delta, Ordering::SeqCst);
|
||||
// }
|
||||
|
||||
pub fn rt_time_slice(&self) -> isize {
|
||||
return self.rt_time_slice.load(Ordering::SeqCst);
|
||||
}
|
||||
// pub fn rt_time_slice(&self) -> isize {
|
||||
// return self.rt_time_slice.load(Ordering::SeqCst);
|
||||
// }
|
||||
|
||||
pub fn set_rt_time_slice(&self, rt_time_slice: isize) {
|
||||
self.rt_time_slice.store(rt_time_slice, Ordering::SeqCst);
|
||||
}
|
||||
// pub fn set_rt_time_slice(&self, rt_time_slice: isize) {
|
||||
// self.rt_time_slice.store(rt_time_slice, Ordering::SeqCst);
|
||||
// }
|
||||
|
||||
pub fn increase_rt_time_slice(&self, delta: isize) {
|
||||
self.rt_time_slice.fetch_add(delta, Ordering::SeqCst);
|
||||
}
|
||||
// pub fn increase_rt_time_slice(&self, delta: isize) {
|
||||
// self.rt_time_slice.fetch_add(delta, Ordering::SeqCst);
|
||||
// }
|
||||
|
||||
pub fn priority(&self) -> SchedPriority {
|
||||
return self.priority;
|
||||
pub fn policy(&self) -> crate::sched::SchedPolicy {
|
||||
return *self.sched_policy.read_irqsave();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,283 +0,0 @@
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
kBUG,
|
||||
libs::{
|
||||
rbtree::RBTree,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
mm::percpu::PerCpu,
|
||||
process::{
|
||||
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
|
||||
},
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::{
|
||||
core::{sched_enqueue, Scheduler},
|
||||
SchedPriority,
|
||||
};
|
||||
|
||||
/// 声明全局的cfs调度器实例
|
||||
pub static mut CFS_SCHEDULER_PTR: Option<Box<SchedulerCFS>> = None;
|
||||
|
||||
/// @brief 获取cfs调度器实例的可变引用
|
||||
#[inline]
|
||||
pub fn __get_cfs_scheduler() -> &'static mut SchedulerCFS {
|
||||
return unsafe { CFS_SCHEDULER_PTR.as_mut().unwrap() };
|
||||
}
|
||||
|
||||
/// @brief 初始化cfs调度器
|
||||
pub unsafe fn sched_cfs_init() {
|
||||
if CFS_SCHEDULER_PTR.is_none() {
|
||||
CFS_SCHEDULER_PTR = Some(Box::new(SchedulerCFS::new()));
|
||||
} else {
|
||||
kBUG!("Try to init CFS Scheduler twice.");
|
||||
panic!("Try to init CFS Scheduler twice.");
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief CFS队列(per-cpu的)
|
||||
#[derive(Debug)]
|
||||
struct CFSQueue {
|
||||
/// 当前cpu上执行的进程剩余的时间片
|
||||
cpu_exec_proc_jiffies: i64,
|
||||
/// 自旋锁保护的队列
|
||||
locked_queue: SpinLock<RBTree<i64, Arc<ProcessControlBlock>>>,
|
||||
/// 当前核心的队列专属的IDLE进程的pcb
|
||||
idle_pcb: Arc<ProcessControlBlock>,
|
||||
}
|
||||
|
||||
impl CFSQueue {
|
||||
pub fn new(idle_pcb: Arc<ProcessControlBlock>) -> CFSQueue {
|
||||
CFSQueue {
|
||||
cpu_exec_proc_jiffies: 0,
|
||||
locked_queue: SpinLock::new(RBTree::new()),
|
||||
idle_pcb,
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 将pcb加入队列
|
||||
pub fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let mut queue = self.locked_queue.lock_irqsave();
|
||||
|
||||
// 如果进程是IDLE进程,那么就不加入队列
|
||||
if pcb.pid().into() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
queue.insert(pcb.sched_info().virtual_runtime() as i64, pcb.clone());
|
||||
}
|
||||
|
||||
/// @brief 将pcb从调度队列中弹出,若队列为空,则返回IDLE进程的pcb
|
||||
pub fn dequeue(&mut self) -> Arc<ProcessControlBlock> {
|
||||
let res: Arc<ProcessControlBlock>;
|
||||
let mut queue = self.locked_queue.lock_irqsave();
|
||||
if !queue.is_empty() {
|
||||
// 队列不为空,返回下一个要执行的pcb
|
||||
res = queue.pop_first().unwrap().1;
|
||||
} else {
|
||||
// 如果队列为空,则返回IDLE进程的pcb
|
||||
res = self.idle_pcb.clone();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/// @brief 获取cfs队列的最小运行时间
|
||||
///
|
||||
/// @return Option<i64> 如果队列不为空,那么返回队列中,最小的虚拟运行时间;否则返回None
|
||||
pub fn min_vruntime(
|
||||
queue: &SpinLockGuard<RBTree<i64, Arc<ProcessControlBlock>>>,
|
||||
) -> Option<i64> {
|
||||
if !queue.is_empty() {
|
||||
return Some(queue.get_first().unwrap().1.sched_info().virtual_runtime() as i64);
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
/// 获取运行队列的长度
|
||||
#[allow(dead_code)]
|
||||
pub fn get_cfs_queue_size(
|
||||
queue: &SpinLockGuard<RBTree<i64, Arc<ProcessControlBlock>>>,
|
||||
) -> usize {
|
||||
return queue.len();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief CFS调度器类
|
||||
pub struct SchedulerCFS {
|
||||
cpu_queue: Vec<&'static mut CFSQueue>,
|
||||
}
|
||||
|
||||
impl SchedulerCFS {
|
||||
pub fn new() -> SchedulerCFS {
|
||||
// 暂时手动指定核心数目
|
||||
// todo: 从cpu模块来获取核心的数目
|
||||
let mut result = SchedulerCFS {
|
||||
cpu_queue: Default::default(),
|
||||
};
|
||||
|
||||
// 为每个cpu核心创建队列,进程重构后可以直接初始化Idle_pcb?
|
||||
for i in 0..PerCpu::MAX_CPU_NUM {
|
||||
let idle_pcb = ProcessManager::idle_pcb()[i as usize].clone();
|
||||
result
|
||||
.cpu_queue
|
||||
.push(Box::leak(Box::new(CFSQueue::new(idle_pcb))));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief 更新这个cpu上,这个进程的可执行时间。
|
||||
#[inline]
|
||||
fn update_cpu_exec_proc_jiffies(
|
||||
_priority: SchedPriority,
|
||||
cfs_queue: &mut CFSQueue,
|
||||
is_idle: bool,
|
||||
) -> &mut CFSQueue {
|
||||
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置分配给进程的可执行时间
|
||||
if !is_idle {
|
||||
cfs_queue.cpu_exec_proc_jiffies = 10;
|
||||
} else {
|
||||
cfs_queue.cpu_exec_proc_jiffies = 0;
|
||||
}
|
||||
|
||||
return cfs_queue;
|
||||
}
|
||||
|
||||
/// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间
|
||||
pub fn timer_update_jiffies(&mut self, sched_info: &ProcessSchedulerInfo) {
|
||||
let current_cpu_queue: &mut CFSQueue =
|
||||
self.cpu_queue[smp_get_processor_id().data() as usize];
|
||||
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间
|
||||
|
||||
let mut queue = None;
|
||||
for _ in 0..10 {
|
||||
if let Ok(q) = current_cpu_queue.locked_queue.try_lock_irqsave() {
|
||||
queue = Some(q);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if queue.is_none() {
|
||||
return;
|
||||
}
|
||||
let queue = queue.unwrap();
|
||||
// 更新进程的剩余可执行时间
|
||||
current_cpu_queue.cpu_exec_proc_jiffies -= 1;
|
||||
// 时间片耗尽,标记需要被调度
|
||||
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
|
||||
ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.insert(ProcessFlags::NEED_SCHEDULE);
|
||||
}
|
||||
drop(queue);
|
||||
|
||||
// 更新当前进程的虚拟运行时间
|
||||
sched_info.increase_virtual_runtime(1);
|
||||
}
|
||||
|
||||
/// @brief 将进程加入cpu的cfs调度队列,并且重设其虚拟运行时间为当前队列的最小值
|
||||
pub fn enqueue_reset_vruntime(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
|
||||
let queue = cpu_queue.locked_queue.lock_irqsave();
|
||||
if queue.len() > 0 {
|
||||
pcb.sched_info()
|
||||
.set_virtual_runtime(CFSQueue::min_vruntime(&queue).unwrap_or(0) as isize)
|
||||
}
|
||||
drop(queue);
|
||||
cpu_queue.enqueue(pcb);
|
||||
}
|
||||
|
||||
/// @brief 设置cpu的队列的IDLE进程的pcb
|
||||
#[allow(dead_code)]
|
||||
pub fn set_cpu_idle(&mut self, cpu_id: usize, pcb: Arc<ProcessControlBlock>) {
|
||||
// kdebug!("set cpu idle: id={}", cpu_id);
|
||||
self.cpu_queue[cpu_id].idle_pcb = pcb;
|
||||
}
|
||||
/// 获取某个cpu的运行队列中的进程数
|
||||
pub fn get_cfs_queue_len(&mut self, cpu_id: ProcessorId) -> usize {
|
||||
let queue = self.cpu_queue[cpu_id.data() as usize]
|
||||
.locked_queue
|
||||
.lock_irqsave();
|
||||
return CFSQueue::get_cfs_queue_size(&queue);
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheduler for SchedulerCFS {
|
||||
/// @brief 在当前cpu上进行调度。
|
||||
/// 请注意,进入该函数之前,需要关中断
|
||||
fn sched(&mut self) -> Option<Arc<ProcessControlBlock>> {
|
||||
assert!(!CurrentIrqArch::is_irq_enabled());
|
||||
|
||||
ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.remove(ProcessFlags::NEED_SCHEDULE);
|
||||
|
||||
let current_cpu_id = smp_get_processor_id().data() as usize;
|
||||
|
||||
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
|
||||
|
||||
let proc: Arc<ProcessControlBlock> = current_cpu_queue.dequeue();
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
// 如果当前不是running态,或者当前进程的虚拟运行时间大于等于下一个进程的,那就需要切换。
|
||||
let state = ProcessManager::current_pcb()
|
||||
.sched_info()
|
||||
.inner_lock_read_irqsave()
|
||||
.state();
|
||||
if (state != ProcessState::Runnable)
|
||||
|| (ProcessManager::current_pcb().sched_info().virtual_runtime()
|
||||
>= proc.sched_info().virtual_runtime())
|
||||
{
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
// 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
|
||||
if state == ProcessState::Runnable {
|
||||
sched_enqueue(ProcessManager::current_pcb(), false);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
// 设置进程可以执行的时间
|
||||
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
|
||||
SchedulerCFS::update_cpu_exec_proc_jiffies(
|
||||
proc.sched_info().priority(),
|
||||
current_cpu_queue,
|
||||
Arc::ptr_eq(&proc, ¤t_cpu_queue.idle_pcb),
|
||||
);
|
||||
}
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
return Some(proc);
|
||||
} else {
|
||||
// 不进行切换
|
||||
|
||||
// 设置进程可以执行的时间
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
if current_cpu_queue.cpu_exec_proc_jiffies <= 0 {
|
||||
SchedulerCFS::update_cpu_exec_proc_jiffies(
|
||||
ProcessManager::current_pcb().sched_info().priority(),
|
||||
current_cpu_queue,
|
||||
Arc::ptr_eq(&proc, ¤t_cpu_queue.idle_pcb),
|
||||
);
|
||||
// kdebug!("cpu:{:?}",current_cpu_id);
|
||||
}
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
sched_enqueue(proc, false);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
}
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_queue = &mut self.cpu_queue[pcb.sched_info().on_cpu().unwrap().data() as usize];
|
||||
|
||||
cpu_queue.enqueue(pcb);
|
||||
}
|
||||
}
|
38
kernel/src/sched/clock.rs
Normal file
38
kernel/src/sched/clock.rs
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
这个文件实现的是调度过程中设计到的时钟
|
||||
*/
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::{
|
||||
arch::{driver::tsc::TSCManager, CurrentTimeArch},
|
||||
time::TimeArch,
|
||||
};
|
||||
|
||||
pub struct SchedClock;
|
||||
|
||||
impl SchedClock {
|
||||
#[inline]
|
||||
pub fn sched_clock_cpu(_cpu: usize) -> u64 {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
if TSCManager::cpu_khz() == 0 {
|
||||
// TCS no init
|
||||
return 0;
|
||||
}
|
||||
return CurrentTimeArch::cycles2ns(CurrentTimeArch::get_cycles()) as u64;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct ClockUpdataFlag: u8 {
|
||||
/// 请求在下一次调用 __schedule() 时跳过时钟更新
|
||||
const RQCF_REQ_SKIP = 0x01;
|
||||
/// 表示跳过时钟更新正在生效,update_rq_clock() 的调用将被忽略。
|
||||
const RQCF_ACT_SKIP = 0x02;
|
||||
/// 调试标志,指示自上次固定 rq::lock 以来是否已调用过
|
||||
const RQCF_UPDATE = 0x04;
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
use core::{
|
||||
intrinsics::unlikely,
|
||||
sync::atomic::{compiler_fence, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
kinfo,
|
||||
mm::percpu::PerCpu,
|
||||
process::{AtomicPid, Pid, ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState},
|
||||
smp::{core::smp_get_processor_id, cpu::ProcessorId},
|
||||
};
|
||||
|
||||
use super::rt::{sched_rt_init, SchedulerRT, __get_rt_scheduler};
|
||||
use super::{
|
||||
cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler},
|
||||
SchedPolicy,
|
||||
};
|
||||
|
||||
lazy_static! {
|
||||
/// 记录每个cpu上正在执行的进程的pid
|
||||
pub static ref CPU_EXECUTING: CpuExecuting = CpuExecuting::new();
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CpuExecuting {
|
||||
data: Vec<AtomicPid>,
|
||||
}
|
||||
|
||||
impl CpuExecuting {
|
||||
pub fn new() -> Self {
|
||||
let mut data = Vec::new();
|
||||
for _ in 0..PerCpu::MAX_CPU_NUM {
|
||||
data.push(AtomicPid::new(Pid::new(0)));
|
||||
}
|
||||
Self { data }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn set(&self, cpu_id: ProcessorId, pid: Pid) {
|
||||
self.data[cpu_id.data() as usize].store(pid, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get(&self, cpu_id: ProcessorId) -> Pid {
|
||||
self.data[cpu_id.data() as usize].load(Ordering::SeqCst)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取某个cpu的负载情况,返回当前负载,cpu_id 是获取负载的cpu的id
|
||||
// TODO:将获取负载情况调整为最近一段时间运行进程的数量
|
||||
#[allow(dead_code)]
|
||||
pub fn get_cpu_loads(cpu_id: ProcessorId) -> u32 {
|
||||
let cfs_scheduler = __get_cfs_scheduler();
|
||||
let rt_scheduler = __get_rt_scheduler();
|
||||
let len_cfs = cfs_scheduler.get_cfs_queue_len(cpu_id);
|
||||
let len_rt = rt_scheduler.rt_queue_len(cpu_id);
|
||||
// let load_rt = rt_scheduler.get_load_list_len(cpu_id);
|
||||
// kdebug!("this cpu_id {} is load rt {}", cpu_id, load_rt);
|
||||
|
||||
return (len_rt + len_cfs) as u32;
|
||||
}
|
||||
// 负载均衡
|
||||
pub fn loads_balance(pcb: Arc<ProcessControlBlock>) {
|
||||
// FIXME: 由于目前负载均衡是直接添加到目标CPU的队列中,导致会由于时序问题导致进程在两个CPU上都存在。
|
||||
// 在调度子系统重写/改进之前,暂时只设置进程在0号CPU上运行
|
||||
// 由于调度器问题,暂时不进行负载均衡,见issue: https://github.com/DragonOS-Community/DragonOS/issues/571
|
||||
let min_loads_cpu_id = ProcessorId::new(0);
|
||||
|
||||
// 获取总的CPU数量
|
||||
// let cpu_num = unsafe { smp_get_total_cpu() };
|
||||
// 获取当前负载最小的CPU的id
|
||||
// let mut min_loads = get_cpu_loads(smp_get_processor_id());
|
||||
// for cpu_id in 0..cpu_num {
|
||||
// let cpu_id = ProcessorId::new(cpu_id);
|
||||
// let tmp_cpu_loads = get_cpu_loads(cpu_id);
|
||||
// if min_loads - tmp_cpu_loads > 0 {
|
||||
// min_loads_cpu_id = cpu_id;
|
||||
// min_loads = tmp_cpu_loads;
|
||||
// }
|
||||
// }
|
||||
|
||||
let pcb_cpu = pcb.sched_info().on_cpu();
|
||||
// 将当前pcb迁移到负载最小的CPU
|
||||
// 如果当前pcb的PF_NEED_MIGRATE已经置位,则不进行迁移操作
|
||||
if pcb_cpu.is_none()
|
||||
|| (min_loads_cpu_id != pcb_cpu.unwrap()
|
||||
&& !pcb.flags().contains(ProcessFlags::NEED_MIGRATE))
|
||||
{
|
||||
pcb.flags().insert(ProcessFlags::NEED_MIGRATE);
|
||||
pcb.sched_info().set_migrate_to(Some(min_loads_cpu_id));
|
||||
// kdebug!("set migrating, pcb:{:?}", pcb);
|
||||
}
|
||||
}
|
||||
/// @brief 具体的调度器应当实现的trait
|
||||
pub trait Scheduler {
|
||||
/// @brief 使用该调度器发起调度的时候,要调用的函数
|
||||
fn sched(&mut self) -> Option<Arc<ProcessControlBlock>>;
|
||||
|
||||
/// @brief 将pcb加入这个调度器的调度队列
|
||||
fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>);
|
||||
}
|
||||
|
||||
pub fn do_sched() -> Option<Arc<ProcessControlBlock>> {
|
||||
// 当前进程持有锁,不切换,避免死锁
|
||||
if ProcessManager::current_pcb().preempt_count() != 0 {
|
||||
let binding = ProcessManager::current_pcb();
|
||||
let guard = binding
|
||||
.sched_info()
|
||||
.inner_lock_try_upgradable_read_irqsave(5);
|
||||
if unlikely(guard.is_none()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut guard = guard.unwrap();
|
||||
|
||||
let state = guard.state();
|
||||
if state.is_blocked() {
|
||||
// try to upgrade
|
||||
for _ in 0..50 {
|
||||
match guard.try_upgrade() {
|
||||
Ok(mut writer) => {
|
||||
// 被mark_sleep但是还在临界区的进程将其设置为Runnable
|
||||
writer.set_state(ProcessState::Runnable);
|
||||
break;
|
||||
}
|
||||
Err(s) => {
|
||||
guard = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let cfs_scheduler: &mut SchedulerCFS = __get_cfs_scheduler();
|
||||
let rt_scheduler: &mut SchedulerRT = __get_rt_scheduler();
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let next: Arc<ProcessControlBlock>;
|
||||
match rt_scheduler.pick_next_task_rt(smp_get_processor_id()) {
|
||||
Some(p) => {
|
||||
next = p;
|
||||
// 将pick的进程放回原处
|
||||
rt_scheduler.enqueue_front(next);
|
||||
|
||||
return rt_scheduler.sched();
|
||||
}
|
||||
None => {
|
||||
return cfs_scheduler.sched();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 将进程加入调度队列
|
||||
///
|
||||
/// @param pcb 要被加入队列的pcb
|
||||
/// @param reset_time 是否重置虚拟运行时间
|
||||
pub fn sched_enqueue(pcb: Arc<ProcessControlBlock>, mut reset_time: bool) {
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
if pcb.sched_info().inner_lock_read_irqsave().state() != ProcessState::Runnable {
|
||||
return;
|
||||
}
|
||||
let cfs_scheduler = __get_cfs_scheduler();
|
||||
let rt_scheduler = __get_rt_scheduler();
|
||||
// 除了IDLE以外的进程,都进行负载均衡
|
||||
if pcb.pid().into() > 0 {
|
||||
loads_balance(pcb.clone());
|
||||
}
|
||||
|
||||
if pcb.flags().contains(ProcessFlags::NEED_MIGRATE) {
|
||||
// kdebug!("migrating pcb:{:?}", pcb);
|
||||
pcb.flags().remove(ProcessFlags::NEED_MIGRATE);
|
||||
pcb.sched_info().set_on_cpu(pcb.sched_info().migrate_to());
|
||||
reset_time = true;
|
||||
}
|
||||
|
||||
assert!(pcb.sched_info().on_cpu().is_some());
|
||||
|
||||
match pcb.sched_info().inner_lock_read_irqsave().policy() {
|
||||
SchedPolicy::CFS => {
|
||||
if reset_time {
|
||||
cfs_scheduler.enqueue_reset_vruntime(pcb.clone());
|
||||
} else {
|
||||
cfs_scheduler.enqueue(pcb.clone());
|
||||
}
|
||||
}
|
||||
SchedPolicy::FIFO | SchedPolicy::RR => rt_scheduler.enqueue(pcb.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化进程调度器模块
|
||||
#[inline(never)]
|
||||
pub fn sched_init() {
|
||||
kinfo!("Initializing schedulers...");
|
||||
unsafe {
|
||||
sched_cfs_init();
|
||||
sched_rt_init();
|
||||
}
|
||||
kinfo!("Schedulers initialized");
|
||||
}
|
||||
|
||||
/// @brief 当时钟中断到达时,更新时间片
|
||||
/// 请注意,该函数只能被时钟中断处理程序调用
|
||||
#[inline(never)]
|
||||
pub fn sched_update_jiffies() {
|
||||
let binding = ProcessManager::current_pcb();
|
||||
let guard = binding.sched_info().inner_lock_try_read_irqsave(10);
|
||||
if unlikely(guard.is_none()) {
|
||||
return;
|
||||
}
|
||||
let guard = guard.unwrap();
|
||||
let policy = guard.policy();
|
||||
drop(guard);
|
||||
match policy {
|
||||
SchedPolicy::CFS => {
|
||||
__get_cfs_scheduler().timer_update_jiffies(binding.sched_info());
|
||||
}
|
||||
SchedPolicy::FIFO | SchedPolicy::RR => {
|
||||
__get_rt_scheduler().timer_update_jiffies();
|
||||
}
|
||||
}
|
||||
}
|
107
kernel/src/sched/cputime.rs
Normal file
107
kernel/src/sched/cputime.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use core::sync::atomic::{compiler_fence, AtomicUsize, Ordering};
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch, exception::InterruptArch, process::ProcessControlBlock,
|
||||
smp::core::smp_get_processor_id, time::jiffies::TICK_NESC,
|
||||
};
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use super::{clock::SchedClock, cpu_irq_time};
|
||||
|
||||
pub fn irq_time_read(cpu: usize) -> u64 {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let irqtime = cpu_irq_time(cpu);
|
||||
|
||||
let mut total;
|
||||
|
||||
loop {
|
||||
let seq = irqtime.sync.load(Ordering::SeqCst);
|
||||
total = irqtime.total;
|
||||
|
||||
if seq == irqtime.sync.load(Ordering::SeqCst) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
total
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct IrqTime {
|
||||
pub total: u64,
|
||||
pub tick_delta: u64,
|
||||
pub irq_start_time: u64,
|
||||
pub sync: AtomicUsize,
|
||||
}
|
||||
|
||||
impl IrqTime {
|
||||
pub fn account_delta(&mut self, delta: u64) {
|
||||
// 开始更改时增加序列号
|
||||
self.sync.fetch_add(1, Ordering::SeqCst);
|
||||
self.total += delta;
|
||||
self.tick_delta += delta;
|
||||
}
|
||||
|
||||
pub fn irqtime_tick_accounted(&mut self, max: u64) -> u64 {
|
||||
let delta = self.tick_delta.min(max);
|
||||
self.tick_delta -= delta;
|
||||
return delta;
|
||||
}
|
||||
|
||||
pub fn irqtime_start() {
|
||||
let cpu = smp_get_processor_id().data() as usize;
|
||||
let irq_time = cpu_irq_time(cpu);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
irq_time.irq_start_time = SchedClock::sched_clock_cpu(cpu) as u64;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub fn irqtime_account_irq(_pcb: Arc<ProcessControlBlock>) {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let cpu = smp_get_processor_id().data() as usize;
|
||||
let irq_time = cpu_irq_time(cpu);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
let delta = SchedClock::sched_clock_cpu(cpu) as u64 - irq_time.irq_start_time;
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
irq_time.account_delta(delta);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CpuTimeFunc;
|
||||
impl CpuTimeFunc {
|
||||
pub fn irqtime_account_process_tick(
|
||||
_pcb: &Arc<ProcessControlBlock>,
|
||||
_user_tick: bool,
|
||||
ticks: u64,
|
||||
) {
|
||||
let cputime = TICK_NESC as u64 * ticks;
|
||||
|
||||
let other = Self::account_other_time(u64::MAX);
|
||||
|
||||
if other >= cputime {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: update process time
|
||||
}
|
||||
|
||||
pub fn account_other_time(max: u64) -> u64 {
|
||||
assert!(!CurrentIrqArch::is_irq_enabled());
|
||||
|
||||
let mut accounted = Self::steal_account_process_time(max);
|
||||
|
||||
if accounted < max {
|
||||
let irqtime = cpu_irq_time(smp_get_processor_id().data() as usize);
|
||||
accounted += irqtime.irqtime_tick_accounted(max - accounted);
|
||||
}
|
||||
|
||||
accounted
|
||||
}
|
||||
|
||||
pub fn steal_account_process_time(_max: u64) -> u64 {
|
||||
// 这里未考虑虚拟机时间窃取
|
||||
0
|
||||
}
|
||||
}
|
1801
kernel/src/sched/fair.rs
Normal file
1801
kernel/src/sched/fair.rs
Normal file
File diff suppressed because it is too large
Load Diff
67
kernel/src/sched/idle.rs
Normal file
67
kernel/src/sched/idle.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use super::Scheduler;
|
||||
|
||||
pub struct IdleScheduler;
|
||||
|
||||
impl Scheduler for IdleScheduler {
|
||||
fn enqueue(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
_pcb: alloc::sync::Arc<crate::process::ProcessControlBlock>,
|
||||
_flags: super::EnqueueFlag,
|
||||
) {
|
||||
// idle已经被设置,无需入队
|
||||
}
|
||||
|
||||
fn dequeue(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
_pcb: alloc::sync::Arc<crate::process::ProcessControlBlock>,
|
||||
_flags: super::DequeueFlag,
|
||||
) {
|
||||
}
|
||||
|
||||
fn yield_task(_rq: &mut super::CpuRunQueue) {}
|
||||
|
||||
fn check_preempt_currnet(
|
||||
rq: &mut super::CpuRunQueue,
|
||||
_pcb: &alloc::sync::Arc<crate::process::ProcessControlBlock>,
|
||||
_flags: super::WakeupFlags,
|
||||
) {
|
||||
rq.resched_current();
|
||||
}
|
||||
|
||||
fn pick_task(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
) -> Option<alloc::sync::Arc<crate::process::ProcessControlBlock>> {
|
||||
panic!()
|
||||
}
|
||||
|
||||
/// ### 表示idle被选中
|
||||
///
|
||||
/// 主要做一些统计工作
|
||||
fn pick_next_task(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
_pcb: Option<alloc::sync::Arc<crate::process::ProcessControlBlock>>,
|
||||
) -> Option<alloc::sync::Arc<crate::process::ProcessControlBlock>> {
|
||||
// TODO: Fixme
|
||||
// 做一些统计工作
|
||||
None
|
||||
}
|
||||
|
||||
fn tick(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
_pcb: alloc::sync::Arc<crate::process::ProcessControlBlock>,
|
||||
_queued: bool,
|
||||
) {
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
fn task_fork(_pcb: alloc::sync::Arc<crate::process::ProcessControlBlock>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn put_prev_task(
|
||||
_rq: &mut super::CpuRunQueue,
|
||||
_prev: alloc::sync::Arc<crate::process::ProcessControlBlock>,
|
||||
) {
|
||||
// Nothing todo
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
260
kernel/src/sched/pelt.rs
Normal file
260
kernel/src/sched/pelt.rs
Normal file
@ -0,0 +1,260 @@
|
||||
use core::intrinsics::unlikely;
|
||||
|
||||
use alloc::sync::Arc;
|
||||
|
||||
use crate::process::ProcessControlBlock;
|
||||
|
||||
use super::{
|
||||
fair::{CfsRunQueue, FairSchedEntity},
|
||||
CpuRunQueue, LoadWeight, SchedPolicy, SCHED_CAPACITY_SCALE, SCHED_CAPACITY_SHIFT,
|
||||
};
|
||||
|
||||
const RUNNABLE_AVG_Y_N_INV: [u32; 32] = [
|
||||
0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6, 0xe0ccdeeb, 0xdbfbb796,
|
||||
0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85, 0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46,
|
||||
0xb504f333, 0xb123f581, 0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9,
|
||||
0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80, 0x85aac367, 0x82cd8698,
|
||||
];
|
||||
|
||||
pub const LOAD_AVG_PERIOD: u64 = 32;
|
||||
pub const LOAD_AVG_MAX: usize = 47742;
|
||||
pub const PELT_MIN_DIVIDER: usize = LOAD_AVG_MAX - 1024;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct SchedulerAvg {
|
||||
/// 存储上次更新这些平均值的时间
|
||||
pub last_update_time: u64,
|
||||
/// 存储所有可运行任务的负载之和
|
||||
pub load_sum: u64,
|
||||
/// 存储所有可运行任务的时间之和
|
||||
pub runnable_sum: u64,
|
||||
/// 存储所有运行任务的时间之和
|
||||
pub util_sum: u64,
|
||||
/// 记录周期性任务的贡献值,用于计算平均CPU利用率
|
||||
pub period_contrib: u32,
|
||||
|
||||
pub load_avg: usize,
|
||||
pub runnable_avg: usize,
|
||||
pub util_avg: usize,
|
||||
}
|
||||
|
||||
impl SchedulerAvg {
|
||||
#[inline]
|
||||
pub fn get_pelt_divider(&self) -> usize {
|
||||
return PELT_MIN_DIVIDER + self.period_contrib as usize;
|
||||
}
|
||||
|
||||
pub fn update_load_sum(
|
||||
&mut self,
|
||||
now: u64,
|
||||
load: u32,
|
||||
mut runnable: u32,
|
||||
mut running: u32,
|
||||
) -> bool {
|
||||
if now < self.last_update_time {
|
||||
self.last_update_time = now;
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut delta = now - self.last_update_time;
|
||||
delta >>= 10;
|
||||
|
||||
if delta == 0 {
|
||||
return false;
|
||||
}
|
||||
|
||||
self.last_update_time += delta << 10;
|
||||
|
||||
if load == 0 {
|
||||
runnable = 0;
|
||||
running = 0;
|
||||
}
|
||||
|
||||
self.accumulate_sum(delta, load, runnable, running) != 0
|
||||
}
|
||||
|
||||
pub fn accumulate_sum(
|
||||
&mut self,
|
||||
mut delta: u64,
|
||||
load: u32,
|
||||
runnable: u32,
|
||||
running: u32,
|
||||
) -> u64 {
|
||||
let mut contrib = delta as u32;
|
||||
|
||||
delta += self.period_contrib as u64;
|
||||
|
||||
let periods = delta / 1024;
|
||||
|
||||
if periods > 0 {
|
||||
self.load_sum = Self::decay_load(self.load_sum, periods);
|
||||
self.runnable_sum = Self::decay_load(self.runnable_sum, periods);
|
||||
self.util_sum = Self::decay_load(self.util_sum, periods);
|
||||
|
||||
delta %= 1024;
|
||||
if load > 0 {
|
||||
contrib = Self::accumulate_pelt_segments(
|
||||
periods,
|
||||
1024 - self.period_contrib,
|
||||
delta as u32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self.period_contrib = delta as u32;
|
||||
|
||||
if load > 0 {
|
||||
self.load_sum += (contrib * load) as u64;
|
||||
}
|
||||
if runnable > 0 {
|
||||
self.runnable_sum += (runnable & contrib << SCHED_CAPACITY_SHIFT) as u64;
|
||||
}
|
||||
|
||||
if running > 0 {
|
||||
self.util_sum += (contrib << SCHED_CAPACITY_SHIFT) as u64;
|
||||
}
|
||||
|
||||
return periods;
|
||||
}
|
||||
|
||||
fn decay_load(mut val: u64, n: u64) -> u64 {
|
||||
if unlikely(n > LOAD_AVG_PERIOD) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut local_n = n;
|
||||
|
||||
if unlikely(local_n >= LOAD_AVG_PERIOD) {
|
||||
val >>= local_n / LOAD_AVG_PERIOD;
|
||||
local_n %= LOAD_AVG_PERIOD;
|
||||
}
|
||||
|
||||
((val as i128 * RUNNABLE_AVG_Y_N_INV[local_n as usize] as i128) >> 32) as u64
|
||||
}
|
||||
|
||||
fn accumulate_pelt_segments(periods: u64, d1: u32, d3: u32) -> u32 {
|
||||
/* y^0 == 1 */
|
||||
let c3 = d3;
|
||||
|
||||
/*
|
||||
* c1 = d1 y^p
|
||||
*/
|
||||
let c1 = Self::decay_load(d1 as u64, periods) as u32;
|
||||
|
||||
/*
|
||||
* p-1
|
||||
* c2 = 1024 \Sum y^n
|
||||
* n=1
|
||||
*
|
||||
* inf inf
|
||||
* = 1024 ( \Sum y^n - \Sum y^n - y^0 )
|
||||
* n=0 n=p
|
||||
*/
|
||||
let c2 = LOAD_AVG_MAX as u32 - Self::decay_load(LOAD_AVG_MAX as u64, periods) as u32 - 1024;
|
||||
|
||||
return c1 + c2 + c3;
|
||||
}
|
||||
|
||||
pub fn update_load_avg(&mut self, load: u64) {
|
||||
let divider = self.get_pelt_divider();
|
||||
|
||||
self.load_avg = (load * self.load_sum) as usize / divider;
|
||||
self.runnable_avg = self.runnable_sum as usize / divider;
|
||||
self.util_avg = self.util_sum as usize / divider;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn post_init_entity_util_avg(pcb: &Arc<ProcessControlBlock>) {
|
||||
let se = pcb.sched_info().sched_entity();
|
||||
let cfs_rq = se.cfs_rq();
|
||||
let sa = &mut se.force_mut().avg;
|
||||
|
||||
// TODO: 这里和架构相关
|
||||
let cpu_scale = SCHED_CAPACITY_SCALE;
|
||||
|
||||
let cap = (cpu_scale as isize - cfs_rq.avg.util_avg as isize) / 2;
|
||||
|
||||
if pcb.sched_info().policy() != SchedPolicy::CFS {
|
||||
sa.last_update_time = cfs_rq.cfs_rq_clock_pelt();
|
||||
}
|
||||
|
||||
if cap > 0 {
|
||||
if cfs_rq.avg.util_avg != 0 {
|
||||
sa.util_avg = cfs_rq.avg.util_avg * se.load.weight as usize;
|
||||
sa.util_avg /= cfs_rq.avg.load_avg + 1;
|
||||
|
||||
if sa.util_avg as isize > cap {
|
||||
sa.util_avg = cap as usize;
|
||||
}
|
||||
} else {
|
||||
sa.util_avg = cap as usize;
|
||||
}
|
||||
}
|
||||
|
||||
sa.runnable_avg = sa.util_avg;
|
||||
}
|
||||
}
|
||||
|
||||
impl CpuRunQueue {
|
||||
pub fn rq_clock_pelt(&self) -> u64 {
|
||||
self.clock_pelt - self.lost_idle_time
|
||||
}
|
||||
}
|
||||
|
||||
impl CfsRunQueue {
|
||||
pub fn cfs_rq_clock_pelt(&self) -> u64 {
|
||||
if unlikely(self.throttled_count > 0) {
|
||||
return self.throttled_clock_pelt - self.throttled_clock_pelt_time;
|
||||
}
|
||||
|
||||
let rq = self.rq();
|
||||
let (rq, _guard) = rq.self_lock();
|
||||
|
||||
return rq.rq_clock_pelt() - self.throttled_clock_pelt_time;
|
||||
}
|
||||
}
|
||||
|
||||
impl FairSchedEntity {
|
||||
pub fn update_load_avg(&mut self, cfs_rq: &mut CfsRunQueue, now: u64) -> bool {
|
||||
if self.avg.update_load_sum(
|
||||
now,
|
||||
self.on_rq as u32,
|
||||
self.runnable() as u32,
|
||||
cfs_rq.is_curr(&self.self_arc()) as u32,
|
||||
) {
|
||||
self.avg
|
||||
.update_load_avg(LoadWeight::scale_load_down(self.load.weight));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct UpdateAvgFlags: u8 {
|
||||
/// 更新任务组(task group)信息
|
||||
const UPDATE_TG = 0x1;
|
||||
|
||||
/// 跳过年龄和负载的更新
|
||||
const SKIP_AGE_LOAD = 0x2;
|
||||
/// 执行附加操作
|
||||
const DO_ATTACH = 0x4;
|
||||
/// 执行分离操作
|
||||
const DO_DETACH = 0x8;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_positive(x: &mut isize, y: isize) {
|
||||
let res = *x + y;
|
||||
*x = res.max(0);
|
||||
}
|
||||
|
||||
pub fn sub_positive(x: &mut usize, y: usize) {
|
||||
if *x > y {
|
||||
*x -= y;
|
||||
} else {
|
||||
*x = 0;
|
||||
}
|
||||
}
|
33
kernel/src/sched/prio.rs
Normal file
33
kernel/src/sched/prio.rs
Normal file
@ -0,0 +1,33 @@
|
||||
pub const MAX_NICE: i32 = 20;
|
||||
pub const MIN_NICE: i32 = -20;
|
||||
pub const NICE_WIDTH: i32 = MAX_NICE - MIN_NICE + 1;
|
||||
|
||||
pub const MAX_RT_PRIO: i32 = 100;
|
||||
pub const MAX_PRIO: i32 = MAX_RT_PRIO + NICE_WIDTH;
|
||||
#[allow(dead_code)]
|
||||
pub const DEFAULT_PRIO: i32 = MAX_RT_PRIO + NICE_WIDTH / 2;
|
||||
|
||||
pub const MAX_DL_PRIO: i32 = 0;
|
||||
pub struct PrioUtil;
|
||||
#[allow(dead_code)]
|
||||
impl PrioUtil {
|
||||
#[inline]
|
||||
pub fn nice_to_prio(nice: i32) -> i32 {
|
||||
nice + DEFAULT_PRIO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn prio_to_nice(prio: i32) -> i32 {
|
||||
prio - DEFAULT_PRIO
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn dl_prio(prio: i32) -> bool {
|
||||
return prio < MAX_DL_PRIO;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn rt_prio(prio: i32) -> bool {
|
||||
return prio < MAX_RT_PRIO;
|
||||
}
|
||||
}
|
@ -1,235 +0,0 @@
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
use alloc::{boxed::Box, collections::LinkedList, sync::Arc, vec::Vec};
|
||||
|
||||
use crate::{
|
||||
arch::cpu::current_cpu_id,
|
||||
kBUG, kdebug,
|
||||
libs::spinlock::SpinLock,
|
||||
mm::percpu::PerCpu,
|
||||
process::{ProcessControlBlock, ProcessFlags, ProcessManager},
|
||||
smp::cpu::ProcessorId,
|
||||
};
|
||||
|
||||
use super::{
|
||||
core::{sched_enqueue, Scheduler},
|
||||
SchedPolicy,
|
||||
};
|
||||
|
||||
/// 声明全局的rt调度器实例
|
||||
pub static mut RT_SCHEDULER_PTR: Option<Box<SchedulerRT>> = None;
|
||||
|
||||
/// @brief 获取rt调度器实例的可变引用
|
||||
#[inline]
|
||||
pub fn __get_rt_scheduler() -> &'static mut SchedulerRT {
|
||||
return unsafe { RT_SCHEDULER_PTR.as_mut().unwrap() };
|
||||
}
|
||||
|
||||
/// @brief 初始化rt调度器
|
||||
pub unsafe fn sched_rt_init() {
|
||||
kdebug!("rt scheduler init");
|
||||
if RT_SCHEDULER_PTR.is_none() {
|
||||
RT_SCHEDULER_PTR = Some(Box::new(SchedulerRT::new()));
|
||||
} else {
|
||||
kBUG!("Try to init RT Scheduler twice.");
|
||||
panic!("Try to init RT Scheduler twice.");
|
||||
}
|
||||
}
|
||||
/// @brief RT队列(per-cpu的)
|
||||
#[derive(Debug)]
|
||||
struct RTQueue {
|
||||
/// 加锁保护的存储进程的双向队列
|
||||
locked_queue: SpinLock<LinkedList<Arc<ProcessControlBlock>>>,
|
||||
}
|
||||
|
||||
impl RTQueue {
|
||||
pub fn new() -> RTQueue {
|
||||
RTQueue {
|
||||
locked_queue: SpinLock::new(LinkedList::new()),
|
||||
}
|
||||
}
|
||||
/// @brief 将pcb加入队列
|
||||
pub fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let mut queue = self.locked_queue.lock_irqsave();
|
||||
|
||||
// 如果进程是IDLE进程,那么就不加入队列
|
||||
if pcb.pid().into() == 0 {
|
||||
return;
|
||||
}
|
||||
queue.push_back(pcb);
|
||||
}
|
||||
|
||||
/// @brief 将pcb从调度队列头部取出,若队列为空,则返回None
|
||||
pub fn dequeue(&mut self) -> Option<Arc<ProcessControlBlock>> {
|
||||
let res: Option<Arc<ProcessControlBlock>>;
|
||||
let mut queue = self.locked_queue.lock_irqsave();
|
||||
if queue.len() > 0 {
|
||||
// 队列不为空,返回下一个要执行的pcb
|
||||
res = Some(queue.pop_front().unwrap());
|
||||
} else {
|
||||
// 如果队列为空,则返回None
|
||||
res = None;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
pub fn enqueue_front(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let mut queue = self.locked_queue.lock_irqsave();
|
||||
|
||||
// 如果进程是IDLE进程,那么就不加入队列
|
||||
if pcb.pid().into() == 0 {
|
||||
return;
|
||||
}
|
||||
queue.push_front(pcb);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn get_rt_queue_size(&mut self) -> usize {
|
||||
let queue = self.locked_queue.lock_irqsave();
|
||||
return queue.len();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief RT调度器类
|
||||
pub struct SchedulerRT {
|
||||
cpu_queue: Vec<Vec<&'static mut RTQueue>>,
|
||||
load_list: Vec<&'static mut LinkedList<u64>>,
|
||||
}
|
||||
|
||||
impl SchedulerRT {
|
||||
const RR_TIMESLICE: isize = 100;
|
||||
const MAX_RT_PRIO: isize = 100;
|
||||
|
||||
pub fn new() -> SchedulerRT {
|
||||
// 暂时手动指定核心数目
|
||||
// todo: 从cpu模块来获取核心的数目
|
||||
let mut result = SchedulerRT {
|
||||
cpu_queue: Default::default(),
|
||||
load_list: Default::default(),
|
||||
};
|
||||
|
||||
// 为每个cpu核心创建队列
|
||||
for cpu_id in 0..PerCpu::MAX_CPU_NUM {
|
||||
result.cpu_queue.push(Vec::new());
|
||||
// 每个CPU有MAX_RT_PRIO个优先级队列
|
||||
for _ in 0..SchedulerRT::MAX_RT_PRIO {
|
||||
result.cpu_queue[cpu_id as usize].push(Box::leak(Box::new(RTQueue::new())));
|
||||
}
|
||||
}
|
||||
// 为每个cpu核心创建负载统计队列
|
||||
for _ in 0..PerCpu::MAX_CPU_NUM {
|
||||
result.load_list.push(Box::leak(Box::default()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// @brief 挑选下一个可执行的rt进程
|
||||
pub fn pick_next_task_rt(&mut self, cpu_id: ProcessorId) -> Option<Arc<ProcessControlBlock>> {
|
||||
// 循环查找,直到找到
|
||||
// 这里应该是优先级数量,而不是CPU数量,需要修改
|
||||
for i in 0..SchedulerRT::MAX_RT_PRIO {
|
||||
let cpu_queue_i: &mut RTQueue = self.cpu_queue[cpu_id.data() as usize][i as usize];
|
||||
let proc: Option<Arc<ProcessControlBlock>> = cpu_queue_i.dequeue();
|
||||
if proc.is_some() {
|
||||
return proc;
|
||||
}
|
||||
}
|
||||
// return 一个空值
|
||||
None
|
||||
}
|
||||
|
||||
pub fn rt_queue_len(&mut self, cpu_id: ProcessorId) -> usize {
|
||||
let mut sum = 0;
|
||||
for prio in 0..SchedulerRT::MAX_RT_PRIO {
|
||||
sum += self.cpu_queue[cpu_id.data() as usize][prio as usize].get_rt_queue_size();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[inline]
|
||||
pub fn load_list_len(&mut self, cpu_id: u32) -> usize {
|
||||
return self.load_list[cpu_id as usize].len();
|
||||
}
|
||||
|
||||
pub fn enqueue_front(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_id = current_cpu_id().data() as usize;
|
||||
let priority = pcb.sched_info().priority().data() as usize;
|
||||
|
||||
self.cpu_queue[cpu_id][priority].enqueue_front(pcb);
|
||||
}
|
||||
|
||||
pub fn timer_update_jiffies(&self) {
|
||||
ProcessManager::current_pcb()
|
||||
.sched_info()
|
||||
.increase_rt_time_slice(-1);
|
||||
}
|
||||
}
|
||||
|
||||
impl Scheduler for SchedulerRT {
|
||||
/// @brief 在当前cpu上进行调度。
|
||||
/// 请注意,进入该函数之前,需要关中断
|
||||
fn sched(&mut self) -> Option<Arc<ProcessControlBlock>> {
|
||||
ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.remove(ProcessFlags::NEED_SCHEDULE);
|
||||
// 正常流程下,这里一定是会pick到next的pcb的,如果是None的话,要抛出错误
|
||||
let cpu_id = current_cpu_id();
|
||||
let proc: Arc<ProcessControlBlock> =
|
||||
self.pick_next_task_rt(cpu_id).expect("No RT process found");
|
||||
let priority = proc.sched_info().priority();
|
||||
let policy = proc.sched_info().inner_lock_read_irqsave().policy();
|
||||
match policy {
|
||||
// 如果是fifo策略,则可以一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)
|
||||
SchedPolicy::FIFO => {
|
||||
// 如果挑选的进程优先级小于当前进程,则不进行切换
|
||||
if proc.sched_info().priority()
|
||||
<= ProcessManager::current_pcb().sched_info().priority()
|
||||
{
|
||||
sched_enqueue(proc, false);
|
||||
} else {
|
||||
// 将当前的进程加进队列
|
||||
sched_enqueue(ProcessManager::current_pcb(), false);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
return Some(proc);
|
||||
}
|
||||
}
|
||||
|
||||
// RR调度策略需要考虑时间片
|
||||
SchedPolicy::RR => {
|
||||
// 同等优先级的,考虑切换
|
||||
if proc.sched_info().priority()
|
||||
>= ProcessManager::current_pcb().sched_info().priority()
|
||||
{
|
||||
// 判断这个进程时间片是否耗尽,若耗尽则将其时间片赋初值然后入队
|
||||
if proc.sched_info().rt_time_slice() <= 0 {
|
||||
proc.sched_info()
|
||||
.set_rt_time_slice(SchedulerRT::RR_TIMESLICE);
|
||||
proc.flags().insert(ProcessFlags::NEED_SCHEDULE);
|
||||
sched_enqueue(proc, false);
|
||||
}
|
||||
// 目标进程时间片未耗尽,切换到目标进程
|
||||
else {
|
||||
// 将当前进程加进队列
|
||||
sched_enqueue(ProcessManager::current_pcb(), false);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
return Some(proc);
|
||||
}
|
||||
}
|
||||
// curr优先级更大,说明一定是实时进程,将所选进程入队列,此时需要入队首
|
||||
else {
|
||||
self.cpu_queue[cpu_id.data() as usize][priority.data() as usize]
|
||||
.enqueue_front(proc);
|
||||
}
|
||||
}
|
||||
_ => panic!("unsupported schedule policy"),
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn enqueue(&mut self, pcb: Arc<ProcessControlBlock>) {
|
||||
let cpu_id = pcb.sched_info().on_cpu().unwrap();
|
||||
let cpu_queue = &mut self.cpu_queue[cpu_id.data() as usize];
|
||||
let priority = pcb.sched_info().priority().data() as usize;
|
||||
cpu_queue[priority].enqueue(pcb);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <process/process.h>
|
||||
|
||||
/*
|
||||
* Scheduling policies
|
||||
*/
|
||||
#define SCHED_NORMAL 0
|
||||
#define SCHED_FIFO 1
|
||||
#define SCHED_RR 2
|
||||
#define SCHED_BATCH 3
|
||||
/* SCHED_ISO: reserved but not implemented yet */
|
||||
#define SCHED_IDLE 5
|
||||
#define SCHED_DEADLINE 6
|
||||
#define SCHED_MAX_POLICY_NUM SCHED_DEADLINE
|
||||
|
||||
#define IS_VALID_SCHED_POLICY(_policy) ((_policy) > 0 && (_policy) <= SCHED_MAX_POLICY_NUM)
|
||||
|
||||
// ================= Rust 实现 =============
|
||||
|
||||
extern void sched_init();
|
||||
extern void sched();
|
@ -1,39 +0,0 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch, exception::InterruptArch, process::ProcessManager,
|
||||
smp::core::smp_get_processor_id, syscall::Syscall,
|
||||
};
|
||||
|
||||
use super::core::{do_sched, CPU_EXECUTING};
|
||||
|
||||
impl Syscall {
|
||||
/// @brief 让系统立即运行调度器的系统调用
|
||||
/// 请注意,该系统调用不能由ring3的程序发起
|
||||
#[inline(always)]
|
||||
pub fn sched(from_user: bool) -> Result<usize, SystemError> {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
|
||||
// 进行权限校验,拒绝用户态发起调度
|
||||
if from_user {
|
||||
return Err(SystemError::EPERM);
|
||||
}
|
||||
// 根据调度结果统一进行切换
|
||||
let pcb = do_sched();
|
||||
|
||||
if let Some(next_pcb) = pcb {
|
||||
let current_pcb = ProcessManager::current_pcb();
|
||||
// kdebug!("sched: current_pcb: {:?}, next_pcb: {:?}\n", current_pcb, next_pcb);
|
||||
if current_pcb.pid() != next_pcb.pid() {
|
||||
CPU_EXECUTING.set(smp_get_processor_id(), next_pcb.pid());
|
||||
unsafe { ProcessManager::switch_process(current_pcb, next_pcb) };
|
||||
}
|
||||
}
|
||||
drop(irq_guard);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn sched_yield() -> Result<usize, SystemError> {
|
||||
return Syscall::sched(false);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ use core::{
|
||||
|
||||
use crate::{
|
||||
arch::{ipc::signal::SigSet, syscall::nr::*},
|
||||
driver::base::device::device_number::DeviceNumber,
|
||||
filesystem::vfs::syscall::{PosixStatfs, PosixStatx},
|
||||
libs::{futex::constant::FutexFlag, rand::GRandFlags},
|
||||
mm::syscall::MremapFlags,
|
||||
@ -13,8 +14,9 @@ use crate::{
|
||||
process::{
|
||||
fork::KernelCloneArgs,
|
||||
resource::{RLimit64, RUsage},
|
||||
ProcessManager,
|
||||
ProcessFlags, ProcessManager,
|
||||
},
|
||||
sched::{schedule, SchedMode},
|
||||
syscall::user_access::check_and_clone_cstr,
|
||||
};
|
||||
|
||||
@ -381,7 +383,11 @@ impl Syscall {
|
||||
|
||||
SYS_GETPID => Self::getpid().map(|pid| pid.into()),
|
||||
|
||||
SYS_SCHED => Self::sched(frame.is_from_user()),
|
||||
SYS_SCHED => {
|
||||
kwarn!("syscall sched");
|
||||
schedule(SchedMode::SM_NONE);
|
||||
Ok(0)
|
||||
}
|
||||
SYS_DUP => {
|
||||
let oldfd: i32 = args[0] as c_int;
|
||||
Self::dup(oldfd)
|
||||
@ -652,8 +658,6 @@ impl Syscall {
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
SYS_MKNOD => {
|
||||
use crate::driver::base::device::device_number::DeviceNumber;
|
||||
|
||||
let path = args[0];
|
||||
let flags = args[1];
|
||||
let dev_t = args[2];
|
||||
@ -1019,7 +1023,7 @@ impl Syscall {
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
SYS_SCHED_YIELD => Self::sched_yield(),
|
||||
// SYS_SCHED_YIELD => Self::sched_yield(),
|
||||
SYS_UNAME => {
|
||||
let name = args[0] as *mut PosixOldUtsName;
|
||||
Self::uname(name)
|
||||
@ -1028,6 +1032,13 @@ impl Syscall {
|
||||
_ => panic!("Unsupported syscall ID: {}", syscall_num),
|
||||
};
|
||||
|
||||
if ProcessManager::current_pcb()
|
||||
.flags()
|
||||
.contains(ProcessFlags::NEED_SCHEDULE)
|
||||
{
|
||||
schedule(SchedMode::SM_PREEMPT);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::InterruptArch,
|
||||
init::initcall::INITCALL_LATE,
|
||||
kdebug, kinfo,
|
||||
@ -24,6 +24,7 @@ use crate::{
|
||||
kthread::{KernelThreadClosure, KernelThreadMechanism},
|
||||
ProcessControlBlock, ProcessManager,
|
||||
},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -823,7 +824,7 @@ pub fn clocksource_watchdog_kthread() -> i32 {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
ProcessManager::mark_sleep(true).expect("clocksource_watchdog_kthread:mark sleep failed");
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ lazy_static! {
|
||||
pub const JIFFIES_SHIFT: u32 = 8;
|
||||
pub const LATCH: u32 = (CLOCK_TICK_RATE + (HZ as u32) / 2) / HZ as u32;
|
||||
pub const ACTHZ: u32 = sh_div(CLOCK_TICK_RATE, LATCH, 8);
|
||||
pub const TICK_NESC: u32 = (NSEC_PER_SEC + (HZ as u32) / 2) / HZ as u32;
|
||||
//TODO 编写测试,保证始终跳动间隔与现实一致(两种时钟源进行对拍)
|
||||
pub const NSEC_PER_JIFFY: u32 = (((NSEC_PER_SEC as u64) << 8) / ACTHZ as u64) as u32;
|
||||
pub const fn sh_div(nom: u32, den: u32, lsh: u32) -> u32 {
|
||||
|
@ -4,10 +4,11 @@ use alloc::{boxed::Box, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch, CurrentTimeArch},
|
||||
arch::{CurrentIrqArch, CurrentTimeArch},
|
||||
exception::InterruptArch,
|
||||
include::bindings::bindings::useconds_t,
|
||||
process::ProcessManager,
|
||||
sched::{schedule, SchedMode},
|
||||
time::timekeeping::getnstimeofday,
|
||||
};
|
||||
|
||||
@ -53,7 +54,7 @@ pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
|
||||
timer.activate();
|
||||
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_NONE);
|
||||
|
||||
let end_time = getnstimeofday();
|
||||
// 返回正确的剩余时间
|
||||
|
@ -12,7 +12,7 @@ use alloc::{
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{sched::sched, CurrentIrqArch},
|
||||
arch::CurrentIrqArch,
|
||||
exception::{
|
||||
softirq::{softirq_vectors, SoftirqNumber, SoftirqVec},
|
||||
InterruptArch,
|
||||
@ -20,6 +20,7 @@ use crate::{
|
||||
kerror, kinfo,
|
||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
||||
process::{ProcessControlBlock, ProcessManager},
|
||||
sched::{schedule, SchedMode},
|
||||
};
|
||||
|
||||
use super::{jiffies::NSEC_PER_JIFFY, timekeeping::update_wall_time};
|
||||
@ -258,7 +259,7 @@ pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
ProcessManager::mark_sleep(true).ok();
|
||||
drop(irq_guard);
|
||||
sched();
|
||||
schedule(SchedMode::SM_PREEMPT);
|
||||
return Ok(MAX_TIMEOUT);
|
||||
} else if timeout < 0 {
|
||||
kerror!("timeout can't less than 0");
|
||||
@ -277,7 +278,7 @@ pub fn schedule_timeout(mut timeout: i64) -> Result<i64, SystemError> {
|
||||
|
||||
drop(irq_guard);
|
||||
|
||||
sched();
|
||||
schedule(SchedMode::SM_PREEMPT);
|
||||
let time_remaining: i64 = timeout - TIMER_JIFFIES.load(Ordering::SeqCst) as i64;
|
||||
if time_remaining >= 0 {
|
||||
// 被提前唤醒,返回剩余时间
|
||||
|
Loading…
x
Reference in New Issue
Block a user