exit.rs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. use core::intrinsics::likely;
  2. use alloc::sync::Arc;
  3. use log::warn;
  4. use system_error::SystemError;
  5. use crate::{
  6. arch::ipc::signal::{SigChildCode, Signal},
  7. sched::{schedule, SchedMode},
  8. syscall::user_access::UserBufferWriter,
  9. time::{sleep::nanosleep, Duration},
  10. };
  11. use super::{
  12. abi::WaitOption, pid::PidType, resource::RUsage, Pid, ProcessControlBlock, ProcessManager,
  13. ProcessState,
  14. };
  15. /// 内核wait4时的参数
  16. #[derive(Debug)]
  17. pub struct KernelWaitOption<'a> {
  18. pub pid_type: PidType,
  19. pub pid: Pid,
  20. pub options: WaitOption,
  21. pub ret_status: i32,
  22. pub ret_info: Option<WaitIdInfo>,
  23. pub ret_rusage: Option<&'a mut RUsage>,
  24. pub no_task_error: Option<SystemError>,
  25. }
  26. #[derive(Debug, Clone)]
  27. #[allow(dead_code)]
  28. pub struct WaitIdInfo {
  29. pub pid: Pid,
  30. pub status: i32,
  31. pub cause: i32,
  32. }
  33. impl KernelWaitOption<'_> {
  34. pub fn new(pid_type: PidType, pid: Pid, options: WaitOption) -> Self {
  35. Self {
  36. pid_type,
  37. pid,
  38. options,
  39. ret_status: 0,
  40. ret_info: None,
  41. ret_rusage: None,
  42. no_task_error: None,
  43. }
  44. }
  45. }
  46. pub fn kernel_wait4(
  47. mut pid: i64,
  48. wstatus_buf: Option<UserBufferWriter<'_>>,
  49. options: WaitOption,
  50. rusage_buf: Option<&mut RUsage>,
  51. ) -> Result<usize, SystemError> {
  52. // i64::MIN is not defined
  53. if pid == i64::MIN {
  54. return Err(SystemError::ESRCH);
  55. }
  56. // 判断pid类型
  57. let pidtype: PidType;
  58. if pid == -1 {
  59. pidtype = PidType::MAX;
  60. } else if pid < 0 {
  61. pidtype = PidType::PGID;
  62. warn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
  63. pid = -pid;
  64. } else if pid == 0 {
  65. pidtype = PidType::PGID;
  66. warn!("kernel_wait4: currently not support pgid, default to wait for pid\n");
  67. pid = ProcessManager::current_pcb().pid().data() as i64;
  68. } else {
  69. pidtype = PidType::PID;
  70. }
  71. let pid = Pid(pid as usize);
  72. // 构造参数
  73. let mut kwo = KernelWaitOption::new(pidtype, pid, options);
  74. kwo.options.insert(WaitOption::WEXITED);
  75. kwo.ret_rusage = rusage_buf;
  76. // 调用do_wait,执行等待
  77. let r = do_wait(&mut kwo)?;
  78. // 如果有wstatus_buf,则将wstatus写入用户空间
  79. if let Some(mut wstatus_buf) = wstatus_buf {
  80. let wstatus = if let Some(ret_info) = &kwo.ret_info {
  81. ret_info.status
  82. } else {
  83. kwo.ret_status
  84. };
  85. wstatus_buf.copy_one_to_user(&wstatus, 0)?;
  86. }
  87. return Ok(r);
  88. }
  89. /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/exit.c#1573
  90. fn do_wait(kwo: &mut KernelWaitOption) -> Result<usize, SystemError> {
  91. let mut retval: Result<usize, SystemError>;
  92. let mut tmp_child_pcb: Option<Arc<ProcessControlBlock>> = None;
  93. macro_rules! notask {
  94. ($outer: lifetime) => {
  95. if let Some(err) = &kwo.no_task_error {
  96. retval = Err(err.clone());
  97. } else {
  98. retval = Ok(0);
  99. }
  100. if retval.is_err() && !kwo.options.contains(WaitOption::WNOHANG) {
  101. retval = Err(SystemError::ERESTARTSYS);
  102. if !ProcessManager::current_pcb().has_pending_signal_fast() {
  103. schedule(SchedMode::SM_PREEMPT);
  104. // todo: 增加子进程退出的回调后,这里可以直接等待在自身的child_wait等待队列上。
  105. continue;
  106. } else {
  107. break $outer;
  108. }
  109. } else {
  110. break $outer;
  111. }
  112. };
  113. }
  114. // todo: 在signal struct里面增加等待队列,并在这里初始化子进程退出的回调,使得子进程退出时,能唤醒当前进程。
  115. 'outer: loop {
  116. kwo.no_task_error = Some(SystemError::ECHILD);
  117. let child_pcb = ProcessManager::find(kwo.pid).ok_or(SystemError::ECHILD);
  118. if kwo.pid_type != PidType::MAX && child_pcb.is_err() {
  119. notask!('outer);
  120. }
  121. if kwo.pid_type == PidType::PID {
  122. let child_pcb = child_pcb.unwrap();
  123. // 获取weak引用,以便于在do_waitpid中能正常drop pcb
  124. let child_weak = Arc::downgrade(&child_pcb);
  125. let r = do_waitpid(child_pcb, kwo);
  126. if let Some(r) = r {
  127. retval = r;
  128. break 'outer;
  129. } else if let Err(SystemError::ESRCH) = child_weak.upgrade().unwrap().wait_queue.sleep()
  130. {
  131. // log::debug!("do_wait: child_pcb sleep failed");
  132. continue;
  133. }
  134. } else if kwo.pid_type == PidType::MAX {
  135. // 等待任意子进程
  136. // todo: 这里有问题!应当让当前进程sleep到自身的child_wait等待队列上,这样才高效。(还没实现)
  137. let current_pcb = ProcessManager::current_pcb();
  138. loop {
  139. let rd_childen = current_pcb.children.read();
  140. if rd_childen.is_empty() {
  141. break;
  142. }
  143. for pid in rd_childen.iter() {
  144. let pcb = ProcessManager::find(*pid).ok_or(SystemError::ECHILD)?;
  145. let sched_guard = pcb.sched_info().inner_lock_read_irqsave();
  146. let state = sched_guard.state();
  147. if state.is_exited() {
  148. kwo.ret_status = state.exit_code().unwrap() as i32;
  149. kwo.no_task_error = None;
  150. // 由于pcb的drop方法里面要获取父进程的children字段的写锁,所以这里不能直接drop pcb,
  151. // 而是要先break到外层循环,以便释放父进程的children字段的锁,才能drop pcb。
  152. // 否则会死锁。
  153. tmp_child_pcb = Some(pcb.clone());
  154. unsafe { ProcessManager::release(*pid) };
  155. retval = Ok((*pid).into());
  156. break 'outer;
  157. }
  158. }
  159. nanosleep(Duration::from_millis(100).into())?;
  160. }
  161. } else {
  162. // todo: 对于pgid的处理
  163. warn!("kernel_wait4: currently not support {:?}", kwo.pid_type);
  164. return Err(SystemError::EINVAL);
  165. }
  166. notask!('outer);
  167. }
  168. drop(tmp_child_pcb);
  169. ProcessManager::current_pcb()
  170. .sched_info
  171. .inner_lock_write_irqsave()
  172. .set_state(ProcessState::Runnable);
  173. // log::debug!(
  174. // "do_wait, kwo.pid: {}, retval = {:?}, kwo: {:?}",
  175. // kwo.pid,
  176. // retval,
  177. // kwo.no_task_error
  178. // );
  179. return retval;
  180. }
  181. fn do_waitpid(
  182. child_pcb: Arc<ProcessControlBlock>,
  183. kwo: &mut KernelWaitOption,
  184. ) -> Option<Result<usize, SystemError>> {
  185. let state = child_pcb.sched_info().inner_lock_read_irqsave().state();
  186. // 获取退出码
  187. match state {
  188. ProcessState::Runnable => {
  189. if kwo.options.contains(WaitOption::WNOHANG)
  190. || kwo.options.contains(WaitOption::WNOWAIT)
  191. {
  192. if let Some(info) = &mut kwo.ret_info {
  193. *info = WaitIdInfo {
  194. pid: child_pcb.pid(),
  195. status: Signal::SIGCONT as i32,
  196. cause: SigChildCode::Continued.into(),
  197. };
  198. } else {
  199. kwo.ret_status = 0xffff;
  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. if (!ptrace) && (!kwo.options.contains(WaitOption::WUNTRACED)) {
  210. kwo.ret_status = 0;
  211. return Some(Ok(0));
  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. return Some(Ok(child_pcb.pid().data()));
  224. }
  225. ProcessState::Exited(status) => {
  226. let pid = child_pcb.pid();
  227. // debug!("wait4: child exited, pid: {:?}, status: {status}\n", pid);
  228. if likely(!kwo.options.contains(WaitOption::WEXITED)) {
  229. return None;
  230. }
  231. // todo: 增加对线程组的group leader的处理
  232. if let Some(infop) = &mut kwo.ret_info {
  233. *infop = WaitIdInfo {
  234. pid,
  235. status: status as i32,
  236. cause: SigChildCode::Exited.into(),
  237. };
  238. }
  239. kwo.ret_status = status as i32;
  240. drop(child_pcb);
  241. // debug!("wait4: to release {pid:?}");
  242. unsafe { ProcessManager::release(pid) };
  243. return Some(Ok(pid.into()));
  244. }
  245. };
  246. return None;
  247. }