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 let controlling_terminal = {
82 let session_reader = self.read();
83 session_reader.controlling_terminal.clone()
84 };
85
86 if let Some(ct) = controlling_terminal {
87 let mut terminal_state = ct.terminal.write();
88 let mut session_writer = self.write();
89
90 if session_writer
92 .controlling_terminal
93 .as_ref()
94 .map_or(false, |current_ct| current_ct.matches(&ct.terminal, ct.is_main))
95 {
96 session_writer.controlling_terminal = None;
97 terminal_state.controller = None;
98
99 if let Some(pg) = session_writer.get_foreground_process_group() {
100 pg.send_signals(locked, &[SIGHUP, SIGCONT]);
101 }
102 }
103 }
104 }
105
106 state_accessor!(Session, mutable_state);
107}
108
109#[apply(state_implementation!)]
110impl SessionMutableState<Base = Session> {
111 pub fn remove(&mut self, pid: pid_t) {
113 self.process_groups.remove(&pid);
114 }
115
116 pub fn insert(&mut self, process_group: &Arc<ProcessGroup>) {
117 self.process_groups.insert(process_group.leader, Arc::downgrade(process_group));
118 }
119
120 pub fn get_foreground_process_group_leader(&self) -> pid_t {
121 self.foreground_process_group
122 }
123
124 pub fn get_foreground_process_group(&self) -> Option<Arc<ProcessGroup>> {
125 self.process_groups.get(&self.foreground_process_group).and_then(Weak::upgrade)
126 }
127
128 pub fn set_foreground_process_group(&mut self, process_group: &Arc<ProcessGroup>) {
129 self.foreground_process_group = process_group.leader;
130 }
131}
132
133#[derive(Clone, Debug)]
135pub struct ControllingTerminal {
136 pub terminal: Arc<Terminal>,
138 pub is_main: bool,
140}
141
142impl ControllingTerminal {
143 pub fn new(terminal: &Terminal, is_main: bool) -> Self {
144 Self { terminal: terminal.to_owned(), is_main }
145 }
146
147 pub fn matches(&self, terminal: &Terminal, is_main: bool) -> bool {
148 std::ptr::eq(terminal, Arc::as_ptr(&self.terminal)) && is_main == self.is_main
149 }
150}