| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- use core::sync::atomic::Ordering;
- use super::{Process, ProcessGroup, Session, Thread, WaitObject, WaitType};
- use crate::{
- kernel::{task::futex_wake, user::UserPointerMut},
- rcu::rcu_sync,
- };
- use alloc::{
- collections::btree_map::BTreeMap,
- sync::{Arc, Weak},
- };
- use eonix_runtime::task::Task;
- use eonix_sync::{AsProof as _, AsProofMut as _, RwLock};
- pub struct ProcessList {
- /// The init process.
- init: Option<Arc<Process>>,
- /// All threads.
- threads: BTreeMap<u32, Arc<Thread>>,
- /// All processes.
- processes: BTreeMap<u32, Weak<Process>>,
- /// All process groups.
- pgroups: BTreeMap<u32, Weak<ProcessGroup>>,
- /// All sessions.
- sessions: BTreeMap<u32, Weak<Session>>,
- }
- static GLOBAL_PROC_LIST: RwLock<ProcessList> = RwLock::new(ProcessList {
- init: None,
- threads: BTreeMap::new(),
- processes: BTreeMap::new(),
- pgroups: BTreeMap::new(),
- sessions: BTreeMap::new(),
- });
- impl ProcessList {
- pub fn get() -> &'static RwLock<Self> {
- &GLOBAL_PROC_LIST
- }
- pub fn add_session(&mut self, session: &Arc<Session>) {
- self.sessions.insert(session.sid, Arc::downgrade(session));
- }
- pub fn add_pgroup(&mut self, pgroup: &Arc<ProcessGroup>) {
- self.pgroups.insert(pgroup.pgid, Arc::downgrade(pgroup));
- }
- pub fn add_process(&mut self, process: &Arc<Process>) {
- self.processes.insert(process.pid, Arc::downgrade(process));
- }
- pub fn add_thread(&mut self, thread: &Arc<Thread>) {
- self.threads.insert(thread.tid, thread.clone());
- }
- pub fn remove_process(&mut self, pid: u32) {
- // Thread group leader has the same tid as the pid.
- if let Some(thread) = self.threads.remove(&pid) {
- self.processes.remove(&pid);
- // SAFETY: We wait until all references are dropped below with `rcu_sync()`.
- let session = unsafe { thread.process.session.swap(None) }.unwrap();
- let pgroup = unsafe { thread.process.pgroup.swap(None) }.unwrap();
- let _parent = unsafe { thread.process.parent.swap(None) }.unwrap();
- pgroup.remove_member(pid, self.prove_mut());
- Task::block_on(rcu_sync());
- if Arc::strong_count(&pgroup) == 1 {
- self.pgroups.remove(&pgroup.pgid);
- }
- if Arc::strong_count(&session) == 1 {
- self.sessions.remove(&session.sid);
- }
- } else {
- panic!("Process {} not found", pid);
- }
- }
- pub fn set_init_process(&mut self, init: Arc<Process>) {
- let old_init = self.init.replace(init);
- assert!(old_init.is_none(), "Init process already set");
- }
- pub fn init_process(&self) -> &Arc<Process> {
- self.init.as_ref().unwrap()
- }
- pub fn try_find_thread(&self, tid: u32) -> Option<&Arc<Thread>> {
- self.threads.get(&tid)
- }
- pub fn try_find_process(&self, pid: u32) -> Option<Arc<Process>> {
- self.processes.get(&pid).and_then(Weak::upgrade)
- }
- pub fn try_find_pgroup(&self, pgid: u32) -> Option<Arc<ProcessGroup>> {
- self.pgroups.get(&pgid).and_then(Weak::upgrade)
- }
- pub fn try_find_session(&self, sid: u32) -> Option<Arc<Session>> {
- self.sessions.get(&sid).and_then(Weak::upgrade)
- }
- /// Make the process a zombie and notify the parent.
- /// # Safety
- /// This function will destroy the process and all its threads.
- /// It is the caller's responsibility to ensure that the process is not
- /// running or will not run after this function is called.
- pub async unsafe fn do_exit(
- &mut self,
- thread: &Thread,
- exit_status: WaitType,
- is_exiting_group: bool,
- ) {
- let process = thread.process.clone();
- if process.pid == 1 {
- panic!("init exited");
- }
- let inner = process.inner.access_mut(self.prove_mut());
- thread.dead.store(true, Ordering::SeqCst);
- if is_exiting_group {
- // TODO: Send SIGKILL to all threads.
- // todo!()
- }
- if thread.tid != process.pid {
- self.threads.remove(&thread.tid);
- inner.threads.remove(&thread.tid).unwrap();
- }
- if let Some(clear_ctid) = thread.get_clear_ctid() {
- UserPointerMut::new(clear_ctid as *mut u32)
- .unwrap()
- .write(0u32)
- .expect("should clear child tid successfully");
- futex_wake(clear_ctid, None, 1)
- .await
- .expect("should wake up child tid");
- }
- if let Some(robust_list) = thread.get_robust_list() {
- let _ = robust_list.wake_all().await;
- }
- // main thread exit
- if thread.tid == process.pid {
- assert_eq!(thread.tid, process.pid);
- thread.files.close_all();
- // If we are the session leader, we should drop the control terminal.
- if process.session(self.prove()).sid == process.pid {
- if let Some(terminal) =
- Task::block_on(process.session(self.prove()).drop_control_terminal())
- {
- terminal.drop_session();
- }
- }
- // Release the MMList as well as the page table.
- unsafe {
- // SAFETY: We are exiting the process, so no one might be using it.
- process.mm_list.replace(None);
- }
- // Make children orphans (adopted by init)
- {
- let init = self.init_process();
- inner.children.retain(|_, child| {
- let child = child.upgrade().unwrap();
- // SAFETY: `child.parent` must be ourself. So we don't need to free it.
- unsafe { child.parent.swap(Some(init.clone())) };
- init.add_child(&child, self.prove_mut());
- false
- });
- }
- let mut init_notify = self.init_process().notify_batch();
- process
- .wait_list
- .drain_exited()
- .into_iter()
- .for_each(|item| init_notify.notify(item));
- init_notify.finish(self.prove());
- process.parent(self.prove()).notify(
- process.exit_signal,
- WaitObject {
- pid: process.pid,
- code: exit_status,
- },
- self.prove(),
- );
- }
- }
- }
|