xref: /DragonOS/kernel/src/process/exit.rs (revision 59a6bcf6aee15a11a16431bdf875905c5ecf9157)
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