blob: 49dca7154a0b3e88dcc297d5720395a43ce797ef [file] [log] [blame] [edit]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use starnix_lock::RwLock;
use std::{
collections::BTreeMap,
sync::{Arc, Weak},
};
use crate::{device::terminal::*, mutable_state::*, task::*, types::*};
#[derive(Debug)]
pub struct SessionMutableState {
/// The process groups in the session
///
/// The references to ProcessGroup is weak to prevent cycles as ProcessGroup have a Arc reference to their
/// session.
/// It is still expected that these weak references are always valid, as process groups must unregister
/// themselves before they are deleted.
process_groups: BTreeMap<pid_t, Weak<ProcessGroup>>,
/// The controlling terminal of the session.
pub controlling_terminal: Option<ControllingTerminal>,
}
/// A session is a collection of `ProcessGroup` objects that are related to each other. Each
/// session has a session ID (`sid`), which is a unique identifier for the session.
///
/// The session leader is the first `ProcessGroup` in a session. It is responsible for managing the
/// session, including sending signals to all processes in the session and controlling the
/// foreground and background process groups.
///
/// When a `ProcessGroup` is created, it is automatically added to the session of its parent.
/// See `setsid(2)` for information about creating sessions.
///
/// A session can be destroyed when the session leader exits or when all process groups in the
/// session are destroyed.
#[derive(Debug)]
pub struct Session {
/// The leader of the session
pub leader: pid_t,
/// The mutable state of the Session.
mutable_state: RwLock<SessionMutableState>,
}
impl PartialEq for Session {
fn eq(&self, other: &Self) -> bool {
self.leader == other.leader
}
}
impl Session {
pub fn new(leader: pid_t) -> Arc<Session> {
Arc::new(Session {
leader,
mutable_state: RwLock::new(SessionMutableState {
process_groups: BTreeMap::new(),
controlling_terminal: None,
}),
})
}
state_accessor!(Session, mutable_state);
}
#[apply(state_implementation!)]
impl SessionMutableState<Base = Session> {
/// Removes the process group from the session. Returns whether the session is empty.
pub fn remove(&mut self, pid: pid_t) {
self.process_groups.remove(&pid);
}
pub fn insert(&mut self, process_group: &Arc<ProcessGroup>) {
self.process_groups.insert(process_group.leader, Arc::downgrade(process_group));
}
}
/// The controlling terminal of a session.
#[derive(Clone, Debug)]
pub struct ControllingTerminal {
/// The controlling terminal.
pub terminal: Arc<Terminal>,
/// Whether the session is associated to the main or replica side of the terminal.
pub is_main: bool,
}
impl ControllingTerminal {
pub fn new(terminal: Arc<Terminal>, is_main: bool) -> Self {
Self { terminal, is_main }
}
}