Refactor signal code

This commit is contained in:
Jianfeng Jiang
2023-11-29 11:43:17 +00:00
committed by Tate, Hongliang Tian
parent 90be8038e0
commit 3734306398
18 changed files with 392 additions and 204 deletions

View File

@ -50,6 +50,7 @@ typeflags::typeflags! {
pub type Full = TRightSet<TRights![Dup, Read, Write, Exec, Signal]>;
pub type ReadOp = TRights![Read];
pub type WriteOp = TRights![Write];
pub type FullOp = TRights![Read, Write, Dup];
/// Wrapper for TRights, used to bypass an error message from the Rust compiler,
/// the relevant issue is: https://github.com/rust-lang/rfcs/issues/2758

View File

@ -48,7 +48,7 @@ pub fn do_exit_group(term_status: TermStatus) {
if let Some(parent) = current.parent() {
// Notify parent
let signal = Box::new(KernelSignal::new(SIGCHLD));
let signal = KernelSignal::new(SIGCHLD);
parent.enqueue_signal(signal);
parent.children_pauser().resume_all();
}

View File

@ -0,0 +1,168 @@
use super::posix_thread::PosixThreadExt;
use super::signal::signals::user::UserSignal;
use super::signal::signals::Signal;
use super::{credentials, process_table, Pgid, Pid, Process, Sid, Uid};
use crate::prelude::*;
use crate::thread::{thread_table, Tid};
/// Sends a signal to a process, using the current process as the sender.
///
/// The credentials of the current process will be checked to determine
/// if it is authorized to send the signal to this particular target process.
///
/// If `signal` is `None`, this method will only check permission without sending
/// any signal.
pub fn kill(pid: Pid, signal: Option<UserSignal>) -> Result<()> {
let process = process_table::get_process(&pid)
.ok_or_else(|| Error::with_message(Errno::ESRCH, "the target process does not exist"))?;
kill_process(&process, signal)
}
/// Sends a signal to all processes in a group, using the current process
/// as the sender.
///
/// The credentials of the current process will be checked to determine
/// if it is authorized to send the signal to the target group.
///
/// If `signal` is `None`, this method will only check permission without sending
/// any signal.
pub fn kill_group(pgid: Pgid, signal: Option<UserSignal>) -> Result<()> {
let process_group = process_table::get_process_group(&pgid)
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target group does not exist"))?;
let inner = process_group.inner.lock();
for process in inner.processes.values() {
kill_process(process, signal)?;
}
Ok(())
}
/// Sends a signal to a target thread, using the current process
/// as the sender.
///
/// If `signal` is `None`, this method will only check permission without sending
/// any signal.
pub fn tgkill(tid: Tid, tgid: Pid, signal: Option<UserSignal>) -> Result<()> {
let thread = thread_table::get_thread(tid)
.ok_or_else(|| Error::with_message(Errno::ESRCH, "target thread does not exist"))?;
if thread.is_exited() {
return Ok(());
}
let posix_thread = thread.as_posix_thread().unwrap();
// Check tgid
let pid = posix_thread.process().pid();
if pid != tgid {
return_errno_with_message!(
Errno::EINVAL,
"the combination of tgid and pid is not valid"
);
}
// Check permission
let signum = signal.map(|signal| signal.num());
let sender = current_thread_sender_ids();
posix_thread.check_signal_perm(signum.as_ref(), &sender)?;
if let Some(signal) = signal {
posix_thread.enqueue_signal(Box::new(signal));
}
Ok(())
}
/// Sends a signal to all processes except current process and init process, using
/// the current process as the sender.
///
/// 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>) -> Result<()> {
let current = current!();
let processes = process_table::get_all_processes();
for process in processes {
if Arc::ptr_eq(&current, &process) || process.is_init_process() {
continue;
}
kill_process(&process, signal)?;
}
Ok(())
}
fn kill_process(process: &Process, signal: Option<UserSignal>) -> Result<()> {
let threads = process.threads().lock();
let posix_threads = threads
.iter()
.map(|thread| thread.as_posix_thread().unwrap());
// First check permission
let signum = signal.map(|signal| signal.num());
let sender_ids = current_thread_sender_ids();
let mut permitted_threads = {
posix_threads.clone().filter(|posix_thread| {
posix_thread
.check_signal_perm(signum.as_ref(), &sender_ids)
.is_ok()
})
};
if permitted_threads.clone().count() == 0 {
return_errno_with_message!(Errno::EPERM, "cannot send signal to the target process");
}
let Some(signal) = signal else { return Ok(()) };
// Send signal to any thread that does not blocks the signal.
for thread in permitted_threads.clone() {
if !thread.has_signal_blocked(&signal) {
thread.enqueue_signal(Box::new(signal));
return Ok(());
}
}
// If all threads block the signal, send signal to the first thread.
let first_thread = permitted_threads.next().unwrap();
first_thread.enqueue_signal(Box::new(signal));
Ok(())
}
fn current_thread_sender_ids() -> SignalSenderIds {
let credentials = credentials();
let ruid = credentials.ruid();
let euid = credentials.euid();
let sid = current!().session().unwrap().sid();
SignalSenderIds::new(ruid, euid, sid)
}
/// The ids of the signal sender process.
///
/// This struct now includes effective user id, real user id and session id.
pub(super) struct SignalSenderIds {
ruid: Uid,
euid: Uid,
sid: Sid,
}
impl SignalSenderIds {
fn new(ruid: Uid, euid: Uid, sid: Sid) -> Self {
Self { ruid, euid, sid }
}
pub(super) fn ruid(&self) -> Uid {
self.ruid
}
pub(super) fn euid(&self) -> Uid {
self.euid
}
pub(super) fn sid(&self) -> Sid {
self.sid
}
}

View File

@ -1,5 +1,7 @@
mod clone;
mod credentials;
mod exit;
mod kill;
pub mod posix_thread;
#[allow(clippy::module_inception)]
mod process;
@ -14,7 +16,9 @@ mod term_status;
mod wait;
pub use clone::{clone_child, CloneArgs, CloneFlags};
pub use credentials::{credentials, credentials_mut, Credentials, Gid, Uid};
pub use exit::do_exit_group;
pub use kill::{kill, kill_all, kill_group, tgkill};
pub use process::ProcessBuilder;
pub use process::{
current, ExitCode, JobControl, Pgid, Pid, Process, ProcessGroup, Session, Sid, Terminal,

View File

@ -5,6 +5,7 @@ use crate::process::posix_thread::{PosixThreadBuilder, PosixThreadExt};
use crate::process::process_vm::ProcessVm;
use crate::process::rlimit::ResourceLimits;
use crate::process::signal::sig_disposition::SigDispositions;
use crate::process::Credentials;
use crate::thread::Thread;
use super::{Pid, Process};
@ -26,6 +27,7 @@ pub struct ProcessBuilder<'a> {
umask: Option<Arc<RwLock<FileCreationMask>>>,
resource_limits: Option<ResourceLimits>,
sig_dispositions: Option<Arc<Mutex<SigDispositions>>>,
credentials: Option<Credentials>,
}
impl<'a> ProcessBuilder<'a> {
@ -43,6 +45,7 @@ impl<'a> ProcessBuilder<'a> {
umask: None,
resource_limits: None,
sig_dispositions: None,
credentials: None,
}
}
@ -91,17 +94,24 @@ impl<'a> ProcessBuilder<'a> {
self
}
pub fn credentials(&mut self, credentials: Credentials) -> &mut Self {
self.credentials = Some(credentials);
self
}
fn check_build(&self) -> Result<()> {
if self.main_thread_builder.is_some() {
debug_assert!(self.parent.upgrade().is_some());
debug_assert!(self.argv.is_none());
debug_assert!(self.envp.is_none());
debug_assert!(self.credentials.is_none());
}
if self.main_thread_builder.is_none() {
debug_assert!(self.parent.upgrade().is_none());
debug_assert!(self.argv.is_some());
debug_assert!(self.envp.is_some());
debug_assert!(self.credentials.is_some());
}
Ok(())
@ -122,6 +132,7 @@ impl<'a> ProcessBuilder<'a> {
umask,
resource_limits,
sig_dispositions,
credentials,
} = self;
let process_vm = process_vm.or_else(|| Some(ProcessVm::alloc())).unwrap();
@ -168,6 +179,7 @@ impl<'a> ProcessBuilder<'a> {
} else {
Thread::new_posix_thread_from_executable(
pid,
credentials.unwrap(),
process.vm(),
&process.fs().read(),
executable_path,

View File

@ -5,20 +5,17 @@ use super::rlimit::ResourceLimits;
use super::signal::constants::SIGCHLD;
use super::signal::sig_disposition::SigDispositions;
use super::signal::sig_mask::SigMask;
use super::signal::sig_queues::SigQueues;
use super::signal::signals::Signal;
use super::signal::{Pauser, SigEvents, SigEventsFilter};
use super::signal::Pauser;
use super::status::ProcessStatus;
use super::{process_table, TermStatus};
use super::{process_table, Credentials, TermStatus};
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;
use crate::fs::utils::FileCreationMask;
use crate::prelude::*;
use crate::thread::{allocate_tid, Thread};
use crate::vm::vmar::Vmar;
use jinux_rights::Full;
mod builder;
mod job_control;
@ -27,6 +24,7 @@ mod session;
mod terminal;
pub use builder::ProcessBuilder;
use jinux_rights::Full;
pub use job_control::JobControl;
pub use process_group::ProcessGroup;
pub use session::Session;
@ -73,10 +71,8 @@ pub struct Process {
resource_limits: Mutex<ResourceLimits>,
// Signal
/// sig dispositions
/// Sig dispositions
sig_dispositions: Arc<Mutex<SigDispositions>>,
/// Process-level signal queues
sig_queues: Mutex<SigQueues>,
}
impl Process {
@ -94,11 +90,10 @@ impl Process {
resource_limits: ResourceLimits,
) -> Self {
let children_pauser = {
let mut sigset = SigMask::new_full();
// SIGCHID does not interrupt pauser. Child process will
// resume paused parent when doing exit.
sigset.remove_signal(SIGCHLD);
Pauser::new_with_sigset(sigset)
let sigmask = SigMask::from(SIGCHLD);
Pauser::new_with_mask(sigmask)
};
Self {
@ -115,7 +110,6 @@ impl Process {
fs,
umask,
sig_dispositions,
sig_queues: Mutex::new(SigQueues::new()),
resource_limits: Mutex::new(resource_limits),
}
}
@ -144,8 +138,11 @@ impl Process {
let process_builder = {
let pid = allocate_tid();
let parent = Weak::new();
let credentials = Credentials::new_root();
let mut builder = ProcessBuilder::new(pid, executable_path, parent);
builder.argv(argv).envp(envp);
builder.argv(argv).envp(envp).credentials(credentials);
builder
};
@ -206,11 +203,23 @@ impl Process {
&self.resource_limits
}
fn main_thread(&self) -> Option<Arc<Thread>> {
self.threads
.lock()
.iter()
.find(|thread| thread.tid() == self.pid)
.cloned()
}
// *********** Parent and child ***********
pub fn parent(&self) -> Option<Arc<Process>> {
self.parent.lock().upgrade()
}
pub fn is_init_process(&self) -> bool {
self.parent().is_none()
}
pub(super) fn children(&self) -> &Mutex<BTreeMap<Pid, Arc<Process>>> {
&self.children
}
@ -501,30 +510,35 @@ impl Process {
&self.sig_dispositions
}
pub fn has_pending_signal(&self) -> bool {
!self.sig_queues.lock().is_empty()
}
pub fn enqueue_signal(&self, signal: Box<dyn Signal>) {
if !self.is_zombie() {
self.sig_queues.lock().enqueue(signal);
/// Enqueues a process-directed signal. This method should only be used for enqueue kernel
/// signal and fault signal.
///
/// The signal may be delivered to any one of the threads that does not currently have the
/// signal blocked. If more than one of the threads has the signal unblocked, then this method
/// chooses an arbitrary thread to which to deliver the signal.
///
/// TODO: restrict these method with access control tool.
pub fn enqueue_signal(&self, signal: impl Signal + Clone + 'static) {
if self.is_zombie() {
return;
}
}
pub fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
self.sig_queues.lock().dequeue(mask)
}
// TODO: check that the signal is not user signal
pub fn register_sigqueue_observer(
&self,
observer: Weak<dyn Observer<SigEvents>>,
filter: SigEventsFilter,
) {
self.sig_queues.lock().register_observer(observer, filter);
}
// Enqueue signal to the first thread that does not block the signal
let threads = self.threads.lock();
for thread in threads.iter() {
let posix_thread = thread.as_posix_thread().unwrap();
if !posix_thread.has_signal_blocked(&signal) {
posix_thread.enqueue_signal(Box::new(signal));
return;
}
}
pub fn unregiser_sigqueue_observer(&self, observer: &Weak<dyn Observer<SigEvents>>) {
self.sig_queues.lock().unregister_observer(observer);
// If all threads block the signal, enqueue signal to the first thread
let thread = threads.iter().next().unwrap();
let posix_thread = thread.as_posix_thread().unwrap();
posix_thread.enqueue_signal(Box::new(signal));
}
// ******************* Status ********************

View File

@ -66,9 +66,13 @@ impl ProcessGroup {
}
/// Broadcasts signal to all processes in the group.
///
/// This method should only be used to broadcast fault signal and kernel signal.
///
/// TODO: do more check to forbid user signal
pub fn broadcast_signal(&self, signal: impl Signal + Clone + 'static) {
for process in self.inner.lock().processes.values() {
process.enqueue_signal(Box::new(signal.clone()));
process.enqueue_signal(signal.clone());
}
}

View File

@ -4,9 +4,12 @@ use core::mem;
use jinux_frame::cpu::GeneralRegs;
use jinux_util::{read_union_fields, union_read_ptr::UnionReadPtr};
use crate::{prelude::*, process::Pid};
use crate::{
prelude::*,
process::{Pid, Uid},
};
use super::{sig_num::SigNum, signals::user::Uid};
use super::sig_num::SigNum;
pub type sigset_t = u64;
// FIXME: this type should be put at suitable place

View File

@ -26,6 +26,6 @@ impl SigEventsFilter {
impl EventsFilter<SigEvents> for SigEventsFilter {
fn filter(&self, event: &SigEvents) -> bool {
self.0.contains(event.0)
!self.0.contains(event.0)
}
}

View File

@ -37,67 +37,68 @@ use crate::{
pub fn handle_pending_signal(context: &mut UserContext) -> Result<()> {
let current = current!();
let current_thread = current_thread!();
let posix_thread = current_thread.as_posix_thread().unwrap();
let pid = current.pid();
let sig_mask = *posix_thread.sig_mask().lock();
// We first deal with signal in current thread, then signal in current process.
let signal = if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) {
Some(signal)
} else {
current.dequeue_signal(&sig_mask)
let signal = {
let posix_thread = current_thread.as_posix_thread().unwrap();
let sig_mask = *posix_thread.sig_mask().lock();
if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) {
signal
} else {
return Ok(());
}
};
if let Some(signal) = signal {
let sig_num = signal.num();
trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name());
let sig_action = current.sig_dispositions().lock().get(sig_num);
trace!("sig action: {:x?}", sig_action);
match sig_action {
SigAction::Ign => {
trace!("Ignore signal {:?}", sig_num);
}
SigAction::User {
handler_addr,
flags,
restorer_addr,
mask,
} => handle_user_signal(
sig_num,
handler_addr,
flags,
restorer_addr,
mask,
context,
signal.to_info(),
)?,
SigAction::Dfl => {
let sig_default_action = SigDefaultAction::from_signum(sig_num);
trace!("sig_default_action: {:?}", sig_default_action);
match sig_default_action {
SigDefaultAction::Core | SigDefaultAction::Term => {
warn!(
"{:?}: terminating on signal {}",
current.executable_path(),
sig_num.sig_name()
);
do_exit_group(TermStatus::Killed(sig_num));
// We should exit current here, since we cannot restore a valid status from trap now.
Task::current().exit();
let sig_num = signal.num();
trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name());
let sig_action = current.sig_dispositions().lock().get(sig_num);
trace!("sig action: {:x?}", sig_action);
match sig_action {
SigAction::Ign => {
trace!("Ignore signal {:?}", sig_num);
}
SigAction::User {
handler_addr,
flags,
restorer_addr,
mask,
} => handle_user_signal(
sig_num,
handler_addr,
flags,
restorer_addr,
mask,
context,
signal.to_info(),
)?,
SigAction::Dfl => {
let sig_default_action = SigDefaultAction::from_signum(sig_num);
trace!("sig_default_action: {:?}", sig_default_action);
match sig_default_action {
SigDefaultAction::Core | SigDefaultAction::Term => {
warn!(
"{:?}: terminating on signal {}",
current.executable_path(),
sig_num.sig_name()
);
do_exit_group(TermStatus::Killed(sig_num));
// We should exit current here, since we cannot restore a valid status from trap now.
Task::current().exit();
}
SigDefaultAction::Ign => {}
SigDefaultAction::Stop => {
let mut status = current_thread.status().lock();
if status.is_running() {
status.set_stopped();
}
SigDefaultAction::Ign => {}
SigDefaultAction::Stop => {
let mut status = current_thread.status().lock();
if status.is_running() {
status.set_stopped();
}
drop(status);
}
SigDefaultAction::Cont => {
let mut status = current_thread.status().lock();
if status.is_stopped() {
status.set_running();
}
drop(status);
drop(status);
}
SigDefaultAction::Cont => {
let mut status = current_thread.status().lock();
if status.is_stopped() {
status.set_running();
}
drop(status);
}
}
}
@ -120,6 +121,7 @@ pub fn handle_user_signal(
debug!("restorer_addr = 0x{:x}", restorer_addr);
// FIXME: How to respect flags?
if flags.contains_unsupported_flag() {
println!("flags = {:?}", flags);
panic!("Unsupported Signal flags");
}
if !flags.contains(SigActionFlags::SA_NODEFER) {

View File

@ -55,23 +55,24 @@ use super::{SigEvents, SigEventsFilter};
/// ```
pub struct Pauser {
wait_queue: WaitQueue,
sigset: SigMask,
sig_mask: SigMask,
is_interrupted: AtomicBool,
}
impl Pauser {
/// Create a new `Pauser`. The `Pauser` can be interrupted by all signals.
/// Create a new `Pauser`. The `Pauser` can be interrupted by all signals except that
/// are blocked by current thread.
pub fn new() -> Arc<Self> {
Self::new_with_sigset(SigMask::new_full())
Self::new_with_mask(SigMask::new_empty())
}
/// Create a new `Pauser`, the `Pauser` can only be interrupted by signals
/// in `sigset`.
pub fn new_with_sigset(sigset: SigMask) -> Arc<Self> {
/// Create a new `Pauser`, the `Pauser` will ignore signals that are in `sig_mask` and
/// blocked by current thread.
pub fn new_with_mask(sig_mask: SigMask) -> Arc<Self> {
let wait_queue = WaitQueue::new();
Arc::new(Self {
wait_queue,
sigset,
sig_mask,
is_interrupted: AtomicBool::new(false),
})
}
@ -106,20 +107,25 @@ impl Pauser {
{
self.is_interrupted.store(false, Ordering::Release);
// Register observers on sigqueues
// Register observer on sigqueue
let observer = Arc::downgrade(self) as Weak<dyn Observer<SigEvents>>;
let filter = SigEventsFilter::new(self.sigset);
let current = current!();
current.register_sigqueue_observer(observer.clone(), filter);
let filter = {
let sig_mask = {
let current_thread = current_thread!();
let poxis_thread = current_thread.as_posix_thread().unwrap();
let mut current_sigmask = *poxis_thread.sig_mask().lock();
current_sigmask.block(self.sig_mask.as_u64());
current_sigmask
};
SigEventsFilter::new(sig_mask)
};
let current_thread = current_thread!();
let posix_thread = current_thread.as_posix_thread().unwrap();
posix_thread.register_sigqueue_observer(observer.clone(), filter);
// Some signal may come before we register observer, so we do another check here.
if posix_thread.has_pending_signal() || current.has_pending_signal() {
if posix_thread.has_pending_signal() {
self.is_interrupted.store(true, Ordering::Release);
}
@ -148,7 +154,6 @@ impl Pauser {
self.wait_queue.wait_until(cond)
};
current.unregiser_sigqueue_observer(&observer);
posix_thread.unregiser_sigqueue_observer(&observer);
match res {

View File

@ -1,6 +1,7 @@
use crate::process::signal::{c_types::siginfo_t, constants::SI_KERNEL, sig_num::SigNum};
use super::Signal;
use crate::process::signal::c_types::siginfo_t;
use crate::process::signal::constants::SI_KERNEL;
use crate::process::signal::sig_num::SigNum;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct KernelSignal {

View File

@ -2,11 +2,12 @@ pub mod fault;
pub mod kernel;
pub mod user;
use super::c_types::siginfo_t;
use super::sig_num::SigNum;
use core::any::Any;
use core::fmt::Debug;
use super::{c_types::siginfo_t, sig_num::SigNum};
pub trait Signal: Send + Sync + Debug {
pub trait Signal: Send + Sync + Debug + Any {
/// Returns the number of the signal.
fn num(&self) -> SigNum;
/// Returns the siginfo_t that gives more details about a signal.

View File

@ -1,15 +1,8 @@
use crate::process::{
signal::{
c_types::siginfo_t,
constants::{SI_QUEUE, SI_TKILL, SI_USER},
sig_num::SigNum,
},
Pid,
};
use super::Signal;
pub type Uid = usize;
use crate::process::signal::c_types::siginfo_t;
use crate::process::signal::constants::{SI_QUEUE, SI_TKILL, SI_USER};
use crate::process::signal::sig_num::SigNum;
use crate::process::{Pid, Uid};
#[derive(Debug, Clone, Copy)]
pub struct UserSignal {
@ -40,10 +33,6 @@ impl UserSignal {
self.pid
}
pub fn uid(&self) -> Uid {
self.uid
}
pub fn kind(&self) -> UserSignalKind {
self.kind
}

View File

@ -1,18 +1,21 @@
use crate::{log_syscall_entry, prelude::*};
use crate::process::process_table;
use super::{SyscallReturn, SYS_KILL};
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::process::kill;
use crate::process::kill_all;
use crate::process::kill_group;
use crate::process::signal::sig_num::SigNum;
use crate::process::signal::signals::user::{UserSignal, UserSignalKind};
use crate::{
process::{signal::sig_num::SigNum, ProcessFilter},
syscall::SYS_KILL,
};
use super::SyscallReturn;
use crate::process::{credentials, ProcessFilter};
pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_KILL);
let process_filter = ProcessFilter::from_id(process_filter as _);
let sig_num = SigNum::try_from(sig_num as u8).unwrap();
let sig_num = if sig_num == 0 {
None
} else {
Some(SigNum::try_from(sig_num as u8)?)
};
debug!(
"process_filter = {:?}, sig_num = {:?}",
process_filter, sig_num
@ -21,32 +24,19 @@ pub fn sys_kill(process_filter: u64, sig_num: u64) -> Result<SyscallReturn> {
Ok(SyscallReturn::Return(0))
}
pub fn do_sys_kill(filter: ProcessFilter, sig_num: SigNum) -> Result<()> {
pub fn do_sys_kill(filter: ProcessFilter, sig_num: Option<SigNum>) -> Result<()> {
let current = current!();
let pid = current.pid();
// FIXME: use the correct uid
let uid = 0;
let signal = UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid);
let signal = sig_num.map(|sig_num| {
let pid = current.pid();
let uid = credentials().ruid();
UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid)
});
match filter {
ProcessFilter::Any => {
for process in process_table::get_all_processes() {
process.enqueue_signal(Box::new(signal));
}
}
ProcessFilter::WithPid(pid) => {
if let Some(process) = process_table::get_process(&pid) {
process.enqueue_signal(Box::new(signal));
} else {
return_errno_with_message!(Errno::ESRCH, "No such process in process table");
}
}
ProcessFilter::WithPgid(pgid) => {
if let Some(process_group) = process_table::get_process_group(&pgid) {
process_group.broadcast_signal(signal);
} else {
return_errno_with_message!(Errno::ESRCH, "No such process group in process table");
}
}
ProcessFilter::Any => kill_all(signal)?,
ProcessFilter::WithPid(pid) => kill(pid, signal)?,
ProcessFilter::WithPgid(pgid) => kill_group(pgid, signal)?,
}
Ok(())
}

View File

@ -1,44 +1,29 @@
use crate::process::posix_thread::PosixThreadExt;
use crate::thread::{thread_table, Tid};
use crate::{log_syscall_entry, prelude::*};
use super::SyscallReturn;
use crate::log_syscall_entry;
use crate::prelude::*;
use crate::process::signal::sig_num::SigNum;
use crate::process::signal::signals::user::{UserSignal, UserSignalKind};
use crate::process::Pid;
use crate::process::tgkill;
use crate::process::{credentials, Pid};
use crate::syscall::SYS_TGKILL;
use super::SyscallReturn;
use crate::thread::Tid;
/// tgkill send a signal to a thread with pid as its thread id, and tgid as its thread group id.
/// Since jinuxx only supports one-thread process now, tgkill will send signal to process with pid as its process id,
/// and tgid as its process group id.
pub fn sys_tgkill(tgid: Pid, tid: Tid, sig_num: u8) -> Result<SyscallReturn> {
log_syscall_entry!(SYS_TGKILL);
let sig_num = SigNum::from_u8(sig_num);
info!("tgid = {}, pid = {}, sig_num = {:?}", tgid, tid, sig_num);
let target_thread =
thread_table::get_thread(tid).ok_or(Error::with_message(Errno::EINVAL, "Invalid pid"))?;
let posix_thread = target_thread.as_posix_thread().unwrap();
let pid = posix_thread.process().pid();
if pid != tgid {
return_errno_with_message!(
Errno::EINVAL,
"the combination of tgid and pid is not valid"
);
}
if target_thread.status().lock().is_exited() {
return Ok(SyscallReturn::Return(0));
}
let signal = {
let src_pid = current!().pid();
let src_uid = 0;
Box::new(UserSignal::new(
sig_num,
UserSignalKind::Tkill,
src_pid,
src_uid,
))
let sig_num = if sig_num == 0 {
None
} else {
Some(SigNum::try_from(sig_num)?)
};
posix_thread.enqueue_signal(signal);
debug!("tgid = {}, pid = {}, sig_num = {:?}", tgid, tid, sig_num);
let signal = sig_num.map(|sig_num| {
let pid = current!().pid();
let uid = credentials().ruid();
UserSignal::new(sig_num, UserSignalKind::Tkill, pid, uid)
});
tgkill(tid, tgid, signal)?;
Ok(SyscallReturn::Return(0))
}

View File

@ -1,7 +1,8 @@
use jinux_frame::{cpu::*, vm::VmIo};
use crate::prelude::*;
use crate::process::signal::signals::fault::FaultSignal;
use crate::vm::page_fault_handler::PageFaultHandler;
use crate::{prelude::*, process::signal::signals::fault::FaultSignal};
use jinux_frame::cpu::*;
use jinux_frame::vm::VmIo;
/// We can't handle most exceptions, just send self a fault signal before return to user space.
pub fn handle_exception(context: &UserContext) {
@ -56,7 +57,7 @@ fn handle_page_fault(trap_info: &CpuExceptionInfo) {
/// generate a fault signal for current process.
fn generate_fault_signal(trap_info: &CpuExceptionInfo) {
let current = current!();
let signal = Box::new(FaultSignal::new(trap_info));
let signal = FaultSignal::new(trap_info);
current.enqueue_signal(signal);
}

View File

@ -420,8 +420,16 @@ impl Vmar_ {
}
pub fn write(&self, offset: usize, buf: &[u8]) -> Result<()> {
let write_start = self.base + offset;
let write_end = buf.len() + write_start;
let write_start = self
.base
.checked_add(offset)
.ok_or_else(|| Error::with_message(Errno::EFAULT, "Arithmetic Overflow"))?;
let write_end = buf
.len()
.checked_add(write_start)
.ok_or_else(|| Error::with_message(Errno::EFAULT, "Arithmetic Overflow"))?;
// if the write range is in child vmar
for (child_vmar_base, child_vmar) in &self.inner.lock().child_vmar_s {
let child_vmar_end = *child_vmar_base + child_vmar.size;