1 use core::intrinsics::likely; 2 3 use alloc::sync::Arc; 4 use system_error::SystemError; 5 6 use crate::{ 7 arch::{ 8 ipc::signal::{SigChildCode, Signal}, 9 sched::sched, 10 CurrentIrqArch, 11 }, 12 exception::InterruptArch, 13 syscall::user_access::UserBufferWriter, 14 }; 15 16 use super::{ 17 abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager, 18 ProcessState, 19 }; 20 21 /// 内核wait4时的参数 22 #[derive(Debug)] 23 pub struct KernelWaitOption<'a> { 24 pub pid_type: PidType, 25 pub pid: Pid, 26 pub options: WaitOption, 27 pub ret_status: i32, 28 pub ret_info: Option<WaitIdInfo>, 29 pub ret_rusage: Option<&'a mut RUsage>, 30 pub no_task_error: Option<SystemError>, 31 } 32 33 #[derive(Debug, Clone)] 34 pub struct WaitIdInfo { 35 pub pid: Pid, 36 pub status: i32, 37 pub cause: i32, 38 } 39 40 impl<'a> KernelWaitOption<'a> { 41 pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self { 42 Self { 43 pid_type, 44 pid, 45 options, 46 ret_status: 0, 47 ret_info: None, 48 ret_rusage: None, 49 no_task_error: None, 50 } 51 } 52 } 53 54 pub fn kernel_wait4( 55 mut pid: i64, 56 wstatus_buf: Option<UserBufferWriter<'_>>, 57 options: WaitOption, 58 rusage_buf: Option<&mut RUsage>, 59 ) -> Result<usize, SystemError> { 60 // i64::MIN is not defined 61 if pid == i64::MIN { 62 return Err(SystemError::ESRCH); 63 } 64 65 // 判断pid类型 66 let pidtype: PidType; 67 68 if pid == -1 { 69 pidtype = PidType::MAX; 70 } else if pid < 0 { 71 pidtype = PidType::PGID; 72 kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); 73 pid = -pid; 74 } else if pid == 0 { 75 pidtype = PidType::PGID; 76 kwarn!("kernel_wait4: currently not support pgid, default to wait for pid\n"); 77 pid = ProcessManager::current_pcb().pid().data() as i64; 78 } else { 79 pidtype = PidType::PID; 80 } 81 82 let pid = Pid(pid as usize); 83 84 // 构造参数 85 let mut kwo = KernelWaitOption::new(pidtype, pid, options); 86 87 kwo.options.insert(WaitOption::WEXITED); 88 kwo.ret_rusage = rusage_buf; 89 90 // 调用do_wait,执行等待 91 let r = do_wait(&mut kwo)?; 92 93 // 如果有wstatus_buf,则将wstatus写入用户空间 94 if let Some(mut wstatus_buf) = wstatus_buf { 95 let wstatus = if let Some(ret_info) = &kwo.ret_info { 96 ret_info.status 97 } else { 98 kwo.ret_status 99 }; 100 wstatus_buf.copy_one_to_user(&wstatus, 0)?; 101 } 102 103 return Ok(r); 104 } 105 106 /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/exit.c#1573 107 fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> { 108 let mut retval: Result<usize, SystemError>; 109 // todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。 110 111 loop { 112 kwo.no_task_error = Some(SystemError::ECHILD); 113 let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD); 114 if kwo.pid_type != PidType::MAX && child_pcb.is_err() { 115 if let Some(err) = &kwo.no_task_error { 116 retval = Err(err.clone()); 117 } else { 118 retval = Ok(0); 119 } 120 121 if !kwo.options.contains(WaitOption::WNOHANG) { 122 retval = Err(SystemError::ERESTARTSYS); 123 if ProcessManager::current_pcb() 124 .sig_info_irqsave() 125 .sig_pending() 126 .has_pending() 127 == false 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 r.is_some() { 145 return r.unwrap(); 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.clone()) }; 162 return Ok(pid.clone().into()); 163 } else { 164 unsafe { pcb.wait_queue.sleep_without_schedule() }; 165 } 166 } 167 drop(irq_guard); 168 sched(); 169 } else { 170 // todo: 对于pgid的处理 171 kwarn!("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 // kdebug!("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 // kdebug!("wait4: to release {pid:?}"); 249 unsafe { ProcessManager::release(pid) }; 250 return Some(Ok(pid.into())); 251 } 252 }; 253 254 return None; 255 } 256