mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 21:26:30 +00:00
Support parent death signal & Refactor do_exit
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
e8c8c027c5
commit
57fc6a5402
@ -181,8 +181,6 @@ fn clone_child_thread(parent_context: &UserContext, clone_args: CloneArgs) -> Re
|
|||||||
|
|
||||||
let child_tid = allocate_tid();
|
let child_tid = allocate_tid();
|
||||||
let child_thread = {
|
let child_thread = {
|
||||||
let is_main_thread = child_tid == current.pid();
|
|
||||||
|
|
||||||
let credentials = {
|
let credentials = {
|
||||||
let credentials = credentials();
|
let credentials = credentials();
|
||||||
Credentials::new_from(&credentials)
|
Credentials::new_from(&credentials)
|
||||||
@ -190,8 +188,7 @@ fn clone_child_thread(parent_context: &UserContext, clone_args: CloneArgs) -> Re
|
|||||||
|
|
||||||
let thread_builder = PosixThreadBuilder::new(child_tid, child_user_space, credentials)
|
let thread_builder = PosixThreadBuilder::new(child_tid, child_user_space, credentials)
|
||||||
.process(Arc::downgrade(¤t))
|
.process(Arc::downgrade(¤t))
|
||||||
.sig_mask(sig_mask)
|
.sig_mask(sig_mask);
|
||||||
.is_main_thread(is_main_thread);
|
|
||||||
thread_builder.build()
|
thread_builder.build()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use super::{process_table, Pid, Process, TermStatus};
|
|||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{
|
process::{
|
||||||
posix_thread::PosixThreadExt,
|
posix_thread::do_exit,
|
||||||
signal::{constants::SIGCHLD, signals::kernel::KernelSignal},
|
signal::{constants::SIGCHLD, signals::kernel::KernelSignal},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -20,17 +20,22 @@ pub fn do_exit_group(term_status: TermStatus) {
|
|||||||
// Exit all threads
|
// Exit all threads
|
||||||
let threads = current.threads().lock().clone();
|
let threads = current.threads().lock().clone();
|
||||||
for thread in threads {
|
for thread in threads {
|
||||||
if thread.status().is_exited() {
|
if let Err(e) = do_exit(thread, term_status) {
|
||||||
continue;
|
debug!("Ignore error when call exit: {:?}", e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
thread.exit();
|
// Sends parent-death signal
|
||||||
if let Some(posix_thread) = thread.as_posix_thread() {
|
// FIXME: according to linux spec, the signal should be sent when a posix thread which
|
||||||
let tid = thread.tid();
|
// creates child process exits, not when the whole process exits group.
|
||||||
if let Err(e) = posix_thread.exit(tid, term_status) {
|
for (_, child) in current.children().lock().iter() {
|
||||||
debug!("Ignore error when call exit: {:?}", e);
|
let Some(signum) = child.parent_death_signal() else {
|
||||||
}
|
continue;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
// FIXME: set pid of the signal
|
||||||
|
let signal = KernelSignal::new(signum);
|
||||||
|
child.enqueue_signal(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close all files then exit the process
|
// Close all files then exit the process
|
||||||
@ -61,7 +66,7 @@ pub fn do_exit_group(term_status: TermStatus) {
|
|||||||
|
|
||||||
const INIT_PROCESS_PID: Pid = 1;
|
const INIT_PROCESS_PID: Pid = 1;
|
||||||
|
|
||||||
/// Get the init process
|
/// Gets the init process
|
||||||
fn get_init_process() -> Option<Arc<Process>> {
|
fn get_init_process() -> Option<Arc<Process>> {
|
||||||
process_table::get_process(INIT_PROCESS_PID)
|
process_table::get_process(INIT_PROCESS_PID)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ pub struct PosixThreadBuilder {
|
|||||||
clear_child_tid: Vaddr,
|
clear_child_tid: Vaddr,
|
||||||
sig_mask: SigMask,
|
sig_mask: SigMask,
|
||||||
sig_queues: SigQueues,
|
sig_queues: SigQueues,
|
||||||
is_main_thread: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PosixThreadBuilder {
|
impl PosixThreadBuilder {
|
||||||
@ -45,7 +44,6 @@ impl PosixThreadBuilder {
|
|||||||
clear_child_tid: 0,
|
clear_child_tid: 0,
|
||||||
sig_mask: SigMask::new_empty(),
|
sig_mask: SigMask::new_empty(),
|
||||||
sig_queues: SigQueues::new(),
|
sig_queues: SigQueues::new(),
|
||||||
is_main_thread: true,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,12 +67,6 @@ impl PosixThreadBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::wrong_self_convention)]
|
|
||||||
pub fn is_main_thread(mut self, is_main_thread: bool) -> Self {
|
|
||||||
self.is_main_thread = is_main_thread;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sig_mask(mut self, sig_mask: SigMask) -> Self {
|
pub fn sig_mask(mut self, sig_mask: SigMask) -> Self {
|
||||||
self.sig_mask = sig_mask;
|
self.sig_mask = sig_mask;
|
||||||
self
|
self
|
||||||
@ -91,7 +83,6 @@ impl PosixThreadBuilder {
|
|||||||
clear_child_tid,
|
clear_child_tid,
|
||||||
sig_mask,
|
sig_mask,
|
||||||
sig_queues,
|
sig_queues,
|
||||||
is_main_thread,
|
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let thread = Arc::new_cyclic(|thread_ref| {
|
let thread = Arc::new_cyclic(|thread_ref| {
|
||||||
@ -104,7 +95,6 @@ impl PosixThreadBuilder {
|
|||||||
|
|
||||||
let posix_thread = PosixThread {
|
let posix_thread = PosixThread {
|
||||||
process,
|
process,
|
||||||
is_main_thread,
|
|
||||||
name: Mutex::new(thread_name),
|
name: Mutex::new(thread_name),
|
||||||
set_child_tid: Mutex::new(set_child_tid),
|
set_child_tid: Mutex::new(set_child_tid),
|
||||||
clear_child_tid: Mutex::new(clear_child_tid),
|
clear_child_tid: Mutex::new(clear_child_tid),
|
||||||
|
65
kernel/aster-nix/src/process/posix_thread/exit.rs
Normal file
65
kernel/aster-nix/src/process/posix_thread/exit.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::{futex::futex_wake, robust_list::wake_robust_futex, PosixThread, PosixThreadExt};
|
||||||
|
use crate::{
|
||||||
|
prelude::*,
|
||||||
|
process::{do_exit_group, TermStatus},
|
||||||
|
thread::{thread_table, Thread, Tid},
|
||||||
|
util::write_val_to_user,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Exits the thread if the thread is a POSIX thread.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// If the thread is not a POSIX thread, this method will panic.
|
||||||
|
pub fn do_exit(thread: Arc<Thread>, term_status: TermStatus) -> Result<()> {
|
||||||
|
if thread.status().is_exited() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
thread.exit();
|
||||||
|
|
||||||
|
let tid = thread.tid();
|
||||||
|
|
||||||
|
let posix_thread = thread.as_posix_thread().unwrap();
|
||||||
|
|
||||||
|
let mut clear_ctid = posix_thread.clear_child_tid().lock();
|
||||||
|
// If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr.
|
||||||
|
if *clear_ctid != 0 {
|
||||||
|
futex_wake(*clear_ctid, 1)?;
|
||||||
|
// FIXME: the correct write length?
|
||||||
|
write_val_to_user(*clear_ctid, &0u32).unwrap();
|
||||||
|
*clear_ctid = 0;
|
||||||
|
}
|
||||||
|
// exit the robust list: walk the robust list; mark futex words as dead and do futex wake
|
||||||
|
wake_robust_list(posix_thread, tid);
|
||||||
|
|
||||||
|
if tid != posix_thread.process().pid() {
|
||||||
|
// We don't remove main thread.
|
||||||
|
// The main thread is removed when the process is reaped.
|
||||||
|
thread_table::remove_thread(tid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if posix_thread.is_main_thread(tid) || posix_thread.is_last_thread() {
|
||||||
|
// exit current process.
|
||||||
|
do_exit_group(term_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
futex_wake(Arc::as_ptr(&posix_thread.process()) as Vaddr, 1)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Walks the robust futex list, marking futex dead and wake waiters.
|
||||||
|
/// It corresponds to Linux's exit_robust_list(), errors are silently ignored.
|
||||||
|
fn wake_robust_list(thread: &PosixThread, tid: Tid) {
|
||||||
|
let mut robust_list = thread.robust_list.lock();
|
||||||
|
let list_head = match *robust_list {
|
||||||
|
Some(robust_list_head) => robust_list_head,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
trace!("wake the rubust_list: {:?}", list_head);
|
||||||
|
for futex_addr in list_head.futexes() {
|
||||||
|
wake_robust_futex(futex_addr, tid).unwrap();
|
||||||
|
}
|
||||||
|
*robust_list = None;
|
||||||
|
}
|
@ -3,11 +3,8 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use aster_rights::{ReadOp, WriteOp};
|
use aster_rights::{ReadOp, WriteOp};
|
||||||
use futex::futex_wake;
|
|
||||||
use robust_list::wake_robust_futex;
|
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
do_exit_group,
|
|
||||||
kill::SignalSenderIds,
|
kill::SignalSenderIds,
|
||||||
signal::{
|
signal::{
|
||||||
sig_mask::{SigMask, SigSet},
|
sig_mask::{SigMask, SigSet},
|
||||||
@ -16,24 +13,25 @@ use super::{
|
|||||||
signals::Signal,
|
signals::Signal,
|
||||||
SigEvents, SigEventsFilter, SigStack,
|
SigEvents, SigEventsFilter, SigStack,
|
||||||
},
|
},
|
||||||
Credentials, Process, TermStatus,
|
Credentials, Process,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
events::Observer,
|
events::Observer,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::signal::constants::SIGCONT,
|
process::signal::constants::SIGCONT,
|
||||||
thread::{thread_table, Tid},
|
thread::Tid,
|
||||||
time::{clocks::ProfClock, Timer, TimerManager},
|
time::{clocks::ProfClock, Timer, TimerManager},
|
||||||
util::write_val_to_user,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod builder;
|
mod builder;
|
||||||
|
mod exit;
|
||||||
pub mod futex;
|
pub mod futex;
|
||||||
mod name;
|
mod name;
|
||||||
mod posix_thread_ext;
|
mod posix_thread_ext;
|
||||||
mod robust_list;
|
mod robust_list;
|
||||||
|
|
||||||
pub use builder::PosixThreadBuilder;
|
pub use builder::PosixThreadBuilder;
|
||||||
|
pub use exit::do_exit;
|
||||||
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
|
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
|
||||||
pub use posix_thread_ext::PosixThreadExt;
|
pub use posix_thread_ext::PosixThreadExt;
|
||||||
pub use robust_list::RobustListHead;
|
pub use robust_list::RobustListHead;
|
||||||
@ -41,7 +39,6 @@ pub use robust_list::RobustListHead;
|
|||||||
pub struct PosixThread {
|
pub struct PosixThread {
|
||||||
// Immutable part
|
// Immutable part
|
||||||
process: Weak<Process>,
|
process: Weak<Process>,
|
||||||
is_main_thread: bool,
|
|
||||||
|
|
||||||
// Mutable part
|
// Mutable part
|
||||||
name: Mutex<Option<ThreadName>>,
|
name: Mutex<Option<ThreadName>>,
|
||||||
@ -224,13 +221,13 @@ impl PosixThread {
|
|||||||
&self.robust_list
|
&self.robust_list
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether the thread is main thread. For Posix thread, If a thread's tid is equal to pid, it's main thread.
|
fn is_main_thread(&self, tid: Tid) -> bool {
|
||||||
pub fn is_main_thread(&self) -> bool {
|
let process = self.process();
|
||||||
self.is_main_thread
|
let pid = process.pid();
|
||||||
|
tid == pid
|
||||||
}
|
}
|
||||||
|
|
||||||
/// whether the thread is the last running thread in process
|
fn is_last_thread(&self) -> bool {
|
||||||
pub fn is_last_thread(&self) -> bool {
|
|
||||||
let process = self.process.upgrade().unwrap();
|
let process = self.process.upgrade().unwrap();
|
||||||
let threads = process.threads().lock();
|
let threads = process.threads().lock();
|
||||||
threads
|
threads
|
||||||
@ -240,62 +237,6 @@ impl PosixThread {
|
|||||||
== 0
|
== 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Walks the robust futex list, marking futex dead and wake waiters.
|
|
||||||
/// It corresponds to Linux's exit_robust_list(), errors are silently ignored.
|
|
||||||
pub fn wake_robust_list(&self, tid: Tid) {
|
|
||||||
let mut robust_list = self.robust_list.lock();
|
|
||||||
let list_head = match *robust_list {
|
|
||||||
None => {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Some(robust_list_head) => robust_list_head,
|
|
||||||
};
|
|
||||||
debug!("wake the rubust_list: {:?}", list_head);
|
|
||||||
for futex_addr in list_head.futexes() {
|
|
||||||
// debug!("futex addr = 0x{:x}", futex_addr);
|
|
||||||
wake_robust_futex(futex_addr, tid).unwrap();
|
|
||||||
}
|
|
||||||
debug!("wake robust futex success");
|
|
||||||
*robust_list = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Posix thread does not contains tid info. So we require tid as a parameter.
|
|
||||||
pub fn exit(&self, tid: Tid, term_status: TermStatus) -> Result<()> {
|
|
||||||
let mut clear_ctid = self.clear_child_tid().lock();
|
|
||||||
// If clear_ctid !=0 ,do a futex wake and write zero to the clear_ctid addr.
|
|
||||||
debug!("wake up ctid");
|
|
||||||
if *clear_ctid != 0 {
|
|
||||||
debug!("futex wake");
|
|
||||||
futex_wake(*clear_ctid, 1)?;
|
|
||||||
debug!("write ctid");
|
|
||||||
// FIXME: the correct write length?
|
|
||||||
debug!("ctid = 0x{:x}", *clear_ctid);
|
|
||||||
write_val_to_user(*clear_ctid, &0u32).unwrap();
|
|
||||||
debug!("clear ctid");
|
|
||||||
*clear_ctid = 0;
|
|
||||||
}
|
|
||||||
debug!("wake up ctid succeeds");
|
|
||||||
// exit the robust list: walk the robust list; mark futex words as dead and do futex wake
|
|
||||||
self.wake_robust_list(tid);
|
|
||||||
|
|
||||||
if tid != self.process().pid() {
|
|
||||||
// If the thread is not main thread. We don't remove main thread.
|
|
||||||
// Main thread are removed when the whole process is reaped.
|
|
||||||
thread_table::remove_thread(tid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.is_main_thread() || self.is_last_thread() {
|
|
||||||
// exit current process.
|
|
||||||
debug!("self is main thread or last thread");
|
|
||||||
debug!("main thread: {}", self.is_main_thread());
|
|
||||||
debug!("last thread: {}", self.is_last_thread());
|
|
||||||
do_exit_group(term_status);
|
|
||||||
}
|
|
||||||
debug!("perform futex wake");
|
|
||||||
futex_wake(Arc::as_ptr(&self.process()) as Vaddr, 1)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the read-only credentials of the thread.
|
/// Gets the read-only credentials of the thread.
|
||||||
pub fn credentials(&self) -> Credentials<ReadOp> {
|
pub fn credentials(&self) -> Credentials<ReadOp> {
|
||||||
self.credentials.dup().restrict()
|
self.credentials.dup().restrict()
|
||||||
|
@ -181,12 +181,12 @@ impl<'a> ProcessBuilder<'a> {
|
|||||||
threads,
|
threads,
|
||||||
executable_path.to_string(),
|
executable_path.to_string(),
|
||||||
process_vm,
|
process_vm,
|
||||||
file_table,
|
|
||||||
fs,
|
fs,
|
||||||
|
file_table,
|
||||||
umask,
|
umask,
|
||||||
sig_dispositions,
|
|
||||||
resource_limits,
|
resource_limits,
|
||||||
nice,
|
nice,
|
||||||
|
sig_dispositions,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7,7 +7,11 @@ use super::{
|
|||||||
process_vm::{Heap, InitStackReader, ProcessVm},
|
process_vm::{Heap, InitStackReader, ProcessVm},
|
||||||
rlimit::ResourceLimits,
|
rlimit::ResourceLimits,
|
||||||
signal::{
|
signal::{
|
||||||
constants::SIGCHLD, sig_disposition::SigDispositions, sig_mask::SigMask, signals::Signal,
|
constants::SIGCHLD,
|
||||||
|
sig_disposition::SigDispositions,
|
||||||
|
sig_mask::SigMask,
|
||||||
|
sig_num::{AtomicSigNum, SigNum},
|
||||||
|
signals::Signal,
|
||||||
Pauser,
|
Pauser,
|
||||||
},
|
},
|
||||||
status::ProcessStatus,
|
status::ProcessStatus,
|
||||||
@ -89,6 +93,8 @@ pub struct Process {
|
|||||||
// Signal
|
// Signal
|
||||||
/// Sig dispositions
|
/// Sig dispositions
|
||||||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||||
|
/// The signal that the process should receive when parent process exits.
|
||||||
|
parent_death_signal: AtomicSigNum,
|
||||||
|
|
||||||
/// A profiling clock measures the user CPU time and kernel CPU time of the current process.
|
/// A profiling clock measures the user CPU time and kernel CPU time of the current process.
|
||||||
prof_clock: Arc<ProfClock>,
|
prof_clock: Arc<ProfClock>,
|
||||||
@ -105,12 +111,14 @@ impl Process {
|
|||||||
threads: Vec<Arc<Thread>>,
|
threads: Vec<Arc<Thread>>,
|
||||||
executable_path: String,
|
executable_path: String,
|
||||||
process_vm: ProcessVm,
|
process_vm: ProcessVm,
|
||||||
file_table: Arc<Mutex<FileTable>>,
|
|
||||||
fs: Arc<RwMutex<FsResolver>>,
|
fs: Arc<RwMutex<FsResolver>>,
|
||||||
|
file_table: Arc<Mutex<FileTable>>,
|
||||||
|
|
||||||
umask: Arc<RwLock<FileCreationMask>>,
|
umask: Arc<RwLock<FileCreationMask>>,
|
||||||
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
|
||||||
resource_limits: ResourceLimits,
|
resource_limits: ResourceLimits,
|
||||||
nice: Nice,
|
nice: Nice,
|
||||||
|
sig_dispositions: Arc<Mutex<SigDispositions>>,
|
||||||
) -> Arc<Self> {
|
) -> Arc<Self> {
|
||||||
let children_pauser = {
|
let children_pauser = {
|
||||||
// SIGCHID does not interrupt pauser. Child process will
|
// SIGCHID does not interrupt pauser. Child process will
|
||||||
@ -135,6 +143,7 @@ impl Process {
|
|||||||
fs,
|
fs,
|
||||||
umask,
|
umask,
|
||||||
sig_dispositions,
|
sig_dispositions,
|
||||||
|
parent_death_signal: AtomicSigNum::new_empty(),
|
||||||
resource_limits: Mutex::new(resource_limits),
|
resource_limits: Mutex::new(resource_limits),
|
||||||
nice: Atomic::new(nice),
|
nice: Atomic::new(nice),
|
||||||
timer_manager: PosixTimerManager::new(&prof_clock, process_ref),
|
timer_manager: PosixTimerManager::new(&prof_clock, process_ref),
|
||||||
@ -587,6 +596,24 @@ impl Process {
|
|||||||
posix_thread.enqueue_signal(Box::new(signal));
|
posix_thread.enqueue_signal(Box::new(signal));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears the parent death signal.
|
||||||
|
pub fn clear_parent_death_signal(&self) {
|
||||||
|
self.parent_death_signal.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the parent death signal as `signum`.
|
||||||
|
pub fn set_parent_death_signal(&self, sig_num: SigNum) {
|
||||||
|
self.parent_death_signal.set(sig_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the parent death signal.
|
||||||
|
///
|
||||||
|
/// The parent death signal is the signal will be sent to child processes
|
||||||
|
/// when the process exits.
|
||||||
|
pub fn parent_death_signal(&self) -> Option<SigNum> {
|
||||||
|
self.parent_death_signal.as_sig_num()
|
||||||
|
}
|
||||||
|
|
||||||
// ******************* Status ********************
|
// ******************* Status ********************
|
||||||
|
|
||||||
fn set_runnable(&self) {
|
fn set_runnable(&self) {
|
||||||
@ -642,12 +669,12 @@ mod test {
|
|||||||
vec![],
|
vec![],
|
||||||
String::new(),
|
String::new(),
|
||||||
ProcessVm::alloc(),
|
ProcessVm::alloc(),
|
||||||
Arc::new(Mutex::new(FileTable::new())),
|
|
||||||
Arc::new(RwMutex::new(FsResolver::new())),
|
Arc::new(RwMutex::new(FsResolver::new())),
|
||||||
|
Arc::new(Mutex::new(FileTable::new())),
|
||||||
Arc::new(RwLock::new(FileCreationMask::default())),
|
Arc::new(RwLock::new(FileCreationMask::default())),
|
||||||
Arc::new(Mutex::new(SigDispositions::default())),
|
|
||||||
ResourceLimits::default(),
|
ResourceLimits::default(),
|
||||||
Nice::default(),
|
Nice::default(),
|
||||||
|
Arc::new(Mutex::new(SigDispositions::default())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use core::sync::atomic::AtomicU8;
|
||||||
|
|
||||||
|
use atomic::Ordering;
|
||||||
|
|
||||||
use super::constants::*;
|
use super::constants::*;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
@ -77,3 +83,46 @@ impl SigNum {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Atomic signal number.
|
||||||
|
///
|
||||||
|
/// This struct represents a signal number and is different from [SigNum]
|
||||||
|
/// in that it allows for an empty signal number.
|
||||||
|
pub struct AtomicSigNum(AtomicU8);
|
||||||
|
|
||||||
|
impl AtomicSigNum {
|
||||||
|
/// Creates a new empty atomic signal number
|
||||||
|
pub const fn new_empty() -> Self {
|
||||||
|
Self(AtomicU8::new(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new signal number with the specified value
|
||||||
|
pub const fn new(sig_num: SigNum) -> Self {
|
||||||
|
Self(AtomicU8::new(sig_num.as_u8()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Determines whether the signal number is empty
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.load(Ordering::Relaxed) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the corresponding [`SigNum`]
|
||||||
|
pub fn as_sig_num(&self) -> Option<SigNum> {
|
||||||
|
let sig_num = self.0.load(Ordering::Relaxed);
|
||||||
|
if sig_num == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(SigNum::from_u8(sig_num))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the new `sig_num`
|
||||||
|
pub fn set(&self, sig_num: SigNum) {
|
||||||
|
self.0.store(sig_num.as_u8(), Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the signal number
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.0.store(0, Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
|||||||
process::{
|
process::{
|
||||||
check_executable_file, credentials_mut, load_program_to_vm,
|
check_executable_file, credentials_mut, load_program_to_vm,
|
||||||
posix_thread::{PosixThreadExt, ThreadName},
|
posix_thread::{PosixThreadExt, ThreadName},
|
||||||
Credentials, MAX_ARGV_NUMBER, MAX_ARG_LEN, MAX_ENVP_NUMBER, MAX_ENV_LEN,
|
Credentials, Process, MAX_ARGV_NUMBER, MAX_ARG_LEN, MAX_ENVP_NUMBER, MAX_ENV_LEN,
|
||||||
},
|
},
|
||||||
util::{read_cstring_from_user, read_val_from_user},
|
util::{read_cstring_from_user, read_val_from_user},
|
||||||
};
|
};
|
||||||
@ -118,8 +118,8 @@ fn do_execve(
|
|||||||
debug!("load elf in execve succeeds");
|
debug!("load elf in execve succeeds");
|
||||||
|
|
||||||
let credentials = credentials_mut();
|
let credentials = credentials_mut();
|
||||||
set_uid_from_elf(&credentials, &elf_file)?;
|
set_uid_from_elf(¤t, &credentials, &elf_file)?;
|
||||||
set_gid_from_elf(&credentials, &elf_file)?;
|
set_gid_from_elf(¤t, &credentials, &elf_file)?;
|
||||||
|
|
||||||
// set executable path
|
// set executable path
|
||||||
current.set_executable_path(new_executable_path);
|
current.set_executable_path(new_executable_path);
|
||||||
@ -177,10 +177,16 @@ fn read_cstring_vec(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets uid for credentials as the same of uid of elf file if elf file has `set_uid` bit.
|
/// Sets uid for credentials as the same of uid of elf file if elf file has `set_uid` bit.
|
||||||
fn set_uid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>) -> Result<()> {
|
fn set_uid_from_elf(
|
||||||
|
current: &Arc<Process>,
|
||||||
|
credentials: &Credentials<WriteOp>,
|
||||||
|
elf_file: &Arc<Dentry>,
|
||||||
|
) -> Result<()> {
|
||||||
if elf_file.mode()?.has_set_uid() {
|
if elf_file.mode()?.has_set_uid() {
|
||||||
let uid = elf_file.owner()?;
|
let uid = elf_file.owner()?;
|
||||||
credentials.set_euid(uid);
|
credentials.set_euid(uid);
|
||||||
|
|
||||||
|
current.clear_parent_death_signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// No matter whether the elf_file has `set_uid` bit, suid should be reset.
|
// No matter whether the elf_file has `set_uid` bit, suid should be reset.
|
||||||
@ -189,10 +195,16 @@ fn set_uid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sets gid for credentials as the same of gid of elf file if elf file has `set_gid` bit.
|
/// Sets gid for credentials as the same of gid of elf file if elf file has `set_gid` bit.
|
||||||
fn set_gid_from_elf(credentials: &Credentials<WriteOp>, elf_file: &Arc<Dentry>) -> Result<()> {
|
fn set_gid_from_elf(
|
||||||
|
current: &Arc<Process>,
|
||||||
|
credentials: &Credentials<WriteOp>,
|
||||||
|
elf_file: &Arc<Dentry>,
|
||||||
|
) -> Result<()> {
|
||||||
if elf_file.mode()?.has_set_gid() {
|
if elf_file.mode()?.has_set_gid() {
|
||||||
let gid = elf_file.group()?;
|
let gid = elf_file.group()?;
|
||||||
credentials.set_egid(gid);
|
credentials.set_egid(gid);
|
||||||
|
|
||||||
|
current.clear_parent_death_signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
// No matter whether the the elf file has `set_gid` bit, sgid should be reset.
|
// No matter whether the the elf file has `set_gid` bit, sgid should be reset.
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::{posix_thread::PosixThreadExt, TermStatus},
|
process::{posix_thread::do_exit, TermStatus},
|
||||||
syscall::SyscallReturn,
|
syscall::SyscallReturn,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -10,14 +10,8 @@ pub fn sys_exit(exit_code: i32) -> Result<SyscallReturn> {
|
|||||||
debug!("exid code = {}", exit_code);
|
debug!("exid code = {}", exit_code);
|
||||||
|
|
||||||
let current_thread = current_thread!();
|
let current_thread = current_thread!();
|
||||||
current_thread.exit();
|
let term_status = TermStatus::Exited(exit_code as _);
|
||||||
|
do_exit(current_thread, term_status)?;
|
||||||
let tid = current_thread.tid();
|
|
||||||
let pid = current!().pid();
|
|
||||||
debug!("tid = {}, pid = {}", tid, pid);
|
|
||||||
|
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
|
||||||
posix_thread.exit(tid, TermStatus::Exited(exit_code as _))?;
|
|
||||||
|
|
||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
@ -6,15 +6,35 @@
|
|||||||
use super::SyscallReturn;
|
use super::SyscallReturn;
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
process::posix_thread::{PosixThreadExt, MAX_THREAD_NAME_LEN},
|
process::{
|
||||||
util::{read_cstring_from_user, write_bytes_to_user},
|
posix_thread::{PosixThreadExt, MAX_THREAD_NAME_LEN},
|
||||||
|
signal::sig_num::SigNum,
|
||||||
|
},
|
||||||
|
util::{read_cstring_from_user, write_bytes_to_user, write_val_to_user},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<SyscallReturn> {
|
pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<SyscallReturn> {
|
||||||
let prctl_cmd = PrctlCmd::from_args(option, arg2, arg3, arg4, arg5)?;
|
let prctl_cmd = PrctlCmd::from_args(option, arg2, arg3, arg4, arg5)?;
|
||||||
debug!("prctl cmd = {:x?}", prctl_cmd);
|
debug!("prctl cmd = {:x?}", prctl_cmd);
|
||||||
let current_thread = current_thread!();
|
let current_thread = current_thread!();
|
||||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||||
match prctl_cmd {
|
match prctl_cmd {
|
||||||
|
PrctlCmd::PR_SET_PDEATHSIG(signum) => {
|
||||||
|
let current = current!();
|
||||||
|
current.set_parent_death_signal(signum);
|
||||||
|
}
|
||||||
|
PrctlCmd::PR_GET_PDEATHSIG(write_to_addr) => {
|
||||||
|
let write_val = {
|
||||||
|
let current = current!();
|
||||||
|
|
||||||
|
match current.parent_death_signal() {
|
||||||
|
None => 0i32,
|
||||||
|
Some(signum) => signum.as_u8() as i32,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
write_val_to_user(write_to_addr, &write_val)?;
|
||||||
|
}
|
||||||
PrctlCmd::PR_GET_NAME(write_to_addr) => {
|
PrctlCmd::PR_GET_NAME(write_to_addr) => {
|
||||||
let thread_name = posix_thread.thread_name().lock();
|
let thread_name = posix_thread.thread_name().lock();
|
||||||
if let Some(thread_name) = &*thread_name {
|
if let Some(thread_name) = &*thread_name {
|
||||||
@ -35,6 +55,8 @@ pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Res
|
|||||||
Ok(SyscallReturn::Return(0))
|
Ok(SyscallReturn::Return(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PR_SET_PDEATHSIG: i32 = 1;
|
||||||
|
const PR_GET_PDEATHSIG: i32 = 2;
|
||||||
const PR_SET_NAME: i32 = 15;
|
const PR_SET_NAME: i32 = 15;
|
||||||
const PR_GET_NAME: i32 = 16;
|
const PR_GET_NAME: i32 = 16;
|
||||||
const PR_SET_TIMERSLACK: i32 = 29;
|
const PR_SET_TIMERSLACK: i32 = 29;
|
||||||
@ -43,6 +65,8 @@ const PR_GET_TIMERSLACK: i32 = 30;
|
|||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum PrctlCmd {
|
pub enum PrctlCmd {
|
||||||
|
PR_SET_PDEATHSIG(SigNum),
|
||||||
|
PR_GET_PDEATHSIG(Vaddr),
|
||||||
PR_SET_NAME(Vaddr),
|
PR_SET_NAME(Vaddr),
|
||||||
PR_GET_NAME(Vaddr),
|
PR_GET_NAME(Vaddr),
|
||||||
PR_SET_TIMERSLACK(u64),
|
PR_SET_TIMERSLACK(u64),
|
||||||
@ -52,6 +76,11 @@ pub enum PrctlCmd {
|
|||||||
impl PrctlCmd {
|
impl PrctlCmd {
|
||||||
fn from_args(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<PrctlCmd> {
|
fn from_args(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<PrctlCmd> {
|
||||||
match option {
|
match option {
|
||||||
|
PR_SET_PDEATHSIG => {
|
||||||
|
let signum = SigNum::try_from(arg2 as u8)?;
|
||||||
|
Ok(PrctlCmd::PR_SET_PDEATHSIG(signum))
|
||||||
|
}
|
||||||
|
PR_GET_PDEATHSIG => Ok(PrctlCmd::PR_GET_PDEATHSIG(arg2 as _)),
|
||||||
PR_SET_NAME => Ok(PrctlCmd::PR_SET_NAME(arg2 as _)),
|
PR_SET_NAME => Ok(PrctlCmd::PR_SET_NAME(arg2 as _)),
|
||||||
PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)),
|
PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)),
|
||||||
PR_GET_TIMERSLACK => todo!(),
|
PR_GET_TIMERSLACK => todo!(),
|
||||||
|
@ -65,13 +65,13 @@ impl Thread {
|
|||||||
&self.task
|
&self.task
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run this thread at once.
|
/// Runs this thread at once.
|
||||||
pub fn run(&self) {
|
pub fn run(&self) {
|
||||||
self.set_status(ThreadStatus::Running);
|
self.set_status(ThreadStatus::Running);
|
||||||
self.task.run();
|
self.task.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exit(&self) {
|
pub(super) fn exit(&self) {
|
||||||
self.set_status(ThreadStatus::Exited);
|
self.set_status(ThreadStatus::Exited);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,14 +98,16 @@ impl Thread {
|
|||||||
self.tid
|
self.tid
|
||||||
}
|
}
|
||||||
|
|
||||||
// The return type must be borrowed box, otherwise the downcast_ref will fail
|
/// Returns the associated data.
|
||||||
|
///
|
||||||
|
/// The return type must be borrowed box, otherwise the `downcast_ref` will fail.
|
||||||
#[allow(clippy::borrowed_box)]
|
#[allow(clippy::borrowed_box)]
|
||||||
pub fn data(&self) -> &Box<dyn Send + Sync + Any> {
|
pub fn data(&self) -> &Box<dyn Send + Sync + Any> {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// allocate a new pid for new process
|
/// Allocates a new tid for the new thread
|
||||||
pub fn allocate_tid() -> Tid {
|
pub fn allocate_tid() -> Tid {
|
||||||
TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst)
|
TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst)
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ itimer/timer_create
|
|||||||
mmap/map_shared_anon
|
mmap/map_shared_anon
|
||||||
pthread/pthread_test
|
pthread/pthread_test
|
||||||
pty/open_pty
|
pty/open_pty
|
||||||
|
signal_c/parent_death_signal
|
||||||
signal_c/signal_test
|
signal_c/signal_test
|
||||||
"
|
"
|
||||||
|
|
||||||
|
49
regression/apps/signal_c/parent_death_signal.c
Normal file
49
regression/apps/signal_c/parent_death_signal.c
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
void signal_handler(int signum)
|
||||||
|
{
|
||||||
|
if (signum == SIGTERM) {
|
||||||
|
printf("child process reveives SIGTERM\n");
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
pid_t pid = fork();
|
||||||
|
|
||||||
|
if (pid == -1) {
|
||||||
|
perror("fork");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid > 0) {
|
||||||
|
printf("Parent PID: %d\n", getpid());
|
||||||
|
// Ensure parent won't exit before child process runs
|
||||||
|
sleep(1);
|
||||||
|
} else {
|
||||||
|
printf("CHild PID: %d\n", getpid());
|
||||||
|
|
||||||
|
prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = signal_handler;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
|
||||||
|
// Child waits for signal from parent death
|
||||||
|
while (1) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
Reference in New Issue
Block a user