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 { 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 let Some(r) = r { 144 return r; 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 let state = pcb.sched_info().inner_lock_read_irqsave().state(); 157 if state.is_exited() { 158 kwo.ret_status = state.exit_code().unwrap() as i32; 159 drop(pcb); 160 unsafe { ProcessManager::release(*pid) }; 161 return Ok((*pid).into()); 162 } else { 163 unsafe { pcb.wait_queue.sleep_without_schedule() }; 164 } 165 } 166 drop(irq_guard); 167 sched(); 168 } else { 169 // todo: 对于pgid的处理 170 kwarn!("kernel_wait4: currently not support {:?}", kwo.pid_type); 171 return Err(SystemError::EINVAL); 172 } 173 } 174 175 return retval; 176 } 177 178 fn do_waitpid( 179 child_pcb: Arc<ProcessControlBlock>, 180 kwo: &mut KernelWaitOption, 181 ) -> Option<Result<usize, SystemError>> { 182 let state = child_pcb.sched_info().inner_lock_read_irqsave().state(); 183 // 获取退出码 184 match state { 185 ProcessState::Runnable => { 186 if kwo.options.contains(WaitOption::WNOHANG) 187 || kwo.options.contains(WaitOption::WNOWAIT) 188 { 189 if let Some(info) = &mut kwo.ret_info { 190 *info = WaitIdInfo { 191 pid: child_pcb.pid(), 192 status: Signal::SIGCONT as i32, 193 cause: SigChildCode::Continued.into(), 194 }; 195 } else { 196 kwo.ret_status = 0xffff; 197 } 198 199 return Some(Ok(0)); 200 } 201 } 202 ProcessState::Blocked(_) | ProcessState::Stopped => { 203 // todo: 在stopped里面,添加code字段,表示停止的原因 204 let exitcode = 0; 205 // 由于目前不支持ptrace,因此这个值为false 206 let ptrace = false; 207 208 if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) { 209 kwo.ret_status = 0; 210 return Some(Ok(0)); 211 } 212 213 if likely(!(kwo.options.contains(WaitOption::WNOWAIT))) { 214 kwo.ret_status = (exitcode << 8) | 0x7f; 215 } 216 if let Some(infop) = &mut kwo.ret_info { 217 *infop = WaitIdInfo { 218 pid: child_pcb.pid(), 219 status: exitcode, 220 cause: SigChildCode::Stopped.into(), 221 }; 222 } 223 224 return Some(Ok(child_pcb.pid().data())); 225 } 226 ProcessState::Exited(status) => { 227 let pid = child_pcb.pid(); 228 // kdebug!("wait4: child exited, pid: {:?}, status: {status}\n", pid); 229 230 if likely(!kwo.options.contains(WaitOption::WEXITED)) { 231 return None; 232 } 233 234 // todo: 增加对线程组的group leader的处理 235 236 if let Some(infop) = &mut kwo.ret_info { 237 *infop = WaitIdInfo { 238 pid, 239 status: status as i32, 240 cause: SigChildCode::Exited.into(), 241 }; 242 } 243 244 kwo.ret_status = status as i32; 245 246 drop(child_pcb); 247 // kdebug!("wait4: to release {pid:?}"); 248 unsafe { ProcessManager::release(pid) }; 249 return Some(Ok(pid.into())); 250 } 251 }; 252 253 return None; 254 } 255