Patch sched rust (#139)

* update

* 添加rt调度器的rust初步实现

* 完善rt调度逻辑

* 调试rt调度器

* 修改sched的返回值

* cargo fmt 格式化

* 删除无用代码,修补rt bug

* 删除无用的代码,和重复的逻辑

* 软中断bugfix

* 删除一些代码

* 添加kthread_run_rt文档

* 解决sphinix警告_static目录不存在的问题

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
kong 2023-01-14 22:38:05 +08:00 committed by GitHub
parent ec53d23ed0
commit 06b09f34ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 426 additions and 173 deletions

0
docs/_static/.gitkeep vendored Normal file
View File

View File

@ -62,6 +62,18 @@
&emsp;&emsp;该宏定义是`kthread_create()`的简单封装,提供创建了内核线程后,立即运行的功能。
### kthread_run_rt()
#### 原型
&emsp;&emsp;`kthread_run_rt(thread_fn, data, name_fmt, ...)`
#### 简介
&emsp;&emsp;创建内核实时线程并加入调度队列。
&emsp;&emsp;类似`kthread_run()`,该宏定义也是`kthread_create()`的简单封装,提供创建了内核实时线程后,在设置实时进程的参数后,立即运行的功能。
## 停止内核线程
### kthread_stop()

View File

@ -2,7 +2,7 @@ use core::arch::x86_64::_popcnt64;
/// @brief ffz - 寻找u64中的第一个0所在的位从第0位开始寻找
/// 请注意如果x中没有0,那么结果将是未定义的。请确保传入的x至少存在1个0
///
///
/// @param x 目标u64
/// @return i32 bit-number(0..63) of the first (least significant) zero bit.
#[inline]

View File

@ -1,6 +1,6 @@
pub mod irqflags;
#[macro_use]
pub mod current;
pub mod ptrace;
pub mod bitops;
pub mod cmpxchg;
pub mod cmpxchg;
pub mod ptrace;

View File

@ -3,10 +3,10 @@ use crate::include::bindings::bindings::pt_regs;
/// @brief 判断给定的栈帧是否来自用户态
/// 判断方法为根据代码段选择子是否具有ring3的访问权限低2bit均为1
pub fn user_mode(regs: *const pt_regs)->bool{
if (unsafe{(*regs).cs} & 0x3) != 0{
pub fn user_mode(regs: *const pt_regs) -> bool {
if (unsafe { (*regs).cs } & 0x3) != 0 {
return true;
}else {
} else {
return false;
}
}
}

View File

@ -3,16 +3,16 @@ use core::arch::asm;
/// @brief 关闭中断
#[inline]
pub fn cli(){
unsafe{
pub fn cli() {
unsafe {
asm!("cli");
}
}
/// @brief 开启中断
#[inline]
pub fn sti(){
unsafe{
pub fn sti() {
unsafe {
asm!("sti");
}
}
}

View File

@ -2,22 +2,22 @@
use core::arch::asm;
#[inline(always)]
pub fn mfence(){
unsafe{
pub fn mfence() {
unsafe {
asm!("mfence");
}
}
#[inline(always)]
pub fn lfence(){
unsafe{
pub fn lfence() {
unsafe {
asm!("lfence");
}
}
#[inline(always)]
pub fn sfence(){
unsafe{
pub fn sfence() {
unsafe {
asm!("sfence");
}
}
}

View File

@ -19,7 +19,7 @@ pub fn switch_mm(
mfence();
// kdebug!("to get pml4t");
let pml4t = unsafe { read_volatile(&next_pcb.mm.as_ref().unwrap().pgd) };
unsafe {
asm!("mov cr3, {}", in(reg) pml4t);
}

View File

@ -1,7 +1,7 @@
#[macro_use]
pub mod asm;
pub mod context;
pub mod cpu;
pub mod interrupt;
pub mod mm;
pub mod context;
pub mod sched;
pub mod sched;

View File

@ -54,6 +54,23 @@ struct process_control_block *kthread_create_on_node(int (*thread_fn)(void *data
__kt; \
})
/**
* @brief 线
*
* @param thread_fn 线
* @param data thread_fn
* @param name_fmt printf-style format string for the thread name
* @param arg name_fmt的参数
*/
#define kthread_run_rt(thread_fn, data, name_fmt, ...) \
({ \
struct process_control_block *__kt = kthread_create(thread_fn, data, name_fmt, ##__VA_ARGS__); \
__kt=process_init_rt_pcb(__kt); \
if (!IS_ERR(__kt)){ \
process_wakeup(__kt);} \
__kt; \
})
/**
* @brief kthread发送停止信号
*

View File

@ -1,2 +1,2 @@
pub mod uart;
pub mod timers;
pub mod uart;

View File

@ -1 +1 @@
pub mod rtc;
pub mod rtc;

View File

@ -1 +1 @@
pub mod rtc;
pub mod rtc;

View File

@ -1,5 +1,5 @@
use crate::include::bindings::bindings::{io_in8, io_out8};
use core::{str, char, intrinsics::offset};
use core::{char, intrinsics::offset, str};
const UART_SUCCESS: i32 = 0;
const E_UART_BITS_RATE_ERROR: i32 = 1;
@ -63,7 +63,7 @@ impl UartPort {
struct UartRegister {
reg_data: u8,
reg_interrupt_enable: u8,
reg_ii_fifo: u8, // Interrupt Identification and FIFO control registers
reg_ii_fifo: u8, // Interrupt Identification and FIFO control registers
reg_line_config: u8,
reg_modem_config: u8,
reg_line_status: u8,
@ -79,7 +79,10 @@ pub struct UartDriver {
impl Default for UartDriver {
fn default() -> Self {
Self {port: UartPort::COM1, baud_rate: 115200}
Self {
port: UartPort::COM1,
baud_rate: 115200,
}
}
}
@ -96,26 +99,26 @@ impl UartDriver {
if baud_rate > UART_MAX_BITS_RATE || UART_MAX_BITS_RATE % baud_rate != 0 {
return Err("uart init error.");
}
unsafe {
io_out8(port + 1, 0x00); // Disable all interrupts
io_out8(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
let divisor = UART_MAX_BITS_RATE / baud_rate;
io_out8(port + 0, (divisor & 0xff) as u8); // Set divisor (lo byte)
io_out8(port + 0, (divisor & 0xff) as u8); // Set divisor (lo byte)
io_out8(port + 1, ((divisor >> 8) & 0xff) as u8); // (hi byte)
io_out8(port + 3, 0x03); // 8 bits, no parity, one stop bit
io_out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
io_out8(port + 3, 0x03); // 8 bits, no parity, one stop bit
io_out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
io_out8(port + 4, 0x08); // IRQs enabled, RTS/DSR clear (现代计算机上一般都不需要hardware flow control因此不需要置位RTS/DSR)
io_out8(port + 4, 0x1E); // Set in loopback mode, test the serial chip
io_out8(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if io_in8(port + 0) != 0xAE {
return Err("uart faulty");
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
io_out8(port + 4, 0x08);
@ -133,15 +136,15 @@ impl UartDriver {
}
fn serial_received(offset: u16) -> bool {
if unsafe{ io_in8(offset + 5) } & 1 != 0 {
if unsafe { io_in8(offset + 5) } & 1 != 0 {
true
} else {
false
}
}
fn is_transmit_empty(offset: u16) -> bool {
if unsafe{ io_in8(offset + 5) } & 0x20 != 0 {
if unsafe { io_in8(offset + 5) } & 0x20 != 0 {
true
} else {
false
@ -157,11 +160,13 @@ impl UartDriver {
let port = uart_port.to_u16();
while UartDriver::is_transmit_empty(port) == false {
for c in str.bytes() {
unsafe { io_out8(port, c); }
unsafe {
io_out8(port, c);
}
}
} //TODO:pause
}
/// @brief 串口接收一个字节
/// @param uart_port 端口号
/// @return 接收的字节
@ -171,7 +176,6 @@ impl UartDriver {
while UartDriver::serial_received(port) == false {} //TODO:pause
unsafe { io_in8(port) as char }
}
}
///@brief 发送数据
@ -180,7 +184,9 @@ impl UartDriver {
#[no_mangle]
pub extern "C" fn c_uart_send(port: u16, c: u8) {
while UartDriver::is_transmit_empty(port) == false {} //TODO:pause
unsafe { io_out8(port, c); }
unsafe {
io_out8(port, c);
}
}
///@brief 从uart接收数据
@ -196,8 +202,7 @@ pub extern "C" fn c_uart_read(port: u16) -> u8 {
///@param port 串口端口
///@param str 字符串S
#[no_mangle]
pub extern "C" fn c_uart_send_str(port: u16, str: *const u8)
{
pub extern "C" fn c_uart_send_str(port: u16, str: *const u8) {
unsafe {
let mut i = 0;
while *offset(str, i) != '\0' as u8 {
@ -222,22 +227,22 @@ pub extern "C" fn c_uart_init(port: u16, baud_rate: u32) -> i32 {
unsafe {
io_out8(port + 1, 0x00); // Disable all interrupts
io_out8(port + 3, 0x80); // Enable DLAB (set baud rate divisor)
let divisor = UART_MAX_BITS_RATE / baud_rate;
io_out8(port + 0, (divisor & 0xff) as u8); // Set divisor (lo byte)
io_out8(port + 0, (divisor & 0xff) as u8); // Set divisor (lo byte)
io_out8(port + 1, ((divisor >> 8) & 0xff) as u8); // (hi byte)
io_out8(port + 3, 0x03); // 8 bits, no parity, one stop bit
io_out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
io_out8(port + 3, 0x03); // 8 bits, no parity, one stop bit
io_out8(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
io_out8(port + 4, 0x08); // IRQs enabled, RTS/DSR clear (现代计算机上一般都不需要hardware flow control因此不需要置位RTS/DSR)
io_out8(port + 4, 0x1E); // Set in loopback mode, test the serial chip
io_out8(port + 0, 0xAE); // Test serial chip (send byte 0xAE and check if serial returns same byte)
// Check if serial is faulty (i.e: not same byte as sent)
if io_in8(port + 0) != 0xAE {
return -E_UART_SERIAL_FAULT;
}
// If serial is not faulty set it in normal operation mode
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
io_out8(port + 4, 0x08);

View File

@ -14,11 +14,9 @@
// ==================implementation with rust===================
extern void softirq_init();
extern void raise_softirq(uint64_t sirq_num);
extern void raise_softirq(uint32_t sirq_num);
extern int register_softirq(uint32_t irq_num, void (*action)(void *data), void *data);
extern int unregister_softirq(uint32_t irq_num);
extern void set_softirq_pending(uint64_t status);
extern void clear_softirq_pending(uint32_t irq_num);
extern void do_softirq();
// for temporary

View File

@ -66,9 +66,9 @@ pub fn __get_softirq_handler_mut() -> &'static mut Softirq {
#[no_mangle]
#[allow(dead_code)]
pub extern "C" fn raise_softirq(sirq_num: u64) {
pub extern "C" fn raise_softirq(sirq_num: u32) {
let softirq_handler = __get_softirq_handler_mut();
softirq_handler.set_softirq_pending(1 << sirq_num);
softirq_handler.set_softirq_pending(sirq_num);
}
/// @brief 软中断注册函数

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -1 +1 @@
pub mod bindings;
pub mod bindings;

View File

@ -1,2 +1,2 @@
#![allow(non_snake_case)]
pub mod bindings;
pub mod bindings;

View File

@ -1,2 +1,2 @@
pub mod signal;
pub mod signal_types;
pub mod signal_types;

View File

@ -546,7 +546,7 @@ impl SigQueue {
}
/// @brief 从C的void*指针转换为static生命周期的可变引用
pub fn from_c_void(p: *mut c_void) -> &'static mut SigQueue{
pub fn from_c_void(p: *mut c_void) -> &'static mut SigQueue {
let sq = p as *mut SigQueue;
let sq = unsafe { sq.as_mut::<'static>() }.unwrap();
return sq;

View File

@ -13,8 +13,8 @@ pub fn atomic_read(ato: *const atomic_t) -> i64 {
/// @brief 原子的设置原子变量的值
#[inline]
pub fn atomic_set(ato: *mut atomic_t, value:i64) {
unsafe{
pub fn atomic_set(ato: *mut atomic_t, value: i64) {
unsafe {
write_volatile(&mut (*ato).value, value);
}
}

View File

@ -6,24 +6,10 @@ pub trait FFIBind2Rust<T> {
fn convert_mut(src: *mut T) -> Option<&'static mut Self>;
}
pub fn __convert_mut<'a, S, D>(src:*mut S) ->Option<&'a mut D>{
return unsafe {
core::mem::transmute::<
*mut S,
*mut D,
>(src)
.as_mut()
};
pub fn __convert_mut<'a, S, D>(src: *mut S) -> Option<&'a mut D> {
return unsafe { core::mem::transmute::<*mut S, *mut D>(src).as_mut() };
}
pub fn __convert_ref<'a, S, D>(src:*const S) ->Option<&'a D>{
return unsafe {
core::mem::transmute::<
*const S,
*const D,
>(src)
.as_ref()
};
pub fn __convert_ref<'a, S, D>(src: *const S) -> Option<&'a D> {
return unsafe { core::mem::transmute::<*const S, *const D>(src).as_ref() };
}

View File

@ -3,13 +3,16 @@ use crate::include::bindings::bindings::List;
/// @brief 初始化链表
#[inline]
pub fn list_init(list: *mut List) {
unsafe{*list}.prev = list;
unsafe{*list}.next = list;
unsafe { *list }.prev = list;
unsafe { *list }.next = list;
}
impl Default for List{
impl Default for List {
fn default() -> Self {
let x= Self { prev: 0 as *mut List, next: 0 as *mut List };
return x;
let x = Self {
prev: 0 as *mut List,
next: 0 as *mut List,
};
return x;
}
}
}

View File

@ -324,32 +324,32 @@ impl LockRef {
}
/*
* 使lockref
* 使lockref
let mut lockref = LockRef::new();
kdebug!("lockref={:?}", lockref);
lockref.inc();
assert_eq!(lockref.count, 1);
kdebug!("lockref={:?}", lockref);
assert!(lockref.dec().is_ok());
assert_eq!(lockref.count, 0);
let mut lockref = LockRef::new();
kdebug!("lockref={:?}", lockref);
lockref.inc();
assert_eq!(lockref.count, 1);
kdebug!("lockref={:?}", lockref);
assert!(lockref.dec().is_ok());
assert_eq!(lockref.count, 0);
assert!(lockref.dec().is_err());
assert_eq!(lockref.count, 0);
assert!(lockref.dec().is_err());
assert_eq!(lockref.count, 0);
lockref.inc();
assert_eq!(lockref.count, 1);
lockref.inc();
assert_eq!(lockref.count, 1);
assert!(lockref.dec_not_zero().is_err());
assert!(lockref.dec_not_zero().is_err());
lockref.inc();
assert_eq!(lockref.count, 2);
lockref.inc();
assert_eq!(lockref.count, 2);
assert!(lockref.dec_not_zero().is_ok());
assert!(lockref.dec_not_zero().is_ok());
lockref.mark_dead();
assert!(lockref.count < 0);
assert!(lockref.inc_not_dead().is_err());
kdebug!("lockref={:?}", lockref);
*/
lockref.mark_dead();
assert!(lockref.count < 0);
assert!(lockref.inc_not_dead().is_err());
kdebug!("lockref={:?}", lockref);
*/

View File

@ -1,9 +1,9 @@
pub mod ffi_convert;
pub mod printk;
pub mod spinlock;
pub mod ffi_convert;
#[macro_use]
pub mod refcount;
pub mod atomic;
pub mod wait_queue;
pub mod list;
pub mod lockref;
pub mod lockref;
pub mod wait_queue;

View File

@ -1,20 +1,28 @@
use crate::{include::bindings::bindings::{atomic_inc, atomic_t, atomic_dec}, kwarn};
use crate::{
include::bindings::bindings::{atomic_dec, atomic_inc, atomic_t},
kwarn,
};
use super::{ffi_convert::{FFIBind2Rust, __convert_mut, __convert_ref}, atomic::atomic_read};
use super::{
atomic::atomic_read,
ffi_convert::{FFIBind2Rust, __convert_mut, __convert_ref},
};
#[derive(Debug, Copy, Clone)]
pub struct RefCount {
pub refs: atomic_t,
}
impl Default for RefCount{
impl Default for RefCount {
fn default() -> Self {
Self { refs: atomic_t { value: 1 }}
Self {
refs: atomic_t { value: 1 },
}
}
}
/// @brief 将给定的来自bindgen的refcount_t解析为Rust的RefCount的引用
impl FFIBind2Rust<crate::include::bindings::bindings::refcount_struct> for RefCount{
impl FFIBind2Rust<crate::include::bindings::bindings::refcount_struct> for RefCount {
fn convert_mut(
src: *mut crate::include::bindings::bindings::refcount_struct,
) -> Option<&'static mut Self> {
@ -23,7 +31,7 @@ impl FFIBind2Rust<crate::include::bindings::bindings::refcount_struct> for RefCo
fn convert_ref(
src: *const crate::include::bindings::bindings::refcount_struct,
) -> Option<&'static Self> {
return __convert_ref(src)
return __convert_ref(src);
}
}
@ -40,10 +48,10 @@ macro_rules! REFCOUNT_INIT {
#[allow(dead_code)]
#[inline]
pub fn refcount_inc(r: &mut RefCount) {
if atomic_read(&r.refs) == 0{
if atomic_read(&r.refs) == 0 {
kwarn!("Refcount increased from 0, may be use-after free");
}
unsafe {
atomic_inc(&mut r.refs);
}
@ -52,10 +60,8 @@ pub fn refcount_inc(r: &mut RefCount) {
/// @brief 引用计数自减1
#[allow(dead_code)]
#[inline]
pub fn refcount_dec(r: &mut RefCount){
unsafe{
pub fn refcount_dec(r: &mut RefCount) {
unsafe {
atomic_dec(&mut r.refs);
}
}

View File

@ -1,12 +1,14 @@
use crate::include::bindings::bindings::{wait_queue_head_t};
use crate::include::bindings::bindings::wait_queue_head_t;
use super::{list::list_init};
use super::list::list_init;
impl Default for wait_queue_head_t{
impl Default for wait_queue_head_t {
fn default() -> Self {
let mut x = Self { wait_list: Default::default(), lock: Default::default() };
let mut x = Self {
wait_list: Default::default(),
lock: Default::default(),
};
list_init(&mut x.wait_list);
return x;
}
}
}

View File

@ -1,5 +1,5 @@
use crate::include::bindings::bindings::{gfp_t, kfree, kmalloc, PAGE_2M_SIZE};
use super::gfp::__GFP_ZERO;
use crate::include::bindings::bindings::{gfp_t, kfree, kmalloc, PAGE_2M_SIZE};
use core::alloc::{GlobalAlloc, Layout};

View File

@ -26,10 +26,9 @@ pub static mut INITIAL_SIGHAND: sighand_struct = sighand_struct {
/// @brief 初始化pid=0的进程的信号相关的信息
#[no_mangle]
pub extern "C" fn initial_proc_init_signal(pcb: *mut process_control_block) {
// 所设置的pcb的pid一定为0
assert_eq!(unsafe { (*pcb).pid }, 0);
// 设置init进程的sighand和signal
unsafe {
(*pcb).sighand = &mut INITIAL_SIGHAND as *mut sighand_struct as usize

View File

@ -1,5 +1,5 @@
pub mod pid;
pub mod process;
pub mod preempt;
pub mod fork;
pub mod initial_proc;
pub mod fork;
pub mod pid;
pub mod preempt;
pub mod process;

View File

@ -1,4 +1,4 @@
use crate::{include::bindings::bindings::pt_regs, arch::asm::current::current_pcb};
use crate::{arch::asm::current::current_pcb, include::bindings::bindings::pt_regs};
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
@ -23,6 +23,6 @@ impl PartialEq for PidType {
* @brief pid
*/
#[no_mangle]
pub extern "C" fn sys_getpid(_regs: &pt_regs)->u64{
pub extern "C" fn sys_getpid(_regs: &pt_regs) -> u64 {
return current_pcb().pid as u64;
}
}

View File

@ -105,6 +105,7 @@ struct process_control_block
long pid;
long priority; // 优先级
int64_t virtual_runtime; // 虚拟运行时间
int64_t rt_time_slice; // 由实时调度器管理的时间片
// 进程拥有的文件描述符的指针数组
// todo: 改用动态指针数组

View File

@ -409,7 +409,7 @@ ul do_execve(struct pt_regs *regs, char *path, char *argv[], char *envp[])
// 关闭之前的文件描述符
process_exit_files(current_pcb);
process_open_stdio(current_pcb);
// 清除进程的vfork标志位
@ -469,6 +469,22 @@ exec_failed:;
}
#pragma GCC pop_options
/**
* @brief rt_pcb
*
* @return
*
*/
struct process_control_block *process_init_rt_pcb(struct process_control_block *rt_pcb)
{
// 暂时将实时进程的优先级设置为10
rt_pcb->priority = 10;
rt_pcb->policy = SCHED_RR;
rt_pcb->rt_time_slice = 80;
rt_pcb->virtual_runtime = 0x7fffffffffffffff;
return rt_pcb;
}
/**
* @brief init进程
*
@ -508,6 +524,12 @@ ul initial_kernel_thread(ul arg)
// waitpid(tpid[i], NULL, NULL);
// kinfo("All test done.");
// 测试实时进程
// struct process_control_block *test_rt1 = kthread_run_rt(&test, NULL, "test rt");
// kdebug("process:rt test kthread is created!!!!");
// 准备切换到用户态
struct pt_regs *regs;

View File

@ -2,9 +2,7 @@ use core::ptr::{read_volatile, write_volatile};
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
process_control_block, PROC_RUNNING, PROC_STOPPED,
},
include::bindings::bindings::{process_control_block, PROC_RUNNING, PROC_STOPPED},
sched::core::{cpu_executing, sched_enqueue},
smp::core::{smp_get_processor_id, smp_send_reschedule},
};

View File

@ -1,24 +1,17 @@
use core::{
ptr::null_mut,
sync::atomic::compiler_fence,
};
use core::{ptr::null_mut, sync::atomic::compiler_fence};
use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::{
asm::current::current_pcb,
context::switch_process,
},
arch::asm::current::current_pcb,
include::bindings::bindings::{
initial_proc_union, process_control_block, MAX_CPU_NUM, PF_NEED_SCHED,
PROC_RUNNING,
initial_proc_union, process_control_block, MAX_CPU_NUM, PF_NEED_SCHED, PROC_RUNNING,
},
kBUG,
libs::spinlock::RawSpinlock,
};
use super::core::Scheduler;
use super::core::{sched_enqueue, Scheduler};
/// 声明全局的cfs调度器实例
@ -149,8 +142,7 @@ impl SchedulerCFS {
impl Scheduler for SchedulerCFS {
/// @brief 在当前cpu上进行调度。
/// 请注意,进入该函数之前,需要关中断
fn sched(&mut self) {
// kdebug!("cfs:sched");
fn sched(&mut self) -> Option<&'static mut process_control_block> {
current_pcb().flags &= !(PF_NEED_SCHED as u64);
let current_cpu_id = current_pcb().cpu_id as usize;
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[current_cpu_id];
@ -163,8 +155,7 @@ impl Scheduler for SchedulerCFS {
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// 本次切换由于时间片到期引发,则再次加入就绪队列,否则交由其它功能模块进行管理
if current_pcb().state & (PROC_RUNNING as u64) != 0 {
// kdebug!("cfs:sched->enqueue");
current_cpu_queue.enqueue(current_pcb());
sched_enqueue(current_pcb());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
@ -175,9 +166,7 @@ impl Scheduler for SchedulerCFS {
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
switch_process(current_pcb(), proc);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
} else {
// 不进行切换
@ -188,10 +177,11 @@ impl Scheduler for SchedulerCFS {
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
current_cpu_queue.enqueue(proc);
sched_enqueue(proc);
compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return None;
}
fn enqueue(&mut self, pcb: &'static mut process_control_block) {

View File

@ -2,11 +2,16 @@ use core::sync::atomic::compiler_fence;
use crate::{
arch::asm::{current::current_pcb, ptrace::user_mode},
include::bindings::bindings::{process_control_block, pt_regs, EPERM, SCHED_NORMAL},
arch::context::switch_process,
include::bindings::bindings::{
process_control_block, pt_regs, EPERM, PROC_RUNNING, SCHED_FIFO, SCHED_NORMAL, SCHED_RR,
},
kdebug,
process::process::process_cpu,
};
use super::cfs::{sched_cfs_init, SchedulerCFS, __get_cfs_scheduler};
use super::rt::{sched_rt_init, SchedulerRT, __get_rt_scheduler};
/// @brief 获取指定的cpu上正在执行的进程的pcb
#[inline]
@ -23,28 +28,50 @@ pub fn cpu_executing(cpu_id: u32) -> &'static mut process_control_block {
/// @brief 具体的调度器应当实现的trait
pub trait Scheduler {
/// @brief 使用该调度器发起调度的时候,要调用的函数
fn sched(&mut self);
fn sched(&mut self) -> Option<&'static mut process_control_block>;
/// @brief 将pcb加入这个调度器的调度队列
fn enqueue(&mut self, pcb: &'static mut process_control_block);
}
fn __sched() {
fn __sched() -> Option<&'static mut process_control_block> {
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);
cfs_scheduler.sched();
compiler_fence(core::sync::atomic::Ordering::SeqCst);
let next: &'static mut process_control_block;
match rt_scheduler.pick_next_task_rt() {
Some(p) => {
next = p;
// kdebug!("next pcb is {}",next.pid);
// rt_scheduler.enqueue_task_rt(next.priority as usize, next);
sched_enqueue(next);
return rt_scheduler.sched();
}
None => {
return cfs_scheduler.sched();
}
}
}
/// @brief 将进程加入调度队列
#[allow(dead_code)]
#[no_mangle]
pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block) {
// 调度器不处理running位为0的进程
if pcb.state & (PROC_RUNNING as u64) == 0 {
return;
}
let cfs_scheduler = __get_cfs_scheduler();
cfs_scheduler.enqueue(pcb);
let rt_scheduler = __get_rt_scheduler();
if pcb.policy == SCHED_NORMAL {
cfs_scheduler.enqueue(pcb);
} else if pcb.policy == SCHED_FIFO || pcb.policy == SCHED_RR {
rt_scheduler.enqueue(pcb);
} else {
panic!("This policy is not supported at this time");
}
}
/// @brief 初始化进程调度器模块
@ -53,6 +80,7 @@ pub extern "C" fn sched_enqueue(pcb: &'static mut process_control_block) {
pub extern "C" fn sched_init() {
unsafe {
sched_cfs_init();
sched_rt_init();
}
}
@ -65,6 +93,9 @@ pub extern "C" fn sched_update_jiffies() {
SCHED_NORMAL => {
__get_cfs_scheduler().timer_update_jiffies();
}
SCHED_FIFO | SCHED_RR => {
current_pcb().rt_time_slice -= 1;
}
_ => {
todo!()
}
@ -80,6 +111,10 @@ pub extern "C" fn sys_sched(regs: &'static mut pt_regs) -> u64 {
if user_mode(regs) {
return (-(EPERM as i64)) as u64;
}
__sched();
// 根据调度结果统一进行切换
let pcb = __sched();
if pcb.is_some() {
switch_process(current_pcb(), pcb.unwrap());
}
0
}

View File

@ -1,2 +1,3 @@
pub mod cfs;
pub mod core;
pub mod cfs;
pub mod rt;

173
kernel/src/sched/rt.rs Normal file
View File

@ -0,0 +1,173 @@
use core::{ptr::null_mut, sync::atomic::compiler_fence};
use alloc::{boxed::Box, vec::Vec};
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{
initial_proc_union, process_control_block, PF_NEED_SCHED, SCHED_FIFO, SCHED_NORMAL,
SCHED_RR,
},
kBUG, kdebug,
libs::spinlock::RawSpinlock,
};
use super::core::{sched_enqueue, Scheduler};
/// 声明全局的rt调度器实例
pub static mut RT_SCHEDULER_PTR: *mut SchedulerRT = null_mut();
/// @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!("test rt init");
if RT_SCHEDULER_PTR.is_null() {
RT_SCHEDULER_PTR = Box::leak(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 {
/// 队列的锁
lock: RawSpinlock,
/// 进程的队列
queue: Vec<&'static mut process_control_block>,
}
impl RTQueue {
pub fn new() -> RTQueue {
RTQueue {
queue: Vec::new(),
lock: RawSpinlock::INIT,
}
}
/// @brief 将pcb加入队列
pub fn enqueue(&mut self, pcb: &'static mut process_control_block) {
self.lock.lock();
// 如果进程是IDLE进程那么就不加入队列
if pcb.pid == 0 {
self.lock.unlock();
return;
}
self.queue.push(pcb);
self.lock.unlock();
}
/// @brief 将pcb从调度队列中弹出,若队列为空则返回None
pub fn dequeue(&mut self) -> Option<&'static mut process_control_block> {
let res: Option<&'static mut process_control_block>;
self.lock.lock();
if self.queue.len() > 0 {
// 队列不为空返回下一个要执行的pcb
res = Some(self.queue.pop().unwrap());
} else {
// 如果队列为空则返回None
res=None;
}
self.lock.unlock();
return res;
}
}
/// @brief RT调度器类
pub struct SchedulerRT {
cpu_queue: Vec<&'static mut RTQueue>,
}
impl SchedulerRT {
const RR_TIMESLICE: i64 = 100;
const MAX_RT_PRIO: i64 = 100;
pub fn new() -> SchedulerRT {
// 暂时手动指定核心数目
// todo: 从cpu模块来获取核心的数目
let mut result = SchedulerRT {
cpu_queue: Default::default(),
};
// 为每个cpu核心创建队列
for _ in 0..SchedulerRT::MAX_RT_PRIO {
result.cpu_queue.push(Box::leak(Box::new(RTQueue::new())));
}
return result;
}
/// @brief 挑选下一个可执行的rt进程
pub fn pick_next_task_rt(&mut self) -> Option<&'static mut process_control_block> {
// 循环查找,直到找到
// 这里应该是优先级数量而不是CPU数量需要修改
for i in 0..SchedulerRT::MAX_RT_PRIO {
let cpu_queue_i: &mut RTQueue = self.cpu_queue[i as usize];
let proc: Option<&'static mut process_control_block> = cpu_queue_i.dequeue();
if proc.is_some(){
return proc;
}
}
// return 一个空值
None
}
}
impl Scheduler for SchedulerRT {
/// @brief 在当前cpu上进行调度。
/// 请注意,进入该函数之前,需要关中断
fn sched(&mut self) -> Option<&'static mut process_control_block> {
current_pcb().flags &= !(PF_NEED_SCHED as u64);
// 正常流程下这里一定是会pick到next的pcb的如果是None的话要抛出错误
let proc: &'static mut process_control_block =
self.pick_next_task_rt().expect("No RT process found");
// 如果是fifo策略则可以一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)
if proc.policy == SCHED_FIFO {
// 如果挑选的进程优先级小于当前进程,则不进行切换
if proc.priority <= current_pcb().priority {
sched_enqueue(proc);
} else {
// 将当前的进程加进队列
sched_enqueue(current_pcb());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
}
// RR调度策略需要考虑时间片
else if proc.policy == SCHED_RR {
// 同等优先级的,考虑切换
if proc.priority >= current_pcb().priority {
// 判断这个进程时间片是否耗尽,若耗尽则将其时间片赋初值然后入队
if proc.rt_time_slice <= 0 {
proc.rt_time_slice = SchedulerRT::RR_TIMESLICE;
proc.flags |= !(PF_NEED_SCHED as u64);
sched_enqueue(proc);
}
// 目标进程时间片未耗尽,切换到目标进程
else {
// 将当前进程加进队列
sched_enqueue(current_pcb());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
return Some(proc);
}
}
// curr优先级更大说明一定是实时进程将所选进程入队列
else {
sched_enqueue(proc);
}
}
return None;
}
fn enqueue(&mut self, pcb: &'static mut process_control_block) {
let cpu_queue = &mut self.cpu_queue[pcb.cpu_id as usize];
cpu_queue.enqueue(pcb);
}
}

View File

@ -1 +1 @@
pub mod core;
pub mod core;