starnix_core/task/
process_group.rs1use crate::mutable_state::{ordered_state_accessor, state_implementation};
6use crate::signals::SignalInfo;
7use crate::task::{PidTable, Session, ThreadGroup};
8use macro_rules_attribute::apply;
9use starnix_sync::{LockBefore, Locked, OrderedRwLock, ProcessGroupState};
10use starnix_uapi::pid_t;
11use starnix_uapi::signals::{SIGCONT, SIGHUP, Signal};
12use std::collections::BTreeMap;
13use std::sync::{Arc, Weak};
14
15#[derive(Debug)]
16pub struct ProcessGroupMutableState {
17 thread_groups: BTreeMap<pid_t, Weak<ThreadGroup>>,
23
24 orphaned: bool,
26}
27
28#[derive(Debug)]
29pub struct ProcessGroup {
30 pub session: Arc<Session>,
32
33 pub leader: pid_t,
35
36 mutable_state: OrderedRwLock<ProcessGroupMutableState, ProcessGroupState>,
38}
39
40impl PartialEq for ProcessGroup {
41 fn eq(&self, other: &Self) -> bool {
42 self.leader == other.leader
43 }
44}
45
46impl Eq for ProcessGroup {}
47
48impl std::hash::Hash for ProcessGroup {
49 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
50 self.leader.hash(state);
51 }
52}
53
54impl ProcessGroup {
72 pub fn new(leader: pid_t, session: Option<Arc<Session>>) -> Arc<ProcessGroup> {
73 let session = session.unwrap_or_else(|| Session::new(leader));
74 let process_group = Arc::new(ProcessGroup {
75 session: session.clone(),
76 leader,
77 mutable_state: OrderedRwLock::new(ProcessGroupMutableState {
78 thread_groups: BTreeMap::new(),
79 orphaned: false,
80 }),
81 });
82 session.write().insert(&process_group);
83 process_group
84 }
85
86 ordered_state_accessor!(ProcessGroup, mutable_state, ProcessGroupState);
87
88 pub fn insert<L>(&self, locked: &mut Locked<L>, thread_group: &ThreadGroup)
89 where
90 L: LockBefore<ProcessGroupState>,
91 {
92 self.write(locked)
93 .thread_groups
94 .insert(thread_group.leader, thread_group.weak_self.clone());
95 }
96
97 pub fn remove<L>(&self, locked: &mut Locked<L>, thread_group: &ThreadGroup) -> bool
99 where
100 L: LockBefore<ProcessGroupState>,
101 {
102 self.write(locked).remove(thread_group)
103 }
104
105 pub fn send_signals<L>(&self, locked: &mut Locked<L>, signals: &[Signal])
106 where
107 L: LockBefore<ProcessGroupState>,
108 {
109 let thread_groups = self.read(locked).thread_groups().collect::<Vec<_>>();
110 Self::send_signals_to_thread_groups(signals, thread_groups);
111 }
112
113 pub fn check_orphaned<L>(&self, locked: &mut Locked<L>, _pids: &PidTable)
119 where
120 L: LockBefore<ProcessGroupState>,
121 {
122 let thread_groups = {
123 let state = self.read(locked);
124 if state.orphaned {
125 return;
126 }
127 state.thread_groups().collect::<Vec<_>>()
128 };
129 for tg in thread_groups {
130 let Some(parent) = tg.read().parent.clone() else {
131 return;
132 };
133 let parent = parent.upgrade();
134 let parent_state = parent.read();
135 if parent_state.process_group.as_ref() != self
136 && parent_state.process_group.session == self.session
137 {
138 return;
139 }
140 }
141 let thread_groups = {
142 let mut state = self.write(locked);
143 if state.orphaned {
144 return;
145 }
146 state.orphaned = true;
147 state.thread_groups().collect::<Vec<_>>()
148 };
149 if thread_groups.iter().any(|tg| tg.load_stopped().is_stopping_or_stopped()) {
150 Self::send_signals_to_thread_groups(&[SIGHUP, SIGCONT], thread_groups);
151 }
152 }
153
154 fn send_signals_to_thread_groups(
155 signals: &[Signal],
156 thread_groups: impl IntoIterator<Item = impl AsRef<ThreadGroup>>,
157 ) {
158 for thread_group in thread_groups.into_iter() {
159 for signal in signals.iter() {
160 thread_group.as_ref().write().send_signal(SignalInfo::default(*signal));
161 }
162 }
163 }
164}
165
166#[apply(state_implementation!)]
167impl ProcessGroupMutableState<Base = ProcessGroup> {
168 pub fn thread_groups(&self) -> Box<dyn Iterator<Item = Arc<ThreadGroup>> + '_> {
169 Box::new(self.thread_groups.values().map(|t| {
170 t.upgrade()
171 .expect("Weak references to thread_groups in ProcessGroup must always be valid")
172 }))
173 }
174
175 fn remove(&mut self, thread_group: &ThreadGroup) -> bool {
177 self.thread_groups.remove(&thread_group.leader);
178
179 self.thread_groups.is_empty()
180 }
181}