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!(
87 ProcessGroup,
88 mutable_state,
89 ProcessGroupState,
90 ProcessGroupMutableState
91 );
92
93 pub fn insert<L>(&self, locked: &mut Locked<L>, thread_group: &ThreadGroup)
94 where
95 L: LockBefore<ProcessGroupState>,
96 {
97 self.write(locked)
98 .thread_groups
99 .insert(thread_group.leader, thread_group.weak_self.clone());
100 }
101
102 pub fn remove<L>(&self, locked: &mut Locked<L>, thread_group: &ThreadGroup) -> bool
104 where
105 L: LockBefore<ProcessGroupState>,
106 {
107 let is_session_leader = self.session.leader == thread_group.leader;
108 let is_empty = self.write(locked).remove(thread_group);
109 if is_session_leader {
110 self.session.disassociate_controlling_terminal(locked);
117 }
118 is_empty
119 }
120
121 pub fn send_signals<L>(&self, locked: &mut Locked<L>, signals: &[Signal])
122 where
123 L: LockBefore<ProcessGroupState>,
124 {
125 let thread_groups = self.read(locked).thread_groups().collect::<Vec<_>>();
126 Self::send_signals_to_thread_groups(signals, thread_groups);
127 }
128
129 pub fn check_orphaned<L>(&self, locked: &mut Locked<L>, _pids: &PidTable)
135 where
136 L: LockBefore<ProcessGroupState>,
137 {
138 let thread_groups = {
139 let state = self.read(locked);
140 if state.orphaned {
141 return;
142 }
143 state.thread_groups().collect::<Vec<_>>()
144 };
145 for tg in thread_groups {
146 let Some(parent) = tg.read().parent.clone() else {
147 return;
148 };
149 let parent = parent.upgrade();
150 let parent_state = parent.read();
151 if parent_state.process_group.as_ref() != self
152 && parent_state.process_group.session == self.session
153 {
154 return;
155 }
156 }
157 let thread_groups = {
158 let mut state = self.write(locked);
159 if state.orphaned {
160 return;
161 }
162 state.orphaned = true;
163 state.thread_groups().collect::<Vec<_>>()
164 };
165 if thread_groups.iter().any(|tg| tg.load_stopped().is_stopping_or_stopped()) {
166 Self::send_signals_to_thread_groups(&[SIGHUP, SIGCONT], thread_groups);
167 }
168 }
169
170 fn send_signals_to_thread_groups(
171 signals: &[Signal],
172 thread_groups: impl IntoIterator<Item = impl AsRef<ThreadGroup>>,
173 ) {
174 for thread_group in thread_groups.into_iter() {
175 for &signal in signals {
176 thread_group.as_ref().write().send_signal(SignalInfo::kernel(signal));
177 }
178 }
179 }
180}
181
182#[apply(state_implementation!)]
183impl ProcessGroupMutableState<Base = ProcessGroup> {
184 pub fn thread_groups(&self) -> Box<dyn Iterator<Item = Arc<ThreadGroup>> + '_> {
185 Box::new(self.thread_groups.values().map(|t| {
186 t.upgrade()
187 .expect("Weak references to thread_groups in ProcessGroup must always be valid")
188 }))
189 }
190
191 fn remove(&mut self, thread_group: &ThreadGroup) -> bool {
193 self.thread_groups.remove(&thread_group.leader);
194
195 self.thread_groups.is_empty()
196 }
197}