123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- use core::intrinsics::likely;
- use alloc::sync::Arc;
- use log::warn;
- use system_error::SystemError;
- use crate::{
- arch::ipc::signal::{SigChildCode, Signal},
- sched::{schedule, SchedMode},
- syscall::user_access::UserBufferWriter,
- time::{sleep::nanosleep, Duration},
- };
- use super::{
- abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager,
- ProcessState,
- };
- /// 内核wait4时的参数
- #[derive(Debug)]
- pub struct KernelWaitOption<'a> {
- pub pid_type: PidType,
- pub pid: Pid,
- pub options: WaitOption,
- pub ret_status: i32,
- pub ret_info: Option<WaitIdInfo>,
- pub ret_rusage: Option<&'a mut RUsage>,
- pub no_task_error: Option<SystemError>,
- }
- #[derive(Debug, Clone)]
- #[allow(dead_code)]
- pub struct WaitIdInfo {
- pub pid: Pid,
- pub status: i32,
- pub cause: i32,
- }
- impl KernelWaitOption<'_> {
- pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self {
- Self {
- pid_type,
- pid,
- options,
- ret_status: 0,
- ret_info: None,
- ret_rusage: None,
- no_task_error: None,
- }
- }
- }
- pub fn kernel_wait4(
- mut pid: i64,
- 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 mut kwo = KernelWaitOption::new(pidtype, pid, options);
- kwo.options.insert(WaitOption::WEXITED);
- kwo.ret_rusage = rusage_buf;
- // 调用do_wait,执行等待
- let r = do_wait(&mut kwo)?;
- // 如果有wstatus_buf,则将wstatus写入用户空间
- if let Some(mut wstatus_buf) = wstatus_buf {
- let wstatus = if let Some(ret_info) = &kwo.ret_info {
- ret_info.status
- } else {
- kwo.ret_status
- };
- wstatus_buf.copy_one_to_user(&wstatus, 0)?;
- }
- return Ok(r);
- }
- /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/exit.c#1573
- 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 {
- retval = Err(err.clone());
- } else {
- retval = Ok(0);
- }
- if retval.is_err() && !kwo.options.contains(WaitOption::WNOHANG) {
- retval = Err(SystemError::ERESTARTSYS);
- if !ProcessManager::current_pcb().has_pending_signal_fast() {
- schedule(SchedMode::SM_PREEMPT);
- // todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。
- continue;
- } else {
- break $outer;
- }
- } else {
- break $outer;
- }
- };
- }
- // todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。
- '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;
- }
- 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;
- }
- }
- nanosleep(Duration::from_millis(100).into())?;
- }
- } else {
- // todo: 对于pgid的处理
- warn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
- return Err(SystemError::EINVAL);
- }
- notask!('outer);
- }
- drop(tmp_child_pcb);
- 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;
- }
- fn do_waitpid(
- child_pcb: Arc<ProcessControlBlock>,
- kwo: &mut KernelWaitOption,
- ) -> Option<Result<usize, SystemError>> {
- let state = child_pcb.sched_info().inner_lock_read_irqsave().state();
- // 获取退出码
- match state {
- ProcessState::Runnable => {
- if kwo.options.contains(WaitOption::WNOHANG)
- || kwo.options.contains(WaitOption::WNOWAIT)
- {
- if let Some(info) = &mut kwo.ret_info {
- *info = WaitIdInfo {
- pid: child_pcb.pid(),
- status: Signal::SIGCONT as i32,
- cause: SigChildCode::Continued.into(),
- };
- } else {
- kwo.ret_status = 0xffff;
- }
- return Some(Ok(0));
- }
- }
- ProcessState::Blocked(_) | ProcessState::Stopped => {
- // todo: 在stopped里面,添加code字段,表示停止的原因
- let exitcode = 0;
- // 由于目前不支持ptrace,因此这个值为false
- let ptrace = false;
- if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) {
- kwo.ret_status = 0;
- return Some(Ok(0));
- }
- if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) {
- kwo.ret_status = (exitcode << 8) | 0x7f;
- }
- if let Some(infop) = &mut kwo.ret_info {
- *infop = WaitIdInfo {
- pid: child_pcb.pid(),
- status: exitcode,
- cause: SigChildCode::Stopped.into(),
- };
- }
- return Some(Ok(child_pcb.pid().data()));
- }
- ProcessState::Exited(status) => {
- let pid = child_pcb.pid();
- // debug!("wait4: child exited, pid: {:?}, status: {status}\n", pid);
- if likely(!kwo.options.contains(WaitOption::WEXITED)) {
- return None;
- }
- // todo: 增加对线程组的group leader的处理
- if let Some(infop) = &mut kwo.ret_info {
- *infop = WaitIdInfo {
- pid,
- status: status as i32,
- cause: SigChildCode::Exited.into(),
- };
- }
- kwo.ret_status = status as i32;
- drop(child_pcb);
- // debug!("wait4: to release {pid:?}");
- unsafe { ProcessManager::release(pid) };
- return Some(Ok(pid.into()));
- }
- };
- return None;
- }
|