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