use super::{ process_table, signal::signals::{kernel::KernelSignal, user::UserSignal}, Pgid, Pid, Process, }; use crate::prelude::*; pub struct ProcessGroup { inner: Mutex, } struct ProcessGroupInner { pgid: Pgid, processes: BTreeMap>, leader_process: Option>, } impl ProcessGroup { fn default() -> Self { ProcessGroup { inner: Mutex::new(ProcessGroupInner { pgid: 0, processes: BTreeMap::new(), leader_process: None, }), } } pub fn new(process: Arc) -> Self { let process_group = ProcessGroup::default(); let pid = process.pid(); process_group.set_pgid(pid); process_group.add_process(process.clone()); process_group.set_leader_process(process); process_group } pub fn set_pgid(&self, pgid: Pgid) { self.inner.lock().pgid = pgid; } pub fn set_leader_process(&self, leader_process: Arc) { self.inner.lock().leader_process = Some(leader_process); } pub fn add_process(&self, process: Arc) { self.inner.lock().processes.insert(process.pid(), process); } pub fn contains_process(&self, pid: Pid) -> bool { self.inner.lock().processes.contains_key(&pid) } /// remove a process from this process group. /// If this group contains no processes now, the group itself will be deleted from global table. pub fn remove_process(&self, pid: Pid) { let mut inner_lock = self.inner.lock(); inner_lock.processes.remove(&pid); let len = inner_lock.processes.len(); let pgid = inner_lock.pgid; // if self contains no process, remove self from table if len == 0 { // this must be the last statement process_table::remove_process_group(pgid); } } pub fn pgid(&self) -> Pgid { self.inner.lock().pgid } /// send kernel signal to all processes in the group pub fn kernel_signal(&self, signal: KernelSignal) { for (_, process) in &self.inner.lock().processes { process.enqueue_signal(Box::new(signal.clone())); } } /// send user signal to all processes in the group pub fn user_signal(&self, signal: UserSignal) { for (_, process) in &self.inner.lock().processes { process.enqueue_signal(Box::new(signal.clone())); } } }