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> {
new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self43 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
kernel_wait4( mut pid: i64, wstatus_buf: Option<UserBufferWriter<'_>>, options: WaitOption, rusage_buf: Option<&mut RUsage>, ) -> Result<usize, SystemError>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
do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError>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
do_waitpid( child_pcb: Arc<ProcessControlBlock>, kwo: &mut KernelWaitOption, ) -> Option<Result<usize, SystemError>>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