Skip to content

Commit

Permalink
修正signal和调度器的部分加锁逻辑,增加回退策略。
Browse files Browse the repository at this point in the history
todo: 把PCB的flags改为无锁的。
  • Loading branch information
fslongjin committed Nov 7, 2023
1 parent 54a39d4 commit 9a3702d
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 34 deletions.
57 changes: 36 additions & 21 deletions kernel/src/arch/x86_64/ipc/signal.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use core::{ffi::c_void, mem::size_of};
use core::{ffi::c_void, intrinsics::unlikely, mem::size_of};

use crate::{
arch::{
Expand Down Expand Up @@ -322,7 +322,7 @@ impl SigContext {
//TODO 引入线程后补上
// let current_thread = ProcessManager::current_pcb().thread;
let pcb = ProcessManager::current_pcb();
let mut archinfo_guard = pcb.arch_info();
let mut archinfo_guard = pcb.arch_info_irqsave();
self.oldmask = *mask;
self.frame = frame.clone();
// context.trap_num = unsafe { (*current_thread).trap_num };
Expand Down Expand Up @@ -368,6 +368,7 @@ pub struct SigStack {
#[no_mangle]
unsafe extern "C" fn do_signal(frame: &mut TrapFrame) {
X86_64SignalArch::do_signal(frame);
return;
}

pub struct X86_64SignalArch;
Expand All @@ -377,35 +378,46 @@ impl SignalArch for X86_64SignalArch {
let pcb = ProcessManager::current_pcb();
let siginfo = pcb.try_siginfo(5);

if unlikely(siginfo.is_none()) {
return;
}

let siginfo_read_guard = siginfo.unwrap();

// 检查sigpending是否为0
if siginfo
.map(|s| s.sig_pending().signal().bits() == 0)
.unwrap_or(true)
|| !frame.from_user()
{
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则启用中断,然后返回
CurrentIrqArch::interrupt_enable();
if siginfo_read_guard.sig_pending().signal().bits() == 0 || !frame.from_user() {
// 若没有正在等待处理的信号,或者将要返回到的是内核态,则返回
return;
}

// 做完上面的检查后,开中断
CurrentIrqArch::interrupt_enable();
let pcb = ProcessManager::current_pcb();
let sig_guard = pcb.sig_struct();

let mut sig_number: Signal;
let mut info: Option<SigInfo>;
let mut sigaction: Sigaction;
let reader = pcb.sig_info();
let sig_block: SigSet = reader.sig_block().clone();
drop(reader);
let sig_block: SigSet = siginfo_read_guard.sig_block().clone();
drop(siginfo_read_guard);

let sig_guard = pcb.try_sig_struct_irq(5);
if unlikely(sig_guard.is_none()) {
return;
}
let siginfo_mut = pcb.try_siginfo_mut(5);
if unlikely(siginfo_mut.is_none()) {
return;
}

let sig_guard = sig_guard.unwrap();
let mut siginfo_mut_guard = siginfo_mut.unwrap();
loop {
(sig_number, info) = pcb.sig_info_mut().dequeue_signal(&sig_block);
(sig_number, info) = siginfo_mut_guard.dequeue_signal(&sig_block);
// 如果信号非法,则直接返回
if sig_number == Signal::INVALID {
return;
}

sigaction = sig_guard.handlers[sig_number as usize - 1];

match sigaction.action() {
SigactionType::SaHandler(action_type) => match action_type {
SaHandlerType::SigError => {
Expand All @@ -425,12 +437,14 @@ impl SignalArch for X86_64SignalArch {
}
// 如果当前动作是忽略这个信号,就继续循环。
}
// 所有的信号都处理完了
let reader = pcb.sig_info();
let oldset = reader.sig_block().clone();

let oldset = siginfo_mut_guard.sig_block().clone();
//避免死锁
drop(reader);
drop(siginfo_mut_guard);
drop(sig_guard);

// 做完上面的检查后,开中断
CurrentIrqArch::interrupt_enable();
let res: Result<i32, SystemError> =
handle_signal(sig_number, &mut sigaction, &info.unwrap(), &oldset, frame);
if res.is_err() {
Expand Down Expand Up @@ -564,7 +578,8 @@ fn setup_frame(
let frame: *mut SigFrame = get_stack(&trap_frame, size_of::<SigFrame>());
// kdebug!("frame=0x{:016x}", frame as usize);
// 要求这个frame的地址位于用户空间,因此进行校验
let r = UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
let r: Result<UserBufferWriter<'_>, SystemError> =
UserBufferWriter::new(frame, size_of::<SigFrame>(), true);
if r.is_err() {
// 如果地址区域位于内核空间,则直接报错
// todo: 生成一个sigsegv
Expand Down
3 changes: 2 additions & 1 deletion kernel/src/exception/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ ENTRY(ret_from_intr)
// 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
movq %rsp, %rdi
callq do_signal

cli

__entry_ret_from_intr_before_gs_check_2:
push %rcx
Expand Down Expand Up @@ -138,6 +138,7 @@ __entry_err_code_after_gs_check_1:

callq *%rdx //调用服务程序 带*号表示调用的是绝对地址

__entry_err_code_to_ret_from_exception:
jmp ret_from_exception


Expand Down
14 changes: 14 additions & 0 deletions kernel/src/libs/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,20 @@ impl<T> RwLock<T> {
return r;
}

#[allow(dead_code)]
pub fn try_upgradeable_read_irqsave(&self) -> Option<RwLockUpgradableGuard<T>> {
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
ProcessManager::preempt_disable();
let mut r = self.inner_try_upgradeable_read();
if r.is_none() {
ProcessManager::preempt_enable();
} else {
r.as_mut().unwrap().irq_guard = Some(irq_guard);
}

return r;
}

fn inner_try_upgradeable_read(&self) -> Option<RwLockUpgradableGuard<T>> {
// 获得UPGRADER守卫不需要查看读者位
// 如果获得读者锁失败,不需要撤回fetch_or的原子操作
Expand Down
45 changes: 42 additions & 3 deletions kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl ProcessManager {
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
let state = pcb.sched_info().state();
if state.is_blocked() {
let mut writer = pcb.sched_info_mut();
let mut writer: RwLockWriteGuard<'_, ProcessSchedulerInfo> = pcb.sched_info_mut();
let state = writer.state();
if state.is_blocked() {
writer.set_state(ProcessState::Runnable);
Expand Down Expand Up @@ -707,15 +707,34 @@ impl ProcessControlBlock {
return self.sched_info.read();
}

#[inline(always)]
pub fn try_sched_info(&self, times: u8) -> Option<RwLockReadGuard<ProcessSchedulerInfo>> {
for _ in 0..times {
if let Some(r) = self.sched_info.try_read() {
return Some(r);
}
}

return None;
}

#[allow(dead_code)]
#[inline(always)]
pub fn sched_info_irqsave(&self) -> RwLockReadGuard<ProcessSchedulerInfo> {
return self.sched_info.read_irqsave();
}

#[inline(always)]
pub fn sched_info_upgradeable_irqsave(&self) -> RwLockUpgradableGuard<ProcessSchedulerInfo> {
return self.sched_info.upgradeable_read();
pub fn sched_info_try_upgradeable_irqsave(
&self,
times: u8,
) -> Option<RwLockUpgradableGuard<ProcessSchedulerInfo>> {
for _ in 0..times {
if let Some(r) = self.sched_info.try_upgradeable_read_irqsave() {
return Some(r);
}
}
return None;
}

#[inline(always)]
Expand Down Expand Up @@ -816,10 +835,30 @@ impl ProcessControlBlock {
self.sig_info.write()
}

pub fn try_siginfo_mut(&self, times: u8) -> Option<RwLockWriteGuard<ProcessSignalInfo>> {
for _ in 0..times {
if let Some(r) = self.sig_info.try_write() {
return Some(r);
}
}

return None;
}

pub fn sig_struct(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock()
}

pub fn try_sig_struct_irq(&self, times: u8) -> Option<SpinLockGuard<SignalStruct>> {
for _ in 0..times {
if let Ok(r) = self.sig_struct.try_lock_irqsave() {
return Some(r);
}
}

return None;
}

pub fn sig_struct_irq(&self) -> SpinLockGuard<SignalStruct> {
self.sig_struct.lock_irqsave()
}
Expand Down
14 changes: 9 additions & 5 deletions kernel/src/sched/cfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ use crate::{
kBUG,
libs::{
rbtree::RBTree,
rwlock::RwLockReadGuard,
spinlock::{SpinLock, SpinLockGuard},
},
process::{ProcessControlBlock, ProcessFlags, ProcessManager, ProcessState},
process::{
ProcessControlBlock, ProcessFlags, ProcessManager, ProcessSchedulerInfo, ProcessState,
},
smp::core::smp_get_processor_id,
};

Expand Down Expand Up @@ -142,7 +145,10 @@ impl SchedulerCFS {
}

/// @brief 时钟中断到来时,由sched的core模块中的函数,调用本函数,更新CFS进程的可执行时间
pub fn timer_update_jiffies(&mut self) {
pub fn timer_update_jiffies(
&mut self,
sched_info_guard: &RwLockReadGuard<'_, ProcessSchedulerInfo>,
) {
let current_cpu_queue: &mut CFSQueue = self.cpu_queue[smp_get_processor_id() as usize];
// todo: 引入调度周期以及所有进程的优先权进行计算,然后设置进程的可执行时间

Expand All @@ -168,9 +174,7 @@ impl SchedulerCFS {
drop(queue);

// 更新当前进程的虚拟运行时间
ProcessManager::current_pcb()
.sched_info()
.increase_virtual_runtime(1);
sched_info_guard.increase_virtual_runtime(1);
}

/// @brief 将进程加入cpu的cfs调度队列,并且重设其虚拟运行时间为当前队列的最小值
Expand Down
23 changes: 19 additions & 4 deletions kernel/src/sched/core.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use core::sync::atomic::{compiler_fence, Ordering};
use core::{
intrinsics::unlikely,
sync::atomic::{compiler_fence, Ordering},
};

use alloc::{sync::Arc, vec::Vec};

Expand Down Expand Up @@ -99,7 +102,13 @@ pub fn do_sched() -> Option<Arc<ProcessControlBlock>> {
// 当前进程持有锁,不切换,避免死锁
if ProcessManager::current_pcb().preempt_count() != 0 {
let binding = ProcessManager::current_pcb();
let mut guard = binding.sched_info_upgradeable_irqsave();
let guard = binding.sched_info_try_upgradeable_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
Expand Down Expand Up @@ -191,10 +200,16 @@ pub extern "C" fn sched_init() {
/// @brief 当时钟中断到达时,更新时间片
/// 请注意,该函数只能被时钟中断处理程序调用
pub extern "C" fn sched_update_jiffies() {
let policy = ProcessManager::current_pcb().sched_info().policy();
let binding = ProcessManager::current_pcb();
let guard = binding.try_sched_info(10);
if unlikely(guard.is_none()) {
return;
}
let guard = guard.unwrap();
let policy = guard.policy();
match policy {
SchedPolicy::CFS => {
__get_cfs_scheduler().timer_update_jiffies();
__get_cfs_scheduler().timer_update_jiffies(&guard);
}
SchedPolicy::FIFO | SchedPolicy::RR => {
__get_rt_scheduler().timer_update_jiffies();
Expand Down

0 comments on commit 9a3702d

Please sign in to comment.