starnix_core/task/
session.rs1use macro_rules_attribute::apply;
6use starnix_sync::{LockBefore, Locked, ProcessGroupState, RwLock};
7use std::collections::BTreeMap;
8use std::sync::{Arc, Weak};
9
10use crate::device::terminal::Terminal;
11use crate::mutable_state::{state_accessor, state_implementation};
12use crate::task::ProcessGroup;
13use starnix_uapi::pid_t;
14use starnix_uapi::signals::{SIGCONT, SIGHUP};
15
16#[derive(Debug)]
17pub struct SessionMutableState {
18 process_groups: BTreeMap<pid_t, Weak<ProcessGroup>>,
25
26 foreground_process_group: pid_t,
29
30 pub controlling_terminal: Option<ControllingTerminal>,
32}
33
34#[derive(Debug)]
47pub struct Session {
48 pub leader: pid_t,
50
51 mutable_state: RwLock<SessionMutableState>,
53}
54
55impl PartialEq for Session {
56 fn eq(&self, other: &Self) -> bool {
57 self.leader == other.leader
58 }
59}
60
61impl Session {
62 pub fn new(leader: pid_t) -> Arc<Session> {
63 Arc::new(Session {
64 leader,
65 mutable_state: RwLock::new(SessionMutableState {
66 process_groups: BTreeMap::new(),
67 foreground_process_group: leader,
68 controlling_terminal: None,
69 }),
70 })
71 }
72
73 pub fn disassociate_controlling_terminal<L>(&self, locked: &mut Locked<L>)
75 where
76 L: LockBefore<ProcessGroupState>,
77 {
78 loop {
79 let Some(controlling_terminal) = self.read().controlling_terminal.clone() else {
84 return;
85 };
86 let mut terminal_state = controlling_terminal.terminal.write();
87 let mut state = self.write();
88
89 if !state.controlling_terminal.as_ref().map_or(false, |current_ct| {
92 current_ct.matches(&controlling_terminal.terminal, controlling_terminal.is_main)
93 }) {
94 continue;
96 }
97
98 state.controlling_terminal = None;
99 terminal_state.controller = None;
100
101 let process_group = state.get_foreground_process_group();
104 drop(state);
105 drop(terminal_state);
106 if let Some(pg) = process_group {
107 pg.send_signals(locked, &[SIGHUP, SIGCONT]);
108 }
109 return;
110 }
111 }
112
113 state_accessor!(Session, mutable_state);
114}
115
116#[apply(state_implementation!)]
117impl SessionMutableState<Base = Session> {
118 pub fn remove(&mut self, pid: pid_t) {
120 self.process_groups.remove(&pid);
121 }
122
123 pub fn insert(&mut self, process_group: &Arc<ProcessGroup>) {
124 self.process_groups.insert(process_group.leader, Arc::downgrade(process_group));
125 }
126
127 pub fn get_foreground_process_group_leader(&self) -> pid_t {
128 self.foreground_process_group
129 }
130
131 pub fn get_foreground_process_group(&self) -> Option<Arc<ProcessGroup>> {
132 self.process_groups.get(&self.foreground_process_group).and_then(Weak::upgrade)
133 }
134
135 pub fn set_foreground_process_group(&mut self, process_group: &Arc<ProcessGroup>) {
136 self.foreground_process_group = process_group.leader;
137 }
138}
139
140#[derive(Clone, Debug)]
142pub struct ControllingTerminal {
143 pub terminal: Arc<Terminal>,
145 pub is_main: bool,
147}
148
149impl ControllingTerminal {
150 pub fn new(terminal: &Terminal, is_main: bool) -> Self {
151 Self { terminal: terminal.to_owned(), is_main }
152 }
153
154 pub fn matches(&self, terminal: &Terminal, is_main: bool) -> bool {
155 std::ptr::eq(terminal, Arc::as_ptr(&self.terminal)) && is_main == self.is_main
156 }
157}