mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 08:53:29 +00:00
Refactor signal code
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
90be8038e0
commit
3734306398
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
168
services/libs/jinux-std/src/process/kill.rs
Normal file
168
services/libs/jinux-std/src/process/kill.rs
Normal 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(¤t, &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
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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 ********************
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user