mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 10:53:25 +00:00
Add basic structures for session, terminal and job control
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
2edbe1f725
commit
9040fb54ea
@ -275,15 +275,31 @@ fn clone_child_process(parent_context: UserContext, clone_args: CloneArgs) -> Re
|
||||
.file_table(child_file_table)
|
||||
.fs(child_fs)
|
||||
.umask(child_umask)
|
||||
.sig_dispositions(child_sig_dispositions)
|
||||
.process_group(current.process_group().unwrap());
|
||||
.sig_dispositions(child_sig_dispositions);
|
||||
|
||||
process_builder.build()?
|
||||
};
|
||||
|
||||
current!().add_child(child.clone());
|
||||
process_table::add_process(child.clone());
|
||||
// Adds child to parent's process group, and parent's child processes.
|
||||
let process_group = current!().process_group().unwrap();
|
||||
|
||||
let mut process_table_mut = process_table::process_table_mut();
|
||||
let mut group_inner = process_group.inner.lock();
|
||||
let mut child_group_mut = child.process_group.lock();
|
||||
let mut children_mut = current.children().lock();
|
||||
|
||||
children_mut.insert(child.pid(), child.clone());
|
||||
|
||||
group_inner.processes.insert(child.pid(), child.clone());
|
||||
*child_group_mut = Arc::downgrade(&process_group);
|
||||
|
||||
process_table_mut.insert(child.pid(), child.clone());
|
||||
drop(process_table_mut);
|
||||
drop(group_inner);
|
||||
drop(child_group_mut);
|
||||
drop(children_mut);
|
||||
|
||||
// Deals with clone flags
|
||||
let child_thread = thread_table::tid_to_thread(child_tid).unwrap();
|
||||
let child_posix_thread = child_thread.as_posix_thread().unwrap();
|
||||
clone_parent_settid(child_tid, clone_args.parent_tidptr, clone_flags)?;
|
||||
|
@ -37,9 +37,11 @@ pub fn do_exit_group(term_status: TermStatus) {
|
||||
// Move children to the init process
|
||||
if !is_init_process(¤t) {
|
||||
if let Some(init_process) = get_init_process() {
|
||||
let mut init_children = init_process.children().lock();
|
||||
for (_, child_process) in current.children().lock().extract_if(|_, _| true) {
|
||||
child_process.set_parent(Arc::downgrade(&init_process));
|
||||
init_process.add_child(child_process);
|
||||
let mut parent = child_process.parent.lock();
|
||||
init_children.insert(child_process.pid(), child_process.clone());
|
||||
*parent = Arc::downgrade(&init_process);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -56,7 +58,7 @@ const INIT_PROCESS_PID: Pid = 1;
|
||||
|
||||
/// Get the init process
|
||||
fn get_init_process() -> Option<Arc<Process>> {
|
||||
process_table::pid_to_process(INIT_PROCESS_PID)
|
||||
process_table::get_process(&INIT_PROCESS_PID)
|
||||
}
|
||||
|
||||
fn is_init_process(process: &Process) -> bool {
|
||||
|
@ -4,7 +4,6 @@ pub mod posix_thread;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod process;
|
||||
mod process_filter;
|
||||
mod process_group;
|
||||
pub mod process_table;
|
||||
mod process_vm;
|
||||
mod program_loader;
|
||||
@ -17,9 +16,10 @@ mod wait;
|
||||
pub use clone::{clone_child, CloneArgs, CloneFlags};
|
||||
pub use exit::do_exit_group;
|
||||
pub use process::ProcessBuilder;
|
||||
pub use process::{current, ExitCode, Pgid, Pid, Process};
|
||||
pub use process::{
|
||||
current, ExitCode, JobControl, Pgid, Pid, Process, ProcessGroup, Session, Sid, Terminal,
|
||||
};
|
||||
pub use process_filter::ProcessFilter;
|
||||
pub use process_group::ProcessGroup;
|
||||
pub use program_loader::{check_executable_file, load_program_to_vm};
|
||||
pub use rlimit::ResourceType;
|
||||
pub use term_status::TermStatus;
|
||||
|
@ -1,12 +1,10 @@
|
||||
use crate::fs::file_table::FileTable;
|
||||
use crate::fs::fs_resolver::FsResolver;
|
||||
use crate::fs::utils::FileCreationMask;
|
||||
use crate::process::posix_thread::PosixThreadBuilder;
|
||||
use crate::process::process_group::ProcessGroup;
|
||||
use crate::process::process_table;
|
||||
use crate::process::posix_thread::{PosixThreadBuilder, PosixThreadExt};
|
||||
use crate::process::process_vm::ProcessVm;
|
||||
use crate::process::rlimit::ResourceLimits;
|
||||
use crate::process::{posix_thread::PosixThreadExt, signal::sig_disposition::SigDispositions};
|
||||
use crate::process::signal::sig_disposition::SigDispositions;
|
||||
use crate::thread::Thread;
|
||||
|
||||
use super::{Pid, Process};
|
||||
@ -23,7 +21,6 @@ pub struct ProcessBuilder<'a> {
|
||||
argv: Option<Vec<CString>>,
|
||||
envp: Option<Vec<CString>>,
|
||||
process_vm: Option<ProcessVm>,
|
||||
process_group: Option<Arc<ProcessGroup>>,
|
||||
file_table: Option<Arc<Mutex<FileTable>>>,
|
||||
fs: Option<Arc<RwLock<FsResolver>>>,
|
||||
umask: Option<Arc<RwLock<FileCreationMask>>>,
|
||||
@ -41,7 +38,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
argv: None,
|
||||
envp: None,
|
||||
process_vm: None,
|
||||
process_group: None,
|
||||
file_table: None,
|
||||
fs: None,
|
||||
umask: None,
|
||||
@ -60,11 +56,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn process_group(&mut self, process_group: Arc<ProcessGroup>) -> &mut Self {
|
||||
self.process_group = Some(process_group);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn file_table(&mut self, file_table: Arc<Mutex<FileTable>>) -> &mut Self {
|
||||
self.file_table = Some(file_table);
|
||||
self
|
||||
@ -126,7 +117,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
argv,
|
||||
envp,
|
||||
process_vm,
|
||||
process_group,
|
||||
file_table,
|
||||
fs,
|
||||
umask,
|
||||
@ -136,10 +126,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
|
||||
let process_vm = process_vm.or_else(|| Some(ProcessVm::alloc())).unwrap();
|
||||
|
||||
let process_group_ref = process_group
|
||||
.as_ref()
|
||||
.map_or_else(Weak::new, Arc::downgrade);
|
||||
|
||||
let file_table = file_table
|
||||
.or_else(|| Some(Arc::new(Mutex::new(FileTable::new_with_stdio()))))
|
||||
.unwrap();
|
||||
@ -168,7 +154,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
threads,
|
||||
executable_path.to_string(),
|
||||
process_vm,
|
||||
process_group_ref,
|
||||
file_table,
|
||||
fs,
|
||||
umask,
|
||||
@ -194,15 +179,6 @@ impl<'a> ProcessBuilder<'a> {
|
||||
|
||||
process.threads().lock().push(thread);
|
||||
|
||||
if let Some(process_group) = process_group {
|
||||
process_group.add_process(process.clone());
|
||||
} else {
|
||||
let new_process_group = Arc::new(ProcessGroup::new(process.clone()));
|
||||
let pgid = new_process_group.pgid();
|
||||
process.set_process_group(Arc::downgrade(&new_process_group));
|
||||
process_table::add_process_group(new_process_group);
|
||||
}
|
||||
|
||||
process.set_runnable();
|
||||
|
||||
Ok(process)
|
||||
|
140
services/libs/jinux-std/src/process/process/job_control.rs
Normal file
140
services/libs/jinux-std/src/process/process/job_control.rs
Normal file
@ -0,0 +1,140 @@
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::constants::{SIGCONT, SIGHUP};
|
||||
use crate::process::signal::signals::kernel::KernelSignal;
|
||||
use crate::process::{ProcessGroup, Session};
|
||||
|
||||
/// The job control for terminals like tty and pty.
|
||||
///
|
||||
/// This struct is used to support shell job control, which allows users to
|
||||
/// run commands in the foreground or in the background. This struct manages
|
||||
/// the session and foreground process group for a terminal.
|
||||
pub struct JobControl {
|
||||
foreground: SpinLock<Weak<ProcessGroup>>,
|
||||
session: SpinLock<Weak<Session>>,
|
||||
}
|
||||
|
||||
impl JobControl {
|
||||
/// Creates a new `TtyJobControl`
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
foreground: SpinLock::new(Weak::new()),
|
||||
session: SpinLock::new(Weak::new()),
|
||||
}
|
||||
}
|
||||
|
||||
// *************** Session ***************
|
||||
|
||||
/// Returns the session whose controlling terminal is the terminal.
|
||||
fn session(&self) -> Option<Arc<Session>> {
|
||||
self.session.lock().upgrade()
|
||||
}
|
||||
|
||||
/// Sets the terminal as the controlling terminal of the `session`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This terminal should not belong to any session.
|
||||
pub fn set_session(&self, session: &Arc<Session>) {
|
||||
debug_assert!(self.session().is_none());
|
||||
*self.session.lock() = Arc::downgrade(session);
|
||||
}
|
||||
|
||||
/// Sets the terminal as the controlling terminal of the session of current process.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This function should only be called in process context.
|
||||
pub fn set_current_session(&self) -> Result<()> {
|
||||
if self.session().is_some() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"the terminal is already controlling terminal of another session"
|
||||
);
|
||||
}
|
||||
|
||||
let current = current!();
|
||||
|
||||
let process_group = current.process_group().unwrap();
|
||||
*self.foreground.lock() = Arc::downgrade(&process_group);
|
||||
|
||||
let session = current.session().unwrap();
|
||||
*self.session.lock() = Arc::downgrade(&session);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Releases the current session from this terminal.
|
||||
pub fn release_current_session(&self) -> Result<()> {
|
||||
let Some(session) = self.session() else {
|
||||
return_errno_with_message!(
|
||||
Errno::ENOTTY,
|
||||
"the terminal is not controlling terminal now"
|
||||
);
|
||||
};
|
||||
|
||||
if let Some(foreground) = self.foreground() {
|
||||
foreground.kernel_signal(KernelSignal::new(SIGHUP));
|
||||
foreground.kernel_signal(KernelSignal::new(SIGCONT));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// *************** Foreground process group ***************
|
||||
|
||||
/// Returns the foreground process group
|
||||
pub fn foreground(&self) -> Option<Arc<ProcessGroup>> {
|
||||
self.foreground.lock().upgrade()
|
||||
}
|
||||
|
||||
/// Sets the foreground process group.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// The process group should belong to one session.
|
||||
pub fn set_foreground(&self, process_group: Option<&Arc<ProcessGroup>>) -> Result<()> {
|
||||
let Some(process_group) = process_group else {
|
||||
// FIXME: should we allow this branch?
|
||||
*self.foreground.lock() = Weak::new();
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
let session = process_group.session().unwrap();
|
||||
let Some(terminal_session) = self.session() else {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"the terminal does not become controlling terminal of one session."
|
||||
);
|
||||
};
|
||||
|
||||
if !Arc::ptr_eq(&terminal_session, &session) {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"the process proup belongs to different session"
|
||||
);
|
||||
}
|
||||
|
||||
*self.foreground.lock() = Arc::downgrade(process_group);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Determines whether current process belongs to the foreground process group. If
|
||||
/// the foreground process group is None, returns true.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This function should only be called in process context.
|
||||
pub fn current_belongs_to_foreground(&self) -> bool {
|
||||
let Some(foreground) = self.foreground() else {
|
||||
return true;
|
||||
};
|
||||
|
||||
foreground.contains_process(current!().pid())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for JobControl {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
@ -1,7 +1,4 @@
|
||||
mod builder;
|
||||
|
||||
use super::posix_thread::PosixThreadExt;
|
||||
use super::process_group::ProcessGroup;
|
||||
use super::process_vm::user_heap::UserHeap;
|
||||
use super::process_vm::ProcessVm;
|
||||
use super::rlimit::ResourceLimits;
|
||||
@ -13,7 +10,7 @@ use super::signal::signals::Signal;
|
||||
use super::signal::{Pauser, SigEvents, SigEventsFilter};
|
||||
use super::status::ProcessStatus;
|
||||
use super::{process_table, TermStatus};
|
||||
use crate::device::tty::get_n_tty;
|
||||
use crate::device::tty::open_ntty_as_controlling_terminal;
|
||||
use crate::events::Observer;
|
||||
use crate::fs::file_table::FileTable;
|
||||
use crate::fs::fs_resolver::FsResolver;
|
||||
@ -23,10 +20,25 @@ use crate::thread::{allocate_tid, Thread};
|
||||
use crate::vm::vmar::Vmar;
|
||||
use jinux_rights::Full;
|
||||
|
||||
pub use builder::ProcessBuilder;
|
||||
mod builder;
|
||||
mod job_control;
|
||||
mod process_group;
|
||||
mod session;
|
||||
mod terminal;
|
||||
|
||||
pub use builder::ProcessBuilder;
|
||||
pub use job_control::JobControl;
|
||||
pub use process_group::ProcessGroup;
|
||||
pub use session::Session;
|
||||
pub use terminal::Terminal;
|
||||
|
||||
/// Process id.
|
||||
pub type Pid = u32;
|
||||
/// Process group id.
|
||||
pub type Pgid = u32;
|
||||
/// Session Id.
|
||||
pub type Sid = u32;
|
||||
|
||||
pub type ExitCode = i32;
|
||||
|
||||
/// Process stands for a set of threads that shares the same userspace.
|
||||
@ -46,11 +58,11 @@ pub struct Process {
|
||||
/// Process status
|
||||
status: Mutex<ProcessStatus>,
|
||||
/// Parent process
|
||||
parent: Mutex<Weak<Process>>,
|
||||
pub(super) parent: Mutex<Weak<Process>>,
|
||||
/// Children processes
|
||||
children: Mutex<BTreeMap<Pid, Arc<Process>>>,
|
||||
/// Process group
|
||||
process_group: Mutex<Weak<ProcessGroup>>,
|
||||
pub(super) process_group: Mutex<Weak<ProcessGroup>>,
|
||||
/// File table
|
||||
file_table: Arc<Mutex<FileTable>>,
|
||||
/// FsResolver
|
||||
@ -75,7 +87,6 @@ impl Process {
|
||||
threads: Vec<Arc<Thread>>,
|
||||
executable_path: String,
|
||||
process_vm: ProcessVm,
|
||||
process_group: Weak<ProcessGroup>,
|
||||
file_table: Arc<Mutex<FileTable>>,
|
||||
fs: Arc<RwLock<FsResolver>>,
|
||||
umask: Arc<RwLock<FileCreationMask>>,
|
||||
@ -99,7 +110,7 @@ impl Process {
|
||||
status: Mutex::new(ProcessStatus::Uninit),
|
||||
parent: Mutex::new(parent),
|
||||
children: Mutex::new(BTreeMap::new()),
|
||||
process_group: Mutex::new(process_group),
|
||||
process_group: Mutex::new(Weak::new()),
|
||||
file_table,
|
||||
fs,
|
||||
umask,
|
||||
@ -118,11 +129,9 @@ impl Process {
|
||||
// spawn user process should give an absolute path
|
||||
debug_assert!(executable_path.starts_with('/'));
|
||||
let process = Process::create_user_process(executable_path, argv, envp)?;
|
||||
// FIXME: How to determine the fg process group?
|
||||
let process_group = Weak::clone(&process.process_group.lock());
|
||||
// FIXME: tty should be a parameter?
|
||||
let tty = get_n_tty();
|
||||
tty.set_fg(process_group);
|
||||
|
||||
open_ntty_as_controlling_terminal(&process)?;
|
||||
|
||||
process.run();
|
||||
Ok(process)
|
||||
}
|
||||
@ -141,7 +150,23 @@ impl Process {
|
||||
};
|
||||
|
||||
let process = process_builder.build()?;
|
||||
process_table::add_process(process.clone());
|
||||
|
||||
let mut session_table_mut = process_table::session_table_mut();
|
||||
let mut group_table_mut = process_table::group_table_mut();
|
||||
let mut process_table_mut = process_table::process_table_mut();
|
||||
|
||||
// Creates new group
|
||||
let group = ProcessGroup::new(process.clone());
|
||||
*process.process_group.lock() = Arc::downgrade(&group);
|
||||
group_table_mut.insert(group.pgid(), group.clone());
|
||||
|
||||
// Creates new session
|
||||
let session = Session::new(group.clone());
|
||||
group.inner.lock().session = Arc::downgrade(&session);
|
||||
session.inner.lock().leader = Some(process.clone());
|
||||
session_table_mut.insert(session.sid(), session);
|
||||
|
||||
process_table_mut.insert(process.pid(), process.clone());
|
||||
Ok(process)
|
||||
}
|
||||
|
||||
@ -180,30 +205,25 @@ impl Process {
|
||||
}
|
||||
|
||||
// *********** Parent and child ***********
|
||||
|
||||
pub fn add_child(&self, child: Arc<Process>) {
|
||||
let child_pid = child.pid();
|
||||
self.children.lock().insert(child_pid, child);
|
||||
}
|
||||
|
||||
pub fn set_parent(&self, parent: Weak<Process>) {
|
||||
*self.parent.lock() = parent;
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Arc<Process>> {
|
||||
self.parent.lock().upgrade()
|
||||
}
|
||||
|
||||
pub fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
|
||||
pub(super) fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
|
||||
&self.children
|
||||
}
|
||||
|
||||
pub fn has_child(&self, pid: &Pid) -> bool {
|
||||
self.children.lock().contains_key(pid)
|
||||
}
|
||||
|
||||
pub fn children_pauser(&self) -> &Arc<Pauser> {
|
||||
&self.children_pauser
|
||||
}
|
||||
|
||||
// *********** Process group ***********
|
||||
// *********** Process group & Session***********
|
||||
|
||||
/// Returns the process group id of the process.
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
if let Some(process_group) = self.process_group.lock().upgrade() {
|
||||
process_group.pgid()
|
||||
@ -212,19 +232,219 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set process group for current process. If old process group exists,
|
||||
/// remove current process from old process group.
|
||||
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
||||
if let Some(old_process_group) = self.process_group() {
|
||||
old_process_group.remove_process(self.pid());
|
||||
}
|
||||
*self.process_group.lock() = process_group;
|
||||
}
|
||||
|
||||
/// Returns the process group which the process belongs to.
|
||||
pub fn process_group(&self) -> Option<Arc<ProcessGroup>> {
|
||||
self.process_group.lock().upgrade()
|
||||
}
|
||||
|
||||
/// Returns whether `self` is the leader of process group.
|
||||
fn is_group_leader(self: &Arc<Self>) -> bool {
|
||||
let Some(process_group) = self.process_group() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(leader) = process_group.leader() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
Arc::ptr_eq(self, &leader)
|
||||
}
|
||||
|
||||
/// Returns the session which the process belongs to.
|
||||
pub fn session(&self) -> Option<Arc<Session>> {
|
||||
let process_group = self.process_group()?;
|
||||
process_group.session()
|
||||
}
|
||||
|
||||
/// Returns whether the process is session leader.
|
||||
pub fn is_session_leader(self: &Arc<Self>) -> bool {
|
||||
let session = self.session().unwrap();
|
||||
|
||||
let Some(leading_process) = session.leader() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
Arc::ptr_eq(self, &leading_process)
|
||||
}
|
||||
|
||||
/// Moves the process to the new session.
|
||||
///
|
||||
/// If the process is already session leader, this method does nothing.
|
||||
///
|
||||
/// Otherwise, this method creates a new process group in a new session
|
||||
/// and moves the process to the session, returning the new session.
|
||||
///
|
||||
/// This method may return the following errors:
|
||||
/// * `EPERM`, if the process is a process group leader, or some existing session
|
||||
/// or process group has the same id as the process.
|
||||
pub fn to_new_session(self: &Arc<Self>) -> Result<Arc<Session>> {
|
||||
if self.is_session_leader() {
|
||||
return Ok(self.session().unwrap());
|
||||
}
|
||||
|
||||
if self.is_group_leader() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"process group leader cannot be moved to new session."
|
||||
);
|
||||
}
|
||||
|
||||
let session = self.session().unwrap();
|
||||
let mut session_inner = session.inner.lock();
|
||||
let mut self_group_mut = self.process_group.lock();
|
||||
let mut group_table_mut = process_table::group_table_mut();
|
||||
let mut session_table_mut = process_table::session_table_mut();
|
||||
|
||||
if session_table_mut.contains_key(&self.pid) {
|
||||
return_errno_with_message!(Errno::EPERM, "cannot create new session");
|
||||
}
|
||||
|
||||
if group_table_mut.contains_key(&self.pid) {
|
||||
return_errno_with_message!(Errno::EPERM, "cannot create process group");
|
||||
}
|
||||
|
||||
// Removes the process from session.
|
||||
session_inner.remove_process(self);
|
||||
|
||||
// Removes the process from old group
|
||||
if let Some(old_group) = self.process_group() {
|
||||
let mut group_inner = old_group.inner.lock();
|
||||
group_inner.remove_process(&self.pid);
|
||||
*self_group_mut = Weak::new();
|
||||
|
||||
if group_inner.is_empty() {
|
||||
group_table_mut.remove(&old_group.pgid());
|
||||
debug_assert!(session_inner.process_groups.contains_key(&old_group.pgid()));
|
||||
session_inner.process_groups.remove(&old_group.pgid());
|
||||
|
||||
if session_inner.is_empty() {
|
||||
session_table_mut.remove(&session.sid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new process group
|
||||
let new_group = ProcessGroup::new(self.clone());
|
||||
*self_group_mut = Arc::downgrade(&new_group);
|
||||
group_table_mut.insert(new_group.pgid(), new_group.clone());
|
||||
|
||||
// Creates a new session
|
||||
let new_session = Session::new(new_group.clone());
|
||||
let mut new_group_inner = new_group.inner.lock();
|
||||
new_group_inner.session = Arc::downgrade(&new_session);
|
||||
new_session.inner.lock().leader = Some(self.clone());
|
||||
session_table_mut.insert(new_session.sid(), new_session.clone());
|
||||
|
||||
Ok(new_session)
|
||||
}
|
||||
|
||||
/// Moves the process to other process group.
|
||||
///
|
||||
/// * If the group already exists, the process and the group should belong to the same session.
|
||||
/// * If the group does not exist, this method creates a new group for the process and move the
|
||||
/// process to the group. The group is added to the session of the process.
|
||||
///
|
||||
/// This method may return `EPERM` in following cases:
|
||||
/// * The process is session leader;
|
||||
/// * The group already exists, but the group does not belong to the same session as the process;
|
||||
/// * The group does not exist, but `pgid` is not equal to `pid` of the process.
|
||||
pub fn to_other_group(self: &Arc<Self>, pgid: Pgid) -> Result<()> {
|
||||
// if the process already belongs to the process group
|
||||
if self.pgid() == pgid {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if self.is_session_leader() {
|
||||
return_errno_with_message!(Errno::EPERM, "the process cannot be a session leader");
|
||||
}
|
||||
|
||||
if let Some(process_group) = process_table::get_process_group(&pgid) {
|
||||
let session = self.session().unwrap();
|
||||
if !session.contains_process_group(&process_group) {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"the group and process does not belong to same session"
|
||||
);
|
||||
}
|
||||
self.to_specified_group(&process_group)?;
|
||||
} else {
|
||||
if pgid != self.pid() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"the new process group should have the same id as the process."
|
||||
);
|
||||
}
|
||||
|
||||
self.to_new_group()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a new process group and moves the process to the group.
|
||||
///
|
||||
/// The new group will be added to the same session as the process.
|
||||
fn to_new_group(self: &Arc<Self>) -> Result<()> {
|
||||
let session = self.session().unwrap();
|
||||
let mut session_inner = session.inner.lock();
|
||||
let mut self_group_mut = self.process_group.lock();
|
||||
let mut group_table_mut = process_table::group_table_mut();
|
||||
|
||||
// Removes the process from old group
|
||||
if let Some(old_group) = self.process_group() {
|
||||
let mut group_inner = old_group.inner.lock();
|
||||
group_inner.remove_process(&self.pid);
|
||||
*self_group_mut = Weak::new();
|
||||
|
||||
if group_inner.is_empty() {
|
||||
group_table_mut.remove(&old_group.pgid());
|
||||
debug_assert!(session_inner.process_groups.contains_key(&old_group.pgid()));
|
||||
// The old session won't be empty, since we will add a new group to the session.
|
||||
session_inner.process_groups.remove(&old_group.pgid());
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a new process group. Adds the new group to group table and session.
|
||||
let new_group = ProcessGroup::new(self.clone());
|
||||
*self_group_mut = Arc::downgrade(&new_group);
|
||||
|
||||
group_table_mut.insert(new_group.pgid(), new_group.clone());
|
||||
|
||||
session_inner
|
||||
.process_groups
|
||||
.insert(new_group.pgid(), new_group.clone());
|
||||
let mut new_group_inner = new_group.inner.lock();
|
||||
new_group_inner.session = Arc::downgrade(&session);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Moves the process to a specified group.
|
||||
///
|
||||
/// The caller needs to ensure that the process and the group belongs to the same session.
|
||||
fn to_specified_group(self: &Arc<Process>, group: &Arc<ProcessGroup>) -> Result<()> {
|
||||
let mut self_group_mut = self.process_group.lock();
|
||||
let mut group_table_mut = process_table::group_table_mut();
|
||||
let mut group_inner = group.inner.lock();
|
||||
|
||||
// Removes the process from old group
|
||||
if let Some(old_group) = self.process_group() {
|
||||
let mut group_inner = old_group.inner.lock();
|
||||
group_inner.remove_process(&self.pid);
|
||||
*self_group_mut = Weak::new();
|
||||
|
||||
if group_inner.is_empty() {
|
||||
group_table_mut.remove(&old_group.pgid());
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the process to the specified group
|
||||
group_inner.processes.insert(self.pid, self.clone());
|
||||
*self_group_mut = Arc::downgrade(group);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// ************** Virtual Memory *************
|
||||
|
||||
pub fn vm(&self) -> &ProcessVm {
|
||||
|
92
services/libs/jinux-std/src/process/process/process_group.rs
Normal file
92
services/libs/jinux-std/src/process/process/process_group.rs
Normal file
@ -0,0 +1,92 @@
|
||||
use super::{Pgid, Pid, Process, Session};
|
||||
use crate::prelude::*;
|
||||
use crate::process::signal::signals::kernel::KernelSignal;
|
||||
use crate::process::signal::signals::user::UserSignal;
|
||||
|
||||
/// `ProcessGroup` represents a set of processes. Each `ProcessGroup` has a unique
|
||||
/// identifier `pgid`.
|
||||
pub struct ProcessGroup {
|
||||
pgid: Pgid,
|
||||
pub(in crate::process) inner: Mutex<Inner>,
|
||||
}
|
||||
|
||||
pub(in crate::process) struct Inner {
|
||||
pub(in crate::process) processes: BTreeMap<Pid, Arc<Process>>,
|
||||
pub(in crate::process) leader: Option<Arc<Process>>,
|
||||
pub(in crate::process) session: Weak<Session>,
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(in crate::process) fn remove_process(&mut self, pid: &Pid) {
|
||||
let Some(process) = self.processes.remove(pid) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some(leader) = &self.leader && Arc::ptr_eq(leader, &process) {
|
||||
self.leader = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::process) fn is_empty(&self) -> bool {
|
||||
self.processes.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessGroup {
|
||||
/// Creates a new process group with one process. The pgid is the same as the process
|
||||
/// id. The process will become the leading process of the new process group.
|
||||
///
|
||||
/// The caller needs to ensure that the process does not belong to any group.
|
||||
pub(super) fn new(process: Arc<Process>) -> Arc<Self> {
|
||||
let pid = process.pid();
|
||||
|
||||
let inner = {
|
||||
let mut processes = BTreeMap::new();
|
||||
processes.insert(pid, process.clone());
|
||||
Inner {
|
||||
processes,
|
||||
leader: Some(process.clone()),
|
||||
session: Weak::new(),
|
||||
}
|
||||
};
|
||||
|
||||
Arc::new(ProcessGroup {
|
||||
pgid: pid,
|
||||
inner: Mutex::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns whether self contains a process with `pid`.
|
||||
pub(super) fn contains_process(&self, pid: Pid) -> bool {
|
||||
self.inner.lock().processes.contains_key(&pid)
|
||||
}
|
||||
|
||||
/// Returns the process group identifier
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
self.pgid
|
||||
}
|
||||
|
||||
/// Sends kernel signal to all processes in the group
|
||||
pub fn kernel_signal(&self, signal: KernelSignal) {
|
||||
for process in self.inner.lock().processes.values() {
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends user signal to all processes in the group
|
||||
pub fn user_signal(&self, signal: UserSignal) {
|
||||
for process in self.inner.lock().processes.values() {
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the leader process.
|
||||
pub(super) fn leader(&self) -> Option<Arc<Process>> {
|
||||
self.inner.lock().leader.clone()
|
||||
}
|
||||
|
||||
/// Returns the session which the group belongs to
|
||||
pub fn session(&self) -> Option<Arc<Session>> {
|
||||
self.inner.lock().session.upgrade()
|
||||
}
|
||||
}
|
125
services/libs/jinux-std/src/process/process/session.rs
Normal file
125
services/libs/jinux-std/src/process/process/session.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::{Pgid, Process, ProcessGroup, Sid, Terminal};
|
||||
|
||||
/// A `Session` is a collection of related process groups. Each session has a
|
||||
/// unique identifier `sid`. Process groups and sessions form a two-level
|
||||
/// hierarchical relationship between processes.
|
||||
///
|
||||
/// **Leader**: A *session leader* is the process that creates a new session and whose process
|
||||
/// ID becomes the session ID.
|
||||
///
|
||||
/// **Controlling terminal**: The terminal can be used to manage all processes in the session. The
|
||||
/// controlling terminal is established when the session leader first opens a terminal.
|
||||
pub struct Session {
|
||||
sid: Sid,
|
||||
pub(in crate::process) inner: Mutex<Inner>,
|
||||
}
|
||||
|
||||
pub(in crate::process) struct Inner {
|
||||
pub(in crate::process) process_groups: BTreeMap<Pgid, Arc<ProcessGroup>>,
|
||||
pub(in crate::process) leader: Option<Arc<Process>>,
|
||||
pub(in crate::process) terminal: Option<Arc<dyn Terminal>>,
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(in crate::process) fn is_empty(&self) -> bool {
|
||||
self.process_groups.is_empty()
|
||||
}
|
||||
|
||||
pub(in crate::process) fn remove_process(&mut self, process: &Arc<Process>) {
|
||||
if let Some(leader) = &self.leader && Arc::ptr_eq(leader, process) {
|
||||
self.leader = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub(in crate::process) fn remove_process_group(&mut self, pgid: &Pgid) {
|
||||
self.process_groups.remove(pgid);
|
||||
}
|
||||
}
|
||||
|
||||
impl Session {
|
||||
/// Creates a new session for the process group. The process group becomes the member of
|
||||
/// the new session.
|
||||
///
|
||||
/// The caller needs to ensure that the group does not belong to any session, and the caller
|
||||
/// should set the leader process after creating the session.
|
||||
pub(super) fn new(group: Arc<ProcessGroup>) -> Arc<Self> {
|
||||
let sid = group.pgid();
|
||||
let inner = {
|
||||
let mut process_groups = BTreeMap::new();
|
||||
process_groups.insert(group.pgid(), group);
|
||||
|
||||
Inner {
|
||||
process_groups,
|
||||
leader: None,
|
||||
terminal: None,
|
||||
}
|
||||
};
|
||||
Arc::new(Self {
|
||||
sid,
|
||||
inner: Mutex::new(inner),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the session id
|
||||
pub fn sid(&self) -> Sid {
|
||||
self.sid
|
||||
}
|
||||
|
||||
/// Returns the leader process.
|
||||
pub(super) fn leader(&self) -> Option<Arc<Process>> {
|
||||
self.inner.lock().leader.clone()
|
||||
}
|
||||
|
||||
/// Returns whether `self` contains the `process_group`
|
||||
pub(super) fn contains_process_group(
|
||||
self: &Arc<Self>,
|
||||
process_group: &Arc<ProcessGroup>,
|
||||
) -> bool {
|
||||
self.inner
|
||||
.lock()
|
||||
.process_groups
|
||||
.contains_key(&process_group.pgid())
|
||||
}
|
||||
|
||||
/// Sets terminal as the controlling terminal of the session.
|
||||
///
|
||||
/// If the session already has controlling terminal, this method will return `Err(EPERM)`.
|
||||
pub fn set_terminal<F: Fn() -> Result<Arc<dyn Terminal>>>(&self, terminal: F) -> Result<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
|
||||
if inner.terminal.is_some() {
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"current session already has controlling terminal"
|
||||
);
|
||||
}
|
||||
|
||||
let terminal = terminal()?;
|
||||
inner.terminal = Some(terminal);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Releases the controlling terminal of the session.
|
||||
///
|
||||
/// If the session does not have controlling terminal, this method will return `ENOTTY`.
|
||||
pub fn release_terminal<F: Fn() -> Result<()>>(&self, release_session: F) -> Result<()> {
|
||||
let mut inner = self.inner.lock();
|
||||
if inner.terminal.is_none() {
|
||||
return_errno_with_message!(
|
||||
Errno::ENOTTY,
|
||||
"current session does not has controlling terminal"
|
||||
);
|
||||
}
|
||||
|
||||
release_session()?;
|
||||
inner.terminal = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the controlling terminal of `self`.
|
||||
pub fn terminal(&self) -> Option<Arc<dyn Terminal>> {
|
||||
self.inner.lock().terminal.clone()
|
||||
}
|
||||
}
|
104
services/libs/jinux-std/src/process/process/terminal.rs
Normal file
104
services/libs/jinux-std/src/process/process/terminal.rs
Normal file
@ -0,0 +1,104 @@
|
||||
use crate::fs::inode_handle::FileIo;
|
||||
use crate::prelude::*;
|
||||
use crate::process::{process_table, Pgid, ProcessGroup};
|
||||
|
||||
use super::JobControl;
|
||||
|
||||
/// A termial is used to interact with system. A terminal can support the shell
|
||||
/// job control.
|
||||
///
|
||||
/// We currently support two kinds of terminal, the tty and pty.
|
||||
pub trait Terminal: Send + Sync + FileIo {
|
||||
// *************** Foreground ***************
|
||||
|
||||
/// Returns the foreground process group
|
||||
fn foreground(&self) -> Option<Arc<ProcessGroup>> {
|
||||
self.job_control().foreground()
|
||||
}
|
||||
|
||||
/// Sets the foreground process group of this terminal.
|
||||
///
|
||||
/// If the terminal is not controlling terminal, this method returns `ENOTTY`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should be called in process context.
|
||||
fn set_foreground(&self, pgid: &Pgid) -> Result<()> {
|
||||
if !self.is_controlling_terminal() {
|
||||
return_errno_with_message!(Errno::ENOTTY, "self is not controlling terminal");
|
||||
}
|
||||
|
||||
let foreground = process_table::get_process_group(pgid);
|
||||
|
||||
self.job_control().set_foreground(foreground.as_ref())
|
||||
}
|
||||
|
||||
// *************** Session and controlling terminal ***************
|
||||
|
||||
/// Returns whether the terminal is the controlling terminal of current process.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should be called in process context.
|
||||
fn is_controlling_terminal(&self) -> bool {
|
||||
let session = current!().session().unwrap();
|
||||
let Some(terminal) = session.terminal() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let arc_self = self.arc_self();
|
||||
Arc::ptr_eq(&terminal, &arc_self)
|
||||
}
|
||||
|
||||
/// Sets the terminal as the controlling terminal of the session of current process.
|
||||
///
|
||||
/// If self is not session leader, or the terminal is controlling terminal of other session,
|
||||
/// or the session already has controlling terminal, this method returns `EPERM`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should only be called in process context.
|
||||
fn set_current_session(&self) -> Result<()> {
|
||||
if !current!().is_session_leader() {
|
||||
return_errno_with_message!(Errno::EPERM, "current process is not session leader");
|
||||
}
|
||||
|
||||
let terminal = || {
|
||||
self.job_control().set_current_session()?;
|
||||
Ok(self.arc_self())
|
||||
};
|
||||
|
||||
let session = current!().session().unwrap();
|
||||
session.set_terminal(terminal)
|
||||
}
|
||||
|
||||
/// Releases the terminal from the session of current process if the terminal is the controlling
|
||||
/// terminal of the session.
|
||||
///
|
||||
/// If the terminal is not the controlling terminal of the session, this method will return `ENOTTY`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// This method should only be called in process context.
|
||||
fn release_current_session(&self) -> Result<()> {
|
||||
if !self.is_controlling_terminal() {
|
||||
return_errno_with_message!(Errno::ENOTTY, "release wrong tty");
|
||||
}
|
||||
|
||||
let current = current!();
|
||||
if !current.is_session_leader() {
|
||||
warn!("TODO: release tty for process that is not session leader");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let release_session = || self.job_control().release_current_session();
|
||||
|
||||
let session = current.session().unwrap();
|
||||
session.release_terminal(release_session)
|
||||
}
|
||||
|
||||
/// Returns the job control of the terminal.
|
||||
fn job_control(&self) -> &JobControl;
|
||||
|
||||
fn arc_self(&self) -> Arc<dyn Terminal>;
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
use super::{
|
||||
process_table,
|
||||
signal::signals::{kernel::KernelSignal, user::UserSignal},
|
||||
Pgid, Pid, Process,
|
||||
};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct ProcessGroup {
|
||||
inner: Mutex<ProcessGroupInner>,
|
||||
}
|
||||
|
||||
struct ProcessGroupInner {
|
||||
pgid: Pgid,
|
||||
processes: BTreeMap<Pid, Arc<Process>>,
|
||||
leader_process: Option<Arc<Process>>,
|
||||
}
|
||||
|
||||
impl ProcessGroup {
|
||||
fn default() -> Self {
|
||||
ProcessGroup {
|
||||
inner: Mutex::new(ProcessGroupInner {
|
||||
pgid: 0,
|
||||
processes: BTreeMap::new(),
|
||||
leader_process: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(process: Arc<Process>) -> Self {
|
||||
let process_group = ProcessGroup::default();
|
||||
let pid = process.pid();
|
||||
process_group.set_pgid(pid);
|
||||
process_group.add_process(process.clone());
|
||||
process_group.set_leader_process(process);
|
||||
process_group
|
||||
}
|
||||
|
||||
pub fn set_pgid(&self, pgid: Pgid) {
|
||||
self.inner.lock().pgid = pgid;
|
||||
}
|
||||
|
||||
pub fn set_leader_process(&self, leader_process: Arc<Process>) {
|
||||
self.inner.lock().leader_process = Some(leader_process);
|
||||
}
|
||||
|
||||
pub fn add_process(&self, process: Arc<Process>) {
|
||||
self.inner.lock().processes.insert(process.pid(), process);
|
||||
}
|
||||
|
||||
pub fn contains_process(&self, pid: Pid) -> bool {
|
||||
self.inner.lock().processes.contains_key(&pid)
|
||||
}
|
||||
|
||||
/// remove a process from this process group.
|
||||
/// If this group contains no processes now, the group itself will be deleted from global table.
|
||||
pub fn remove_process(&self, pid: Pid) {
|
||||
let mut inner_lock = self.inner.lock();
|
||||
inner_lock.processes.remove(&pid);
|
||||
let len = inner_lock.processes.len();
|
||||
let pgid = inner_lock.pgid;
|
||||
// if self contains no process, remove self from table
|
||||
if len == 0 {
|
||||
// this must be the last statement
|
||||
process_table::remove_process_group(pgid);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
self.inner.lock().pgid
|
||||
}
|
||||
|
||||
/// send kernel signal to all processes in the group
|
||||
pub fn kernel_signal(&self, signal: KernelSignal) {
|
||||
for process in self.inner.lock().processes.values() {
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
}
|
||||
}
|
||||
|
||||
/// send user signal to all processes in the group
|
||||
pub fn user_signal(&self, signal: UserSignal) {
|
||||
for process in self.inner.lock().processes.values() {
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
}
|
||||
}
|
||||
}
|
@ -5,35 +5,25 @@
|
||||
use crate::events::{Events, Observer, Subject};
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::{process_group::ProcessGroup, Pgid, Pid, Process};
|
||||
use super::{Pgid, Pid, Process, ProcessGroup, Session, Sid};
|
||||
|
||||
lazy_static! {
|
||||
static ref PROCESS_TABLE: Mutex<BTreeMap<Pid, Arc<Process>>> = Mutex::new(BTreeMap::new());
|
||||
static ref PROCESS_GROUP_TABLE: Mutex<BTreeMap<Pgid, Arc<ProcessGroup>>> =
|
||||
Mutex::new(BTreeMap::new());
|
||||
static ref PROCESS_TABLE_SUBJECT: Subject<PidEvent> = Subject::new();
|
||||
static PROCESS_TABLE: Mutex<BTreeMap<Pid, Arc<Process>>> = Mutex::new(BTreeMap::new());
|
||||
static PROCESS_GROUP_TABLE: Mutex<BTreeMap<Pgid, Arc<ProcessGroup>>> = Mutex::new(BTreeMap::new());
|
||||
static PROCESS_TABLE_SUBJECT: Subject<PidEvent> = Subject::new();
|
||||
static SESSION_TABLE: Mutex<BTreeMap<Sid, Arc<Session>>> = Mutex::new(BTreeMap::new());
|
||||
|
||||
// ************ Process *************
|
||||
|
||||
/// Gets a process with pid
|
||||
pub fn get_process(pid: &Pid) -> Option<Arc<Process>> {
|
||||
PROCESS_TABLE.lock().get(pid).cloned()
|
||||
}
|
||||
|
||||
/// add a process to global table
|
||||
pub fn add_process(process: Arc<Process>) {
|
||||
let pid = process.pid();
|
||||
PROCESS_TABLE.lock().insert(pid, process);
|
||||
pub(super) fn process_table_mut() -> MutexGuard<'static, BTreeMap<Pid, Arc<Process>>> {
|
||||
PROCESS_TABLE.lock()
|
||||
}
|
||||
|
||||
/// remove a process from global table
|
||||
pub fn remove_process(pid: Pid) {
|
||||
PROCESS_TABLE.lock().remove(&pid);
|
||||
|
||||
let events = PidEvent::Exit(pid);
|
||||
PROCESS_TABLE_SUBJECT.notify_observers(&events);
|
||||
}
|
||||
|
||||
/// get a process with pid
|
||||
pub fn pid_to_process(pid: Pid) -> Option<Arc<Process>> {
|
||||
PROCESS_TABLE.lock().get(&pid).cloned()
|
||||
}
|
||||
|
||||
/// get all processes
|
||||
/// Gets all processes
|
||||
pub fn get_all_processes() -> Vec<Arc<Process>> {
|
||||
PROCESS_TABLE
|
||||
.lock()
|
||||
@ -42,26 +32,41 @@ pub fn get_all_processes() -> Vec<Arc<Process>> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// add process group to global table
|
||||
pub fn add_process_group(process_group: Arc<ProcessGroup>) {
|
||||
let pgid = process_group.pgid();
|
||||
PROCESS_GROUP_TABLE.lock().insert(pgid, process_group);
|
||||
// ************ Process Group *************
|
||||
|
||||
/// Gets a process group with `pgid`
|
||||
pub fn get_process_group(pgid: &Pgid) -> Option<Arc<ProcessGroup>> {
|
||||
PROCESS_GROUP_TABLE.lock().get(pgid).cloned()
|
||||
}
|
||||
|
||||
/// remove process group from global table
|
||||
pub fn remove_process_group(pgid: Pgid) {
|
||||
PROCESS_GROUP_TABLE.lock().remove(&pgid);
|
||||
/// Returns whether process table contains process group with pgid
|
||||
pub fn contain_process_group(pgid: &Pgid) -> bool {
|
||||
PROCESS_GROUP_TABLE.lock().contains_key(pgid)
|
||||
}
|
||||
|
||||
/// get a process group with pgid
|
||||
pub fn pgid_to_process_group(pgid: Pgid) -> Option<Arc<ProcessGroup>> {
|
||||
PROCESS_GROUP_TABLE.lock().get(&pgid).cloned()
|
||||
pub(super) fn group_table_mut() -> MutexGuard<'static, BTreeMap<Pgid, Arc<ProcessGroup>>> {
|
||||
PROCESS_GROUP_TABLE.lock()
|
||||
}
|
||||
|
||||
// ************ Session *************
|
||||
|
||||
/// Gets a session with `sid`.
|
||||
pub fn get_session(sid: &Sid) -> Option<Arc<Session>> {
|
||||
SESSION_TABLE.lock().get(sid).map(Arc::clone)
|
||||
}
|
||||
|
||||
pub(super) fn session_table_mut() -> MutexGuard<'static, BTreeMap<Sid, Arc<Session>>> {
|
||||
SESSION_TABLE.lock()
|
||||
}
|
||||
|
||||
// ************ Observer *************
|
||||
|
||||
/// Registers an observer which watches `PidEvent`.
|
||||
pub fn register_observer(observer: Weak<dyn Observer<PidEvent>>) {
|
||||
PROCESS_TABLE_SUBJECT.register_observer(observer, ());
|
||||
}
|
||||
|
||||
/// Unregisters an observer which watches `PidEvent`.
|
||||
pub fn unregister_observer(observer: &Weak<dyn Observer<PidEvent>>) {
|
||||
PROCESS_TABLE_SUBJECT.unregister_observer(observer);
|
||||
}
|
||||
|
@ -81,8 +81,11 @@ impl SigQueues {
|
||||
// POSIX leaves unspecified which to deliver first if there are multiple
|
||||
// pending standard signals. So we are free to define our own. The
|
||||
// principle is to give more urgent signals higher priority (like SIGKILL).
|
||||
|
||||
// FIXME: the gvisor pty_test JobControlTest::ReleaseTTY requires that
|
||||
// the SIGHUP signal should be handled before SIGCONT.
|
||||
const ORDERED_STD_SIGS: [SigNum; COUNT_STD_SIGS] = [
|
||||
SIGKILL, SIGTERM, SIGSTOP, SIGCONT, SIGSEGV, SIGILL, SIGHUP, SIGINT, SIGQUIT, SIGTRAP,
|
||||
SIGKILL, SIGTERM, SIGSTOP, SIGSEGV, SIGILL, SIGHUP, SIGCONT, SIGINT, SIGQUIT, SIGTRAP,
|
||||
SIGABRT, SIGBUS, SIGFPE, SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, SIGSTKFLT, SIGCHLD,
|
||||
SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
|
||||
SIGIO, SIGPWR, SIGSYS,
|
||||
|
@ -80,9 +80,30 @@ fn reap_zombie_child(process: &Process, pid: Pid) -> u32 {
|
||||
for thread in &*child_process.threads().lock() {
|
||||
thread_table::remove_thread(thread.tid());
|
||||
}
|
||||
process_table::remove_process(child_process.pid());
|
||||
if let Some(process_group) = child_process.process_group() {
|
||||
process_group.remove_process(child_process.pid());
|
||||
|
||||
let mut process_table_mut = process_table::process_table_mut();
|
||||
let mut group_table_mut = process_table::group_table_mut();
|
||||
let mut session_table_mut = process_table::session_table_mut();
|
||||
let mut child_group_mut = child_process.process_group.lock();
|
||||
|
||||
let process_group = child_process.process_group().unwrap();
|
||||
let mut group_inner = process_group.inner.lock();
|
||||
let session = group_inner.session.upgrade().unwrap();
|
||||
let mut session_inner = session.inner.lock();
|
||||
|
||||
group_inner.remove_process(&child_process.pid());
|
||||
session_inner.remove_process(&child_process);
|
||||
*child_group_mut = Weak::new();
|
||||
|
||||
if group_inner.is_empty() {
|
||||
group_table_mut.remove(&process_group.pgid());
|
||||
session_inner.remove_process_group(&process_group.pgid());
|
||||
|
||||
if session_inner.is_empty() {
|
||||
session_table_mut.remove(&session.sid());
|
||||
}
|
||||
}
|
||||
|
||||
process_table_mut.remove(&child_process.pid());
|
||||
child_process.exit_code().unwrap()
|
||||
}
|
||||
|
Reference in New Issue
Block a user