Skip to content

Commit

Permalink
bugfix: 修复无法sleep的问题以及进程处于block(true)状态时无法被信号唤醒&唤醒后不处理信号的问题 (#470)
Browse files Browse the repository at this point in the history
  • Loading branch information
fslongjin authored Dec 19, 2023
1 parent 24ff1fa commit 8612b6c
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 36 deletions.
4 changes: 4 additions & 0 deletions kernel/src/arch/x86_64/asm/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,10 @@ ENTRY(syscall_64)

callq *%rdx //调用服务程序

// 将原本要返回的栈帧的栈指针传入do_signal的第一个参数
movq %rsp, %rdi
callq do_signal

cli

// === 恢复调用现场 ===
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/arch/x86_64/ipc/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
28 changes: 15 additions & 13 deletions kernel/src/ipc/signal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,24 +141,25 @@ 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个对应的线程,因此不需要通知进程组内的每个进程。
// todo: 当引入进程组的概念后,需要完善这里,使得它能寻找一个目标进程来唤醒,接着执行信号处理的操作。

// 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.
Expand All @@ -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);
}
}

Expand All @@ -201,15 +202,16 @@ 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;
}

// todo: 检查目标进程是否正在一个cpu上执行,如果是,则返回true,否则继续检查下一项

// 检查目标进程是否有信号正在等待处理,如果是,则返回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;
Expand Down
6 changes: 0 additions & 6 deletions kernel/src/syscall/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()),
Expand Down
29 changes: 28 additions & 1 deletion kernel/src/time/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use core::{fmt, ops};
use core::{
fmt,
ops::{self, Sub},
};

use self::timekeep::ktime_get_real_ns;

Expand Down Expand Up @@ -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
Expand Down
25 changes: 13 additions & 12 deletions kernel/src/time/sleep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
include::bindings::bindings::{useconds_t, Cpu_tsc_freq},
process::ProcessManager,
syscall::SystemError,
time::timekeeping::getnstimeofday,
};

use super::{
Expand All @@ -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
Expand All @@ -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 休眠指定时间(单位:微秒)
Expand Down
2 changes: 1 addition & 1 deletion user/dadk/config/nova_shell-0.1.0.dadk
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"BuildFromSource": {
"Git": {
"url": "https://git.mirrors.dragonos.org.cn/DragonOS-Community/NovaShell.git",
"revision": "95738b235f"
"revision": "4160a0a0de"
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions user/dadk/config/relibc-0.1.0.dadk
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
},
Expand Down

0 comments on commit 8612b6c

Please sign in to comment.