diff --git a/kernel/src/process/exit.rs b/kernel/src/process/exit.rs index 51414efac..ed716b720 100644 --- a/kernel/src/process/exit.rs +++ b/kernel/src/process/exit.rs @@ -49,12 +49,13 @@ pub fn do_exit_group(term_status: TermStatus) { for (_, child_process) in current.children().lock().extract_if(|_, _| true) { let mut parent = child_process.parent.lock(); init_children.insert(child_process.pid(), child_process.clone()); - *parent = Arc::downgrade(&init_process); + parent.set_process(&init_process); } } } - if let Some(parent) = current.parent() { + let parent = current.parent().lock().process(); + if let Some(parent) = parent.upgrade() { // Notify parent let signal = KernelSignal::new(SIGCHLD); parent.enqueue_signal(signal); diff --git a/kernel/src/process/process/mod.rs b/kernel/src/process/process/mod.rs index a82912dfa..4e1ef7182 100644 --- a/kernel/src/process/process/mod.rs +++ b/kernel/src/process/process/mod.rs @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 +use core::sync::atomic::Ordering; + use self::timer_manager::PosixTimerManager; use super::{ posix_thread::PosixThreadExt, @@ -71,7 +73,7 @@ pub struct Process { /// Process status status: ProcessStatus, /// Parent process - pub(super) parent: Mutex>, + pub(super) parent: ParentProcess, /// Children processes children: Mutex>>, /// Process group @@ -102,6 +104,63 @@ pub struct Process { timer_manager: PosixTimerManager, } +/// Representing a parent process by holding a weak reference to it and its PID. +/// +/// This type caches the value of the PID so that it can be retrieved cheaply. +/// +/// The benefit of using `ParentProcess` over `(Mutex>, Atomic,)` is to +/// enforce the invariant that the cached PID and the weak reference are always kept in sync. +pub struct ParentProcess { + process: Mutex>, + pid: Atomic, +} + +impl ParentProcess { + pub fn new(process: Weak) -> Self { + let pid = match process.upgrade() { + Some(process) => process.pid(), + None => 0, + }; + + Self { + process: Mutex::new(process), + pid: Atomic::new(pid), + } + } + + pub fn pid(&self) -> Pid { + self.pid.load(Ordering::Relaxed) + } + + pub fn lock(&self) -> ParentProcessGuard<'_> { + ParentProcessGuard { + guard: self.process.lock(), + this: self, + } + } +} + +pub struct ParentProcessGuard<'a> { + guard: MutexGuard<'a, Weak>, + this: &'a ParentProcess, +} + +impl ParentProcessGuard<'_> { + pub fn process(&self) -> Weak { + self.guard.clone() + } + + pub fn pid(&self) -> Pid { + self.this.pid() + } + + /// Update both pid and weak ref. + pub fn set_process(&mut self, new_process: &Arc) { + self.this.pid.store(new_process.pid(), Ordering::Relaxed); + *self.guard = Arc::downgrade(new_process); + } +} + impl Process { /// Returns the current process. /// @@ -141,7 +200,7 @@ impl Process { process_vm, children_pauser, status: ProcessStatus::new_uninit(), - parent: Mutex::new(parent), + parent: ParentProcess::new(parent), children: Mutex::new(BTreeMap::new()), process_group: Mutex::new(Weak::new()), file_table, @@ -268,12 +327,12 @@ impl Process { } // *********** Parent and child *********** - pub fn parent(&self) -> Option> { - self.parent.lock().upgrade() + pub fn parent(&self) -> &ParentProcess { + &self.parent } pub fn is_init_process(&self) -> bool { - self.parent().is_none() + self.parent.lock().process().upgrade().is_none() } pub(super) fn children(&self) -> &Mutex>> { diff --git a/kernel/src/syscall/getppid.rs b/kernel/src/syscall/getppid.rs index 7cfa33d32..f91a67355 100644 --- a/kernel/src/syscall/getppid.rs +++ b/kernel/src/syscall/getppid.rs @@ -4,9 +4,5 @@ use super::SyscallReturn; use crate::prelude::*; pub fn sys_getppid(ctx: &Context) -> Result { - let parent = ctx.process.parent(); - match parent { - None => Ok(SyscallReturn::Return(0)), - Some(parent) => Ok(SyscallReturn::Return(parent.pid() as _)), - } + Ok(SyscallReturn::Return(ctx.process.parent().pid() as _)) }