1 use core::intrinsics::likely; 2 3 use alloc::sync::Arc; 4 use log::warn; 5 use system_error::SystemError; 6 7 use crate::{ 8 arch::{ 9 ipc::signal::{SigChildCode, Signal}, 10 CurrentIrqArch, 11 }, 12 exception::InterruptArch, 13 sched::{schedule, SchedMode}, 14 syscall::user_access::UserBufferWriter, 15 }; 16 17 use super::{ 18 abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, 19 ProcessState, 20 }; 21 22 /// 内核wait4时的参数 23 #[derive(Debug)] 24 pub struct KernelWaitOption<'a> { 25 pub pid_type: PidType, 26 pub pid: Pid, 27 pub options: WaitOption, 28 pub ret_status: i32, 29 pub ret_info: Option<WaitIdInfo>, 30 pub ret_rusage: Option<&'a mut RUsage>, 31 pub no_task_error: Option<SystemError>, 32 } 33 34 #[derive(Debug, Clone)] 35 pub struct WaitIdInfo { 36 pub pid: Pid, 37 pub status: i32, 38 pub cause: i32, 39 } 40 41 impl<'a> KernelWaitOption<'a> { 42 pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self { 43 Self { 44 pid_type, 45 pid, 46 options, 47 ret_status: 0, 48 ret_info: None, 49 ret_rusage: None, 50 no_task_error: None, 51 } 52 } 53 } 54 55 pub fn kernel_wait4( 56 mut pid: i64, 57 wstatus_buf: Option<UserBufferWriter<'_>>, 58 options: WaitOption, 59 rusage_buf: Option<&mut RUsage>, 60 ) -> Result<usize, SystemError> { 61 // i64::MIN is not defined 62 if pid == i64::MIN { 63 return Err(SystemError::ESRCH); 64 } 65 66 // 判断pid类型 67 let pidtype: PidType; 68 69 if pid == -1 { 70 pidtype = PidType::MAX; 71 } else if pid < 0 { 72 pidtype = PidType::PGID; 73 warn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); 74 pid = -pid; 75 } else if pid == 0 { 76 pidtype = PidType::PGID; 77 warn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); 78 pid = ProcessManager::current_pcb().pid().data() as i64; 79 } else { 80 pidtype = PidType::PID; 81 } 82 83 let pid = Pid(pid as usize); 84 85 // 构造参数 86 let mut kwo = KernelWaitOption::new(pidtype, pid, options); 87 88 kwo.options.insert(WaitOption::WEXITED); 89 kwo.ret_rusage = rusage_buf; 90 91 // 调用do_wait,执行等待 92 let r = do_wait(&mut kwo)?; 93 94 // 如果有wstatus_buf,则将wstatus写入用户空间 95 if let Some(mut wstatus_buf) = wstatus_buf { 96 let wstatus = if let Some(ret_info) = &kwo.ret_info { 97 ret_info.status 98 } else { 99 kwo.ret_status 100 }; 101 wstatus_buf.copy_one_to_user(&wstatus, 0)?; 102 } 103 104 return Ok(r); 105 } 106 107 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/exit.c#1573 108 fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> { 109 let mut retval: Result<usize, SystemError>; 110 // todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。 111 112 loop { 113 kwo.no_task_error = Some(SystemError::ECHILD); 114 let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD); 115 if kwo.pid_type != PidType::MAX && child_pcb.is_err() { 116 if let Some(err) = &kwo.no_task_error { 117 retval = Err(err.clone()); 118 } else { 119 retval = Ok(0); 120 } 121 122 if !kwo.options.contains(WaitOption::WNOHANG) { 123 retval = Err(SystemError::ERESTARTSYS); 124 if !ProcessManager::current_pcb() 125 .sig_info_irqsave() 126 .sig_pending() 127 .has_pending() 128 { 129 // todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。 130 continue; 131 } else { 132 break; 133 } 134 } else { 135 break; 136 } 137 } 138 139 if kwo.pid_type == PidType::PID { 140 let child_pcb = child_pcb.unwrap(); 141 // 获取weak引用,以便于在do_waitpid中能正常drop pcb 142 let child_weak = Arc::downgrade(&child_pcb); 143 let r = do_waitpid(child_pcb, kwo); 144 if let Some(r) = r { 145 return r; 146 } else { 147 child_weak.upgrade().unwrap().wait_queue.sleep(); 148 } 149 } else if kwo.pid_type == PidType::MAX { 150 // 等待任意子进程 151 // todo: 这里有问题!如果正在for循环的过程中,子进程退出了,可能会导致父进程永远等待。 152 let current_pcb = ProcessManager::current_pcb(); 153 let rd_childen = current_pcb.children.read(); 154 let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() }; 155 for pid in rd_childen.iter() { 156 let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?; 157 let state = pcb.sched_info().inner_lock_read_irqsave().state(); 158 if state.is_exited() { 159 kwo.ret_status = state.exit_code().unwrap() as i32; 160 drop(pcb); 161 unsafe { ProcessManager::release(*pid) }; 162 return Ok((*pid).into()); 163 } else { 164 unsafe { pcb.wait_queue.sleep_without_schedule() }; 165 } 166 } 167 drop(irq_guard); 168 schedule(SchedMode::SM_NONE); 169 } else { 170 // todo: 对于pgid的处理 171 warn!("kernel_wait4: currently not support {:?}", kwo.pid_type); 172 return Err(SystemError::EINVAL); 173 } 174 } 175 176 return retval; 177 } 178 179 fn do_waitpid( 180 child_pcb: Arc<ProcessControlBlock>, 181 kwo: &mut KernelWaitOption, 182 ) -> Option<Result<usize, SystemError>> { 183 let state = child_pcb.sched_info().inner_lock_read_irqsave().state(); 184 // 获取退出码 185 match state { 186 ProcessState::Runnable => { 187 if kwo.options.contains(WaitOption::WNOHANG) 188 || kwo.options.contains(WaitOption::WNOWAIT) 189 { 190 if let Some(info) = &mut kwo.ret_info { 191 *info = WaitIdInfo { 192 pid: child_pcb.pid(), 193 status: Signal::SIGCONT as i32, 194 cause: SigChildCode::Continued.into(), 195 }; 196 } else { 197 kwo.ret_status = 0xffff; 198 } 199 200 return Some(Ok(0)); 201 } 202 } 203 ProcessState::Blocked(_) | ProcessState::Stopped => { 204 // todo: 在stopped里面,添加code字段,表示停止的原因 205 let exitcode = 0; 206 // 由于目前不支持ptrace,因此这个值为false 207 let ptrace = false; 208 209 if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) { 210 kwo.ret_status = 0; 211 return Some(Ok(0)); 212 } 213 214 if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { 215 kwo.ret_status = (exitcode << 8) | 0x7f; 216 } 217 if let Some(infop) = &mut kwo.ret_info { 218 *infop = WaitIdInfo { 219 pid: child_pcb.pid(), 220 status: exitcode, 221 cause: SigChildCode::Stopped.into(), 222 }; 223 } 224 225 return Some(Ok(child_pcb.pid().data())); 226 } 227 ProcessState::Exited(status) => { 228 let pid = child_pcb.pid(); 229 // debug!("wait4: child exited, pid: {:?}, status: {status}\n", pid); 230 231 if likely(!kwo.options.contains(WaitOption::WEXITED)) { 232 return None; 233 } 234 235 // todo: 增加对线程组的group leader的处理 236 237 if let Some(infop) = &mut kwo.ret_info { 238 *infop = WaitIdInfo { 239 pid, 240 status: status as i32, 241 cause: SigChildCode::Exited.into(), 242 }; 243 } 244 245 kwo.ret_status = status as i32; 246 247 drop(child_pcb); 248 // debug!("wait4: to release {pid:?}"); 249 unsafe { ProcessManager::release(pid) }; 250 return Some(Ok(pid.into())); 251 } 252 }; 253 254 return None; 255 } 256