Genericize `kill*` functions with `Signal` trait
This commit is contained in:
parent
3d6d91ea18
commit
3ae286980e
|
|
@ -49,7 +49,7 @@ fn send_parent_death_signal(current_process: &Process) {
|
|||
};
|
||||
|
||||
// FIXME: Set `si_pid` in the `siginfo_t` argument.
|
||||
let signal = KernelSignal::new(signum);
|
||||
let signal = Box::new(KernelSignal::new(signum));
|
||||
child.enqueue_signal(signal);
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ fn send_child_death_signal(current_process: &Process) {
|
|||
};
|
||||
|
||||
if let Some(signal) = current_process.exit_signal().map(KernelSignal::new) {
|
||||
parent.enqueue_signal(signal);
|
||||
parent.enqueue_signal(Box::new(signal));
|
||||
};
|
||||
parent.children_wait_queue().wake_all();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,7 @@ use super::{
|
|||
Pgid, Pid, Process,
|
||||
posix_thread::{AsPosixThread, thread_table},
|
||||
process_table,
|
||||
signal::{
|
||||
constants::SIGCONT,
|
||||
sig_num::SigNum,
|
||||
signals::{Signal, user::UserSignal},
|
||||
},
|
||||
signal::{constants::SIGCONT, sig_num::SigNum, signals::Signal},
|
||||
};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
|
|
@ -23,8 +19,8 @@ use crate::{
|
|||
///
|
||||
/// If `signal` is `None`, this method will only check permission without sending
|
||||
/// any signal.
|
||||
pub fn kill(pid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||
// Fast path: If the signal is sent to self, we can skip most check.
|
||||
pub fn kill(pid: Pid, signal: Option<Box<dyn Signal>>, ctx: &Context) -> Result<()> {
|
||||
// Fast path: If the signal is sent to self, we can skip most checks.
|
||||
if pid == ctx.process.pid() {
|
||||
let Some(signal) = signal else {
|
||||
return Ok(());
|
||||
|
|
@ -32,7 +28,7 @@ pub fn kill(pid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
|
||||
if !ctx.posix_thread.has_signal_blocked(signal.num()) {
|
||||
// Killing the current thread does not raise any permission issues.
|
||||
ctx.posix_thread.enqueue_signal(Box::new(signal));
|
||||
ctx.posix_thread.enqueue_signal(signal);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +36,6 @@ pub fn kill(pid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
}
|
||||
|
||||
// Slow path
|
||||
|
||||
let process = process_table::get_process(pid)
|
||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?;
|
||||
|
||||
|
|
@ -55,7 +50,7 @@ pub fn kill(pid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
///
|
||||
/// If `signal` is `None`, this method will only check permission without sending
|
||||
/// any signal.
|
||||
pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||
pub fn kill_group<S: Signal + Clone>(pgid: Pgid, signal: Option<S>, ctx: &Context) -> Result<()> {
|
||||
let process_group = process_table::get_process_group(&pgid)
|
||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target group does not exist"))?;
|
||||
|
||||
|
|
@ -63,7 +58,11 @@ pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>, ctx: &Context) -> Resu
|
|||
|
||||
let inner = process_group.lock();
|
||||
for process in inner.iter() {
|
||||
let res = kill_process(process, signal, ctx);
|
||||
let res = kill_process(
|
||||
process,
|
||||
signal.clone().map(|s| Box::new(s) as Box<dyn Signal>),
|
||||
ctx,
|
||||
);
|
||||
if res.is_err_and(|err| err.error() != Errno::EPERM) {
|
||||
result = res;
|
||||
}
|
||||
|
|
@ -77,7 +76,7 @@ pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>, ctx: &Context) -> Resu
|
|||
///
|
||||
/// If `signal` is `None`, this method will only check permission without sending
|
||||
/// any signal.
|
||||
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<Box<dyn Signal>>, ctx: &Context) -> Result<()> {
|
||||
let thread = thread_table::get_thread(tid)
|
||||
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target thread does not exist"))?;
|
||||
let target_posix_thread = thread.as_posix_thread().unwrap();
|
||||
|
|
@ -92,7 +91,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) ->
|
|||
}
|
||||
|
||||
// Check permission
|
||||
let signum = signal.map(|signal| signal.num());
|
||||
let signum = signal.as_ref().map(|signal| signal.num());
|
||||
check_signal_perm(target_posix_thread, ctx, signum)?;
|
||||
|
||||
if thread.is_exited() {
|
||||
|
|
@ -102,7 +101,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) ->
|
|||
if let Some(signal) = signal {
|
||||
// We've checked the permission issues above.
|
||||
// FIXME: We should take some lock while checking the permission to avoid race conditions.
|
||||
target_posix_thread.enqueue_signal(Box::new(signal));
|
||||
target_posix_thread.enqueue_signal(signal);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
@ -113,7 +112,7 @@ pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>, ctx: &Context) ->
|
|||
///
|
||||
/// The credentials of the current process will be checked to determine
|
||||
/// if it is authorized to send the signal to the target group.
|
||||
pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||
pub fn kill_all<S: Signal + Clone>(signal: Option<S>, ctx: &Context) -> Result<()> {
|
||||
let mut result = Ok(());
|
||||
|
||||
for process in process_table::process_table_mut().iter() {
|
||||
|
|
@ -121,7 +120,11 @@ pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
continue;
|
||||
}
|
||||
|
||||
let res = kill_process(process, signal, ctx);
|
||||
let res = kill_process(
|
||||
process,
|
||||
signal.clone().map(|s| Box::new(s) as Box<dyn Signal>),
|
||||
ctx,
|
||||
);
|
||||
if res.is_err_and(|err| err.error() != Errno::EPERM) {
|
||||
result = res;
|
||||
}
|
||||
|
|
@ -130,8 +133,8 @@ pub fn kill_all(signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
|||
result
|
||||
}
|
||||
|
||||
fn kill_process(process: &Process, signal: Option<UserSignal>, ctx: &Context) -> Result<()> {
|
||||
let signum = signal.map(|signal| signal.num());
|
||||
fn kill_process(process: &Process, signal: Option<Box<dyn Signal>>, ctx: &Context) -> Result<()> {
|
||||
let signum = signal.as_ref().map(|signal| signal.num());
|
||||
let target_main_thread = process.main_thread();
|
||||
check_signal_perm(target_main_thread.as_posix_thread().unwrap(), ctx, signum)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -634,12 +634,12 @@ impl Process {
|
|||
/// This method does not perform permission checks on user signals.
|
||||
/// Therefore, unless the caller can ensure that there are no permission issues,
|
||||
/// this method should be used to enqueue kernel signals or fault signals.
|
||||
pub fn enqueue_signal(&self, signal: impl Signal + Clone + 'static) {
|
||||
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
if self.status.is_zombie() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.sig_queues.enqueue(Box::new(signal));
|
||||
self.sig_queues.enqueue(signal);
|
||||
|
||||
for task in self.tasks.lock().as_slice() {
|
||||
let posix_thread = task.as_posix_thread().unwrap();
|
||||
|
|
@ -819,7 +819,7 @@ pub fn enqueue_signal_async(process: Weak<Process>, signum: SigNum) {
|
|||
work_queue::submit_work_func(
|
||||
move || {
|
||||
if let Some(process) = process.upgrade() {
|
||||
process.enqueue_signal(KernelSignal::new(signum));
|
||||
process.enqueue_signal(Box::new(KernelSignal::new(signum)));
|
||||
}
|
||||
},
|
||||
work_queue::WorkPriority::High,
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl ProcessGroup {
|
|||
// TODO: Do some checks to forbid user signals.
|
||||
pub fn broadcast_signal(&self, signal: impl Signal + Clone + 'static) {
|
||||
for process in self.inner.lock().processes.values() {
|
||||
process.enqueue_signal(signal.clone());
|
||||
process.enqueue_signal(Box::new(signal.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ fn create_process_timer_callback(
|
|||
let sent_signal = move || {
|
||||
let signal = KernelSignal::new(SIGALRM);
|
||||
if let Some(process) = current_process.upgrade() {
|
||||
process.enqueue_signal(signal);
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use crate::{
|
|||
ProcessFilter, kill, kill_all, kill_group,
|
||||
signal::{
|
||||
sig_num::SigNum,
|
||||
signals::user::{UserSignal, UserSignalKind},
|
||||
signals::{
|
||||
Signal,
|
||||
user::{UserSignal, UserSignalKind},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -36,7 +39,9 @@ pub fn do_sys_kill(filter: ProcessFilter, sig_num: Option<SigNum>, ctx: &Context
|
|||
|
||||
match filter {
|
||||
ProcessFilter::Any => kill_all(signal, ctx)?,
|
||||
ProcessFilter::WithPid(pid) => kill(pid, signal, ctx)?,
|
||||
ProcessFilter::WithPid(pid) => {
|
||||
kill(pid, signal.map(|s| Box::new(s) as Box<dyn Signal>), ctx)?
|
||||
}
|
||||
ProcessFilter::WithPgid(pgid) => kill_group(pgid, signal, ctx)?,
|
||||
ProcessFilter::WithPidfd(_) => unreachable!(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ use crate::{
|
|||
Pid,
|
||||
signal::{
|
||||
sig_num::SigNum,
|
||||
signals::user::{UserSignal, UserSignalKind},
|
||||
signals::{
|
||||
Signal,
|
||||
user::{UserSignal, UserSignalKind},
|
||||
},
|
||||
},
|
||||
tgkill,
|
||||
},
|
||||
|
|
@ -30,7 +33,7 @@ pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8, ctx: &Context) -> Result<Sys
|
|||
let signal = sig_num.map(|sig_num| {
|
||||
let pid = ctx.process.pid();
|
||||
let uid = ctx.posix_thread.credentials().ruid();
|
||||
UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid)
|
||||
Box::new(UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid)) as Box<dyn Signal>
|
||||
});
|
||||
tgkill(tid, tgid, signal, ctx)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ pub fn sys_timer_create(
|
|||
let process = current_process.clone();
|
||||
let signal = KernelSignal::new(SIGALRM);
|
||||
Box::new(move || {
|
||||
process.enqueue_signal(signal);
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
})
|
||||
// Determine the timeout action through `sigevent`.
|
||||
} else {
|
||||
|
|
@ -62,7 +62,7 @@ pub fn sys_timer_create(
|
|||
let process = current_process.clone();
|
||||
let signal = KernelSignal::new(SigNum::try_from(signo as u8)?);
|
||||
Box::new(move || {
|
||||
process.enqueue_signal(signal);
|
||||
process.enqueue_signal(Box::new(signal));
|
||||
})
|
||||
}
|
||||
// Spawn a posix thread to run the `sigev_function`, which is stored in
|
||||
|
|
|
|||
Loading…
Reference in New Issue