starnix_core/task/
session.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use macro_rules_attribute::apply;
6use starnix_sync::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;
14
15#[derive(Debug)]
16pub struct SessionMutableState {
17    /// The process groups in the session
18    ///
19    /// The references to ProcessGroup is weak to prevent cycles as ProcessGroup have a Arc reference to their
20    /// session.
21    /// It is still expected that these weak references are always valid, as process groups must unregister
22    /// themselves before they are deleted.
23    process_groups: BTreeMap<pid_t, Weak<ProcessGroup>>,
24
25    /// The leader of the foreground process group. This is necessary because the leader must
26    /// be returned even if the process group has already been deleted.
27    foreground_process_group: pid_t,
28
29    /// The controlling terminal of the session.
30    pub controlling_terminal: Option<ControllingTerminal>,
31}
32
33/// A session is a collection of `ProcessGroup` objects that are related to each other. Each
34/// session has a session ID (`sid`), which is a unique identifier for the session.
35///
36/// The session leader is the first `ProcessGroup` in a session. It is responsible for managing the
37/// session, including sending signals to all processes in the session and controlling the
38/// foreground and background process groups.
39///
40/// When a `ProcessGroup` is created, it is automatically added to the session of its parent.
41/// See `setsid(2)` for information about creating sessions.
42///
43/// A session can be destroyed when the session leader exits or when all process groups in the
44/// session are destroyed.
45#[derive(Debug)]
46pub struct Session {
47    /// The leader of the session
48    pub leader: pid_t,
49
50    /// The mutable state of the Session.
51    mutable_state: RwLock<SessionMutableState>,
52}
53
54impl PartialEq for Session {
55    fn eq(&self, other: &Self) -> bool {
56        self.leader == other.leader
57    }
58}
59
60impl Session {
61    pub fn new(leader: pid_t) -> Arc<Session> {
62        Arc::new(Session {
63            leader,
64            mutable_state: RwLock::new(SessionMutableState {
65                process_groups: BTreeMap::new(),
66                foreground_process_group: leader,
67                controlling_terminal: None,
68            }),
69        })
70    }
71
72    state_accessor!(Session, mutable_state);
73}
74
75#[apply(state_implementation!)]
76impl SessionMutableState<Base = Session> {
77    /// Removes the process group from the session. Returns whether the session is empty.
78    pub fn remove(&mut self, pid: pid_t) {
79        self.process_groups.remove(&pid);
80    }
81
82    pub fn insert(&mut self, process_group: &Arc<ProcessGroup>) {
83        self.process_groups.insert(process_group.leader, Arc::downgrade(process_group));
84    }
85
86    pub fn get_foreground_process_group_leader(&self) -> pid_t {
87        self.foreground_process_group
88    }
89
90    pub fn get_foreground_process_group(&self) -> Option<Arc<ProcessGroup>> {
91        self.process_groups.get(&self.foreground_process_group).and_then(Weak::upgrade)
92    }
93
94    pub fn set_foreground_process_group(&mut self, process_group: &Arc<ProcessGroup>) {
95        self.foreground_process_group = process_group.leader;
96    }
97}
98
99/// The controlling terminal of a session.
100#[derive(Clone, Debug)]
101pub struct ControllingTerminal {
102    /// The controlling terminal.
103    pub terminal: Arc<Terminal>,
104    /// Whether the session is associated to the main or replica side of the terminal.
105    pub is_main: bool,
106}
107
108impl ControllingTerminal {
109    pub fn new(terminal: &Terminal, is_main: bool) -> Self {
110        Self { terminal: terminal.to_owned(), is_main }
111    }
112
113    pub fn matches(&self, terminal: &Terminal, is_main: bool) -> bool {
114        std::ptr::eq(terminal, Arc::as_ptr(&self.terminal)) && is_main == self.is_main
115    }
116}