bugfix: 修复无法sleep的问题以及进程处于block(true)状态时无法被信号唤醒&唤醒后不处理信号的问题 (#470)

This commit is contained in:
LoGin 2023-12-19 11:56:14 +08:00 committed by GitHub
parent 24ff1faffb
commit 8612b6ce7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 36 deletions

View File

@ -374,6 +374,10 @@ ENTRY(syscall_64)
callq *%rdx //
// do_signal
movq %rsp, %rdi
callq do_signal
cli
// === ===

View File

@ -495,7 +495,7 @@ impl SignalArch for X86_64SignalArch {
}
fn sys_rt_sigreturn(trap_frame: &mut TrapFrame) -> u64 {
let frame = (trap_frame.rsp as usize) as *mut SigFrame;
let frame = (trap_frame.rsp as usize - size_of::<u64>()) as *mut SigFrame;
// 如果当前的rsp不来自用户态则认为产生了错误或被SROP攻击
if UserBufferWriter::new(frame, size_of::<SigFrame>(), true).is_err() {

View File

@ -141,12 +141,7 @@ impl Signal {
/// @param pt siginfo结构体中pid字段代表的含义
fn complete_signal(&self, pcb: Arc<ProcessControlBlock>, pt: PidType) {
// kdebug!("complete_signal");
// todo: 将信号产生的消息通知到正在监听这个信号的进程引入signalfd之后在这里调用signalfd_notify)
// 将这个信号加到目标进程的sig_pending中
pcb.sig_info_mut()
.sig_pending_mut()
.signal_mut()
.insert(self.clone().into());
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// ===== 寻找需要wakeup的目标进程 =====
// 备注由于当前没有进程组的概念每个进程只有1个对应的线程因此不需要通知进程组内的每个进程。
@ -154,11 +149,17 @@ impl Signal {
// let _signal = pcb.sig_struct();
let mut _target: Option<Arc<ProcessControlBlock>> = None;
let target_pcb: Option<Arc<ProcessControlBlock>>;
// 判断目标进程是否想接收这个信号
if self.wants_signal(pcb.clone()) {
_target = Some(pcb.clone());
// todo: 将信号产生的消息通知到正在监听这个信号的进程引入signalfd之后在这里调用signalfd_notify)
// 将这个信号加到目标进程的sig_pending中
pcb.sig_info_mut()
.sig_pending_mut()
.signal_mut()
.insert(self.clone().into());
target_pcb = Some(pcb.clone());
} else if pt == PidType::PID {
/*
* There is just one thread and it does not need to be woken.
@ -176,9 +177,9 @@ impl Signal {
// TODO:引入进程组后,在这里挑选一个进程来唤醒,让它执行相应的操作。
compiler_fence(core::sync::atomic::Ordering::SeqCst);
// TODO: 到这里信号已经被放置在共享的pending队列中我们在这里把目标进程唤醒。
if _target.is_some() {
let guard = pcb.sig_struct();
signal_wake_up(pcb.clone(), guard, *self == Signal::SIGKILL);
if let Some(target_pcb) = target_pcb {
let guard = target_pcb.sig_struct();
signal_wake_up(target_pcb.clone(), guard, *self == Signal::SIGKILL);
}
}
@ -201,7 +202,9 @@ impl Signal {
return true;
}
if pcb.sched_info().state().is_blocked() {
if pcb.sched_info().state().is_blocked()
&& (pcb.sched_info().state().is_blocked_interruptable() == false)
{
return false;
}
@ -209,7 +212,6 @@ impl Signal {
// 检查目标进程是否有信号正在等待处理如果是则返回false否则返回true
if pcb.sig_info().sig_pending().signal().bits() == 0 {
assert!(pcb.sig_info().sig_pending().queue().q.is_empty());
return true;
} else {
return false;

View File

@ -702,12 +702,6 @@ impl Syscall {
Self::sigaction(sig, act, old_act, frame.from_user())
}
SYS_RT_SIGRETURN => {
// 由于目前signal机制的实现与x86_64强关联因此暂时在arch/x86_64/syscall.rs中调用
// todo: 未来需要将signal机制与平台解耦
todo!()
}
SYS_GETPID => Self::getpid().map(|pid| pid.into()),
SYS_SCHED => Self::sched(frame.from_user()),

View File

@ -1,4 +1,7 @@
use core::{fmt, ops};
use core::{
fmt,
ops::{self, Sub},
};
use self::timekeep::ktime_get_real_ns;
@ -54,6 +57,30 @@ impl TimeSpec {
}
}
impl Sub for TimeSpec {
type Output = Duration;
fn sub(self, rhs: Self) -> Self::Output {
let sec = self.tv_sec.checked_sub(rhs.tv_sec).unwrap_or(0);
let nsec = self.tv_nsec.checked_sub(rhs.tv_nsec).unwrap_or(0);
Duration::from_micros((sec * 1000000 + nsec / 1000) as u64)
}
}
impl From<Duration> for TimeSpec {
fn from(dur: Duration) -> Self {
TimeSpec {
tv_sec: dur.total_micros() as i64 / 1000000,
tv_nsec: (dur.total_micros() as i64 % 1000000) * 1000,
}
}
}
impl Into<Duration> for TimeSpec {
fn into(self) -> Duration {
Duration::from_micros(self.tv_sec as u64 * 1000000 + self.tv_nsec as u64 / 1000)
}
}
/// A representation of an absolute time value.
///
/// The `Instant` type is a wrapper around a `i64` value that

View File

@ -8,6 +8,7 @@ use crate::{
include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
process::ProcessManager,
syscall::SystemError,
time::timekeeping::getnstimeofday,
};
use super::{
@ -27,8 +28,7 @@ pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
return Err(SystemError::EINVAL);
}
// 对于小于500us的时间使用spin/rdtsc来进行定时
if sleep_time.tv_nsec < 500000 {
if sleep_time.tv_nsec < 500000 && sleep_time.tv_sec == 0 {
let expired_tsc: u64 = unsafe {
CurrentTimeArch::get_cycles() as u64
+ (sleep_time.tv_nsec as u64 * Cpu_tsc_freq) / 1000000000
@ -41,28 +41,29 @@ pub fn nanosleep(sleep_time: TimeSpec) -> Result<TimeSpec, SystemError> {
tv_nsec: 0,
});
}
let total_sleep_time_us: u64 =
sleep_time.tv_sec as u64 * 1000000 + sleep_time.tv_nsec as u64 / 1000;
// 创建定时器
let handler: Box<WakeUpHelper> = WakeUpHelper::new(ProcessManager::current_pcb());
let timer: Arc<Timer> = Timer::new(
handler,
next_n_us_timer_jiffies((sleep_time.tv_nsec / 1000) as u64),
);
let timer: Arc<Timer> = Timer::new(handler, next_n_us_timer_jiffies(total_sleep_time_us));
let irq_guard: crate::exception::IrqFlagsGuard =
unsafe { CurrentIrqArch::save_and_disable_irq() };
ProcessManager::mark_sleep(true).ok();
let start_time = getnstimeofday();
timer.activate();
drop(irq_guard);
sched();
// TODO: 增加信号唤醒的功能后,返回正确的剩余时间
let end_time = getnstimeofday();
// 返回正确的剩余时间
let real_sleep_time = end_time - start_time;
let rm_time: TimeSpec = (sleep_time - real_sleep_time.into()).into();
return Ok(TimeSpec {
tv_sec: 0,
tv_nsec: 0,
});
return Ok(rm_time);
}
/// @brief 休眠指定时间(单位:微秒)

View File

@ -6,7 +6,7 @@
"BuildFromSource": {
"Git": {
"url": "https://git.mirrors.dragonos.org.cn/DragonOS-Community/NovaShell.git",
"revision": "95738b235f"
"revision": "4160a0a0de"
}
}
},

View File

@ -5,8 +5,8 @@
"task_type": {
"BuildFromSource": {
"Git": {
"url": "https://git.mirrors.dragonos.org/DragonOS-Community/relibc.git",
"revision": "3ef630632f"
"url": "https://git.mirrors.dragonos.org.cn/DragonOS-Community/relibc.git",
"revision": "27e779dc23"
}
}
},