Skip to content

Commit

Permalink
fix: 修复wait4系统调用部分语义与Linux不一致的问题
Browse files Browse the repository at this point in the history
解决wait不住/wait之后卡死的bug

Signed-off-by: longjin <[email protected]>
  • Loading branch information
fslongjin committed Dec 15, 2024
1 parent 4c72027 commit e548d7c
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 61 deletions.
2 changes: 1 addition & 1 deletion kernel/src/driver/tty/tty_job_control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl TtyJobCtrlManager {
ProcessManager::current_pcb()
.flags()
.insert(ProcessFlags::HAS_PENDING_SIGNAL);

log::debug!("job_ctrl_ioctl: kill. pgid: {pgid}, tty_pgid: {tty_pgid:?}");
return Err(SystemError::ERESTARTSYS);
}
}
Expand Down
4 changes: 2 additions & 2 deletions kernel/src/net/event_poll/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,8 @@ impl EventPoll {
}

// 如果有未处理的信号则返回错误
if current_pcb.sig_info_irqsave().sig_pending().signal().bits() != 0 {
return Err(SystemError::EINTR);
if current_pcb.has_pending_signal_fast() {
return Err(SystemError::ERESTARTSYS);
}

// 还未等待到事件发生,则睡眠
Expand Down
30 changes: 20 additions & 10 deletions kernel/src/process/exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ pub fn kernel_wait4(
fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
let mut retval: Result<usize, SystemError>;
let mut tmp_child_pcb: Option<Arc<ProcessControlBlock>> = None;

macro_rules! notask {
($outer: lifetime) => {
if let Some(err) = &kwo.no_task_error {
Expand All @@ -116,9 +115,8 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
}

if retval.is_err() && !kwo.options.contains(WaitOption::WNOHANG) {
retval = Err(SystemError::EINTR);
// retval = Err(SystemError::ERESTARTSYS);
if !ProcessManager::current_pcb().has_pending_signal() {
retval = Err(SystemError::ERESTARTSYS);
if !ProcessManager::current_pcb().has_pending_signal_fast() {
schedule(SchedMode::SM_PREEMPT);
// todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。
continue;
Expand All @@ -135,6 +133,7 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
'outer: loop {
kwo.no_task_error = Some(SystemError::ECHILD);
let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD);

if kwo.pid_type != PidType::MAX && child_pcb.is_err() {
notask!('outer);
}
Expand All @@ -143,14 +142,14 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
let child_pcb = child_pcb.unwrap();
// 获取weak引用,以便于在do_waitpid中能正常drop pcb
let child_weak = Arc::downgrade(&child_pcb);
log::debug!("do_wait: child_pcb: {:?}", child_pcb.pid());
let r = do_waitpid(child_pcb, kwo);
log::debug!("do_wait: do_waitpid return: {:?}", r);
if let Some(r) = r {
return r;
retval = r;
break 'outer;
} else {
if let Err(SystemError::ESRCH) = child_weak.upgrade().unwrap().wait_queue.sleep() {
return Err(SystemError::ECHILD);
// log::debug!("do_wait: child_pcb sleep failed");
continue;
}
}
} else if kwo.pid_type == PidType::MAX {
Expand Down Expand Up @@ -185,12 +184,23 @@ fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
warn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
return Err(SystemError::EINVAL);
}
log::debug!("xxxx, pending: {}", ProcessManager::current_pcb().has_pending_signal());

notask!('outer);
}

drop(tmp_child_pcb);
log::debug!("do_wait, retval = {:?}, kwo: {:?}", retval, kwo.no_task_error);
ProcessManager::current_pcb()
.sched_info
.inner_lock_write_irqsave()
.set_state(ProcessState::Runnable);

// log::debug!(
// "do_wait, kwo.pid: {}, retval = {:?}, kwo: {:?}",
// kwo.pid,
// retval,
// kwo.no_task_error
// );

return retval;
}

Expand Down
101 changes: 54 additions & 47 deletions kernel/src/process/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,61 +388,68 @@ impl ProcessManager {
/// - `exit_code` : 进程的退出码
pub fn exit(exit_code: usize) -> ! {
// 关中断
let _guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
let pcb = ProcessManager::current_pcb();
let pid = pcb.pid();
pcb.sched_info
.inner_lock_write_irqsave()
.set_state(ProcessState::Exited(exit_code));
pcb.wait_queue.mark_dead();
pcb.wait_queue.wakeup_all(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 _irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
let pid: Pid;
{
let pcb = ProcessManager::current_pcb();
pid = pcb.pid();
pcb.sched_info
.inner_lock_write_irqsave()
.set_state(ProcessState::Exited(exit_code));
pcb.wait_queue.mark_dead();
pcb.wait_queue.wakeup_all(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 {
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
}
// 进行进程退出后的工作
let thread = pcb.thread.write_irqsave();
if let Some(addr) = thread.set_child_tid {
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
}

if let Some(addr) = thread.clear_child_tid {
if Arc::strong_count(&pcb.basic().user_vm().expect("User VM Not found")) > 1 {
let _ =
Futex::futex_wake(addr, FutexFlag::FLAGS_MATCH_NONE, 1, FUTEX_BITSET_MATCH_ANY);
if let Some(addr) = thread.clear_child_tid {
if Arc::strong_count(&pcb.basic().user_vm().expect("User VM Not found")) > 1 {
let _ = Futex::futex_wake(
addr,
FutexFlag::FLAGS_MATCH_NONE,
1,
FUTEX_BITSET_MATCH_ANY,
);
}
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
}
unsafe { clear_user(addr, core::mem::size_of::<i32>()).expect("clear tid failed") };
}

RobustListHead::exit_robust_list(pcb.clone());
RobustListHead::exit_robust_list(pcb.clone());

// 如果是vfork出来的进程,则需要处理completion
if thread.vfork_done.is_some() {
thread.vfork_done.as_ref().unwrap().complete_all();
}
drop(thread);
unsafe { pcb.basic_mut().set_user_vm(None) };
pcb.exit_files();

// TODO 由于未实现进程组,tty记录的前台进程组等于当前进程,故退出前要置空
// 后续相关逻辑需要在SYS_EXIT_GROUP系统调用中实现
if let Some(tty) = pcb.sig_info_irqsave().tty() {
// 临时解决方案!!! 临时解决方案!!! 引入进程组之后,要重写这个更新前台进程组的逻辑
let mut g = tty.core().contorl_info_irqsave();
if g.pgid == Some(pid) {
g.pgid = None;
// 如果是vfork出来的进程,则需要处理completion
if thread.vfork_done.is_some() {
thread.vfork_done.as_ref().unwrap().complete_all();
}
drop(thread);
unsafe { pcb.basic_mut().set_user_vm(None) };
pcb.exit_files();

// TODO 由于未实现进程组,tty记录的前台进程组等于当前进程,故退出前要置空
// 后续相关逻辑需要在SYS_EXIT_GROUP系统调用中实现
if let Some(tty) = pcb.sig_info_irqsave().tty() {
// 临时解决方案!!! 临时解决方案!!! 引入进程组之后,要重写这个更新前台进程组的逻辑
let mut g = tty.core().contorl_info_irqsave();
if g.pgid == Some(pid) {
g.pgid = None;
}
}
pcb.sig_info_mut().set_tty(None);

drop(pcb);
ProcessManager::exit_notify();
}
pcb.sig_info_mut().set_tty(None);

drop(pcb);
ProcessManager::exit_notify();
// unsafe { CurrentIrqArch::interrupt_enable() };
__schedule(SchedMode::SM_NONE);
error!("pid {pid:?} exited but sched again!");
#[allow(clippy::empty_loop)]
Expand Down
2 changes: 1 addition & 1 deletion user/dadk/config/nova_shell-0.1.0.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ source = "git"
source-path = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/NovaShell.git"
# git标签或分支
# 注意: branch和revision只能二选一,且source要设置为"git"
revision = "cb835e03e4"
revision = "feaebefaef"
# 构建相关信息
[build]
# (可选)构建命令
Expand Down

0 comments on commit e548d7c

Please sign in to comment.