重写调度模块 (#679)

## PR:重写调度模块
--- 
### 完成的部分
- 实现cfs调度策略
- 搭建框架,后续功能可以迭代开发
- 目前能跑,未测试性能

### 需要后续接力的部分
- 实现组内调度(task_group)
- 实现跨核负载均衡(pelt算法)
- 接入sysfs,实现参数动态调节(sched_stat等)
- nice值以及priority等参数的设置及调优
This commit is contained in:
GnoCiYeH 2024-04-05 17:54:48 +08:00 committed by GitHub
parent e8eab1ac82
commit f0c87a897f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
44 changed files with 3733 additions and 1066 deletions

View File

@ -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);
}
}

View File

@ -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 版本

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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 暂停进程
}
/// 信号默认处理函数——继续进程

View File

@ -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();

View File

@ -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 */
// }
// }

View File

@ -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;

View File

@ -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() });
}

View File

@ -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)
}
}

View File

@ -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);
}

View File

@ -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()

View File

@ -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>

View File

@ -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();

View File

@ -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();
}

View File

@ -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();

View File

@ -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 放锁。

View File

@ -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]);
}
}

View File

@ -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来获取临界区数据的不可变引用

View File

@ -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的进程

View File

@ -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 {

View File

@ -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 {

View File

@ -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);

View File

@ -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(())
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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, &current_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, &current_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
View 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;
}
}

View File

@ -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
View 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

File diff suppressed because it is too large Load Diff

67
kernel/src/sched/idle.rs Normal file
View 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
View 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
View 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;
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 {

View File

@ -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();
// 返回正确的剩余时间

View File

@ -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 {
// 被提前唤醒,返回剩余时间