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