feat(wait): 调整内核wait4函数参数类型 (#1175)

* feat:补充wait4的逻辑,添加对进程组的判断

* fix: 修复进程退出码的返回,将正常退出的进程的退出码移动至高8位

* fix: 移除session和processgroup的debug trait

Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>

* fix: 删除shell.service文件中对于backspace的单独设置

Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>

* fix: 更新exit函数文档,明确状态码移位规则

Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>

---------

Signed-off-by: sparkzky <sparkhhhhhhhhhh@outlook.com>
This commit is contained in:
火花 2025-05-24 13:31:20 +08:00 committed by GitHub
parent ae987c6f9a
commit aa394c1f6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 84 additions and 90 deletions

View File

@ -1,26 +1,23 @@
use core::intrinsics::likely;
use alloc::sync::Arc;
use log::warn;
use core::intrinsics::likely;
use system_error::SystemError;
use crate::{
arch::ipc::signal::{SigChildCode, Signal},
ipc::syscall::PidConverter,
sched::{schedule, SchedMode},
syscall::user_access::UserBufferWriter,
time::{sleep::nanosleep, Duration},
};
use super::{
abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager,
ProcessState,
abi::WaitOption, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, ProcessState,
};
/// 内核wait4时的参数
#[derive(Debug)]
pub struct KernelWaitOption<'a> {
pub pid_type: PidType,
pub pid: Pid,
pub pid_converter: PidConverter,
pub options: WaitOption,
pub ret_status: i32,
pub ret_info: Option<WaitIdInfo>,
@ -37,10 +34,9 @@ pub struct WaitIdInfo {
}
impl KernelWaitOption<'_> {
pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self {
pub fn new(pid_converter: PidConverter, options: WaitOption) -> Self {
Self {
pid_type,
pid,
pid_converter,
options,
ret_status: 0,
ret_info: None,
@ -51,36 +47,15 @@ impl KernelWaitOption<'_> {
}
pub fn kernel_wait4(
mut pid: i64,
pid: i32,
wstatus_buf: Option<UserBufferWriter<'_>>,
options: WaitOption,
rusage_buf: Option<&mut RUsage>,
) -> Result<usize, SystemError> {
// i64::MIN is not defined
if pid == i64::MIN {
return Err(SystemError::ESRCH);
}
// 判断pid类型
let pidtype: PidType;
if pid == -1 {
pidtype = PidType::MAX;
} else if pid < 0 {
pidtype = PidType::PGID;
warn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
pid = -pid;
} else if pid == 0 {
pidtype = PidType::PGID;
warn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
pid = ProcessManager::current_pcb().pid().data() as i64;
} else {
pidtype = PidType::PID;
}
let pid = Pid(pid as usize);
let converter = PidConverter::from_id(pid);
// 构造参数
let mut kwo = KernelWaitOption::new(pidtype, pid, options);
let mut kwo = KernelWaitOption::new(converter, options);
kwo.options.insert(WaitOption::WEXITED);
kwo.ret_rusage = rusage_buf;
@ -131,59 +106,78 @@ 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);
}
if kwo.pid_type == PidType::PID {
let child_pcb = child_pcb.unwrap();
// 获取weak引用以便于在do_waitpid中能正常drop pcb
let child_weak = Arc::downgrade(&child_pcb);
let r = do_waitpid(child_pcb, kwo);
if let Some(r) = r {
retval = r;
break 'outer;
} else if let Err(SystemError::ESRCH) = child_weak.upgrade().unwrap().wait_queue.sleep()
{
// log::debug!("do_wait: child_pcb sleep failed");
continue;
}
} else if kwo.pid_type == PidType::MAX {
// 等待任意子进程
// todo: 这里有问题应当让当前进程sleep到自身的child_wait等待队列上这样才高效。还没实现
let current_pcb = ProcessManager::current_pcb();
loop {
let rd_childen = current_pcb.children.read();
if rd_childen.is_empty() {
break;
match kwo.pid_converter {
PidConverter::Pid(pid) => {
let child_pcb = ProcessManager::find(pid)
.ok_or(SystemError::ECHILD)
.unwrap();
// 获取weak引用以便于在do_waitpid中能正常drop pcb
let child_weak = Arc::downgrade(&child_pcb);
let r: Option<Result<usize, SystemError>> = do_waitpid(child_pcb, kwo);
if let Some(r) = r {
retval = r;
break 'outer;
} else if let Err(SystemError::ESRCH) =
child_weak.upgrade().unwrap().wait_queue.sleep()
{
// log::debug!("do_wait: child_pcb sleep failed");
continue;
}
for pid in rd_childen.iter() {
let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
let sched_guard = pcb.sched_info().inner_lock_read_irqsave();
let state = sched_guard.state();
if state.is_exited() {
kwo.ret_status = state.exit_code().unwrap() as i32;
kwo.no_task_error = None;
// 由于pcb的drop方法里面要获取父进程的children字段的写锁所以这里不能直接drop pcb
// 而是要先break到外层循环以便释放父进程的children字段的锁,才能drop pcb。
// 否则会死锁。
tmp_child_pcb = Some(pcb.clone());
unsafe { ProcessManager::release(*pid) };
retval = Ok((*pid).into());
break 'outer;
}
PidConverter::All => {
// 等待任意子进程
// todo: 这里有问题应当让当前进程sleep到自身的child_wait等待队列上这样才高效。还没实现
let current_pcb = ProcessManager::current_pcb();
loop {
let rd_childen = current_pcb.children.read();
if rd_childen.is_empty() {
break;
}
for pid in rd_childen.iter() {
let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
let sched_guard = pcb.sched_info().inner_lock_read_irqsave();
let state = sched_guard.state();
if state.is_exited() {
kwo.ret_status = state.exit_code().unwrap() as i32;
kwo.no_task_error = None;
// 由于pcb的drop方法里面要获取父进程的children字段的写锁所以这里不能直接drop pcb
// 而是要先break到外层循环以便释放父进程的children字段的锁,才能drop pcb。
// 否则会死锁。
tmp_child_pcb = Some(pcb.clone());
unsafe { ProcessManager::release(*pid) };
retval = Ok((*pid).into());
break 'outer;
}
}
drop(rd_childen);
nanosleep(Duration::from_millis(100).into())?;
}
}
PidConverter::Pgid(pgid) => {
let pg = ProcessManager::find_process_group(pgid).ok_or(SystemError::ESRCH)?;
loop {
let inner = pg.process_group_inner.lock();
for (_, pcb) in inner.processes.iter() {
let sched_guard = pcb.sched_info().inner_lock_read_irqsave();
let state = sched_guard.state();
if state.is_exited() {
kwo.ret_status = state.exit_code().unwrap() as i32;
kwo.no_task_error = None;
// 由于pcb的drop方法里面要获取父进程的children字段的写锁所以这里不能直接drop pcb
// 而是要先break到外层循环以便释放父进程的children字段的锁,才能drop pcb。
// 否则会死锁。
tmp_child_pcb = Some(pcb.clone());
let pid = pcb.pid();
unsafe { ProcessManager::release(pid) };
retval = Ok((pid).into());
break 'outer;
}
}
drop(inner);
nanosleep(Duration::from_millis(100).into())?;
}
drop(rd_childen);
nanosleep(Duration::from_millis(100).into())?;
}
} else {
// todo: 对于pgid的处理
warn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
return Err(SystemError::EINVAL);
}
notask!('outer);
}

View File

@ -404,6 +404,11 @@ impl ProcessManager {
/// ## 参数
///
/// - `exit_code` : 进程的退出码
///
/// ## 注意
/// 对于正常退出的进程,状态码应该先左移八位,以便用户态读取的时候正常返回退出码;而对于被信号终止的进程,状态码则是最低七位,无需进行移位操作。
///
/// 因此注意,传入的`exit_code`应该是已经完成了移位操作的
pub fn exit(exit_code: usize) -> ! {
// 关中断
let _irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };

View File

@ -17,14 +17,12 @@ pub type Pgid = Pid;
pub static ALL_PROCESS_GROUP: SpinLock<Option<HashMap<Pgid, Arc<ProcessGroup>>>> =
SpinLock::new(None);
#[derive(Debug)]
pub struct ProcessGroup {
/// 进程组pgid
pub pgid: Pgid,
pub process_group_inner: SpinLock<PGInner>,
}
#[derive(Debug)]
pub struct PGInner {
pub processes: BTreeMap<Pid, Arc<ProcessControlBlock>>,
pub leader: Option<Arc<ProcessControlBlock>>,

View File

@ -16,13 +16,11 @@ pub type Sid = Pid;
/// 系统中所有会话
pub static ALL_SESSION: SpinLock<Option<HashMap<Sid, Arc<Session>>>> = SpinLock::new(None);
#[derive(Debug)]
pub struct Session {
pub sid: Sid,
pub session_inner: SpinLock<SessionInner>,
}
#[derive(Debug)]
pub struct SessionInner {
pub process_groups: BTreeMap<Pgid, Arc<ProcessGroup>>,
pub leader: Option<Arc<ProcessControlBlock>>,

View File

@ -206,7 +206,7 @@ impl Syscall {
}
pub fn wait4(
pid: i64,
pid: i32,
wstatus: *mut i32,
options: i32,
rusage: *mut c_void,
@ -248,7 +248,7 @@ impl Syscall {
///
/// - status: 退出状态
pub fn exit(status: usize) -> ! {
ProcessManager::exit(status);
ProcessManager::exit((status & 0xff) << 8);
}
/// @brief 获取当前进程的pid

View File

@ -295,7 +295,7 @@ impl Syscall {
let rusage = args[3] as *mut c_void;
// 权限校验
// todo: 引入rusage之后更正以下权限校验代码中rusage的大小
Self::wait4(pid.into(), wstatus, options, rusage)
Self::wait4(pid, wstatus, options, rusage)
}
SYS_EXIT => {

View File

@ -6,6 +6,5 @@ Type=simple
ExecStart=/bin/NovaShell
Restart=always
ExecStartPre=-/bin/about.elf
ExecStartPre=/bin/busybox stty erase 127
Environment=PATH=/bin:/usr/bin:/usr/local/bin
Environment=LD_LIBRARY_PATH=/usr/lib:/usr/lib64:/usr/local/lib