Re-introduce the process-wide sigqueues
This commit is contained in:
parent
c7058c7233
commit
00c79732e6
|
|
@ -17,7 +17,7 @@ use crate::{
|
|||
signal::{
|
||||
constants::{SIGCHLD, SIGKILL},
|
||||
signals::kernel::KernelSignal,
|
||||
SigStack,
|
||||
HandlePendingSignal, SigStack,
|
||||
},
|
||||
ContextUnshareAdminApi, Credentials, Process, ProgramToLoad,
|
||||
},
|
||||
|
|
@ -192,7 +192,7 @@ fn wait_other_threads_exit(ctx: &Context) -> Result<()> {
|
|||
let (waiter, waker) = Waiter::new_pair();
|
||||
|
||||
ctx.posix_thread.set_signalled_waker(waker.clone());
|
||||
if ctx.posix_thread.has_pending_sigkill() {
|
||||
if ctx.has_pending_sigkill() {
|
||||
ctx.posix_thread.clear_signalled_waker();
|
||||
return_errno_with_message!(Errno::EAGAIN, "the current thread has received SIGKILL");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,15 +6,7 @@ use aster_rights::{ReadDupOp, ReadOp, WriteOp};
|
|||
use ostd::sync::{RoArc, RwMutexReadGuard, Waker};
|
||||
|
||||
use super::{
|
||||
kill::SignalSenderIds,
|
||||
signal::{
|
||||
sig_disposition::SigDispositions,
|
||||
sig_mask::{AtomicSigMask, SigMask, SigSet},
|
||||
sig_num::SigNum,
|
||||
sig_queues::SigQueues,
|
||||
signals::Signal,
|
||||
SigEvents, SigEventsFilter,
|
||||
},
|
||||
signal::{sig_mask::AtomicSigMask, sig_num::SigNum, sig_queues::SigQueues, signals::Signal},
|
||||
Credentials, Process,
|
||||
};
|
||||
use crate::{
|
||||
|
|
@ -22,8 +14,11 @@ use crate::{
|
|||
fs::{file_table::FileTable, thread_info::ThreadFsInfo},
|
||||
prelude::*,
|
||||
process::{
|
||||
kill::SignalSenderIds,
|
||||
namespace::nsproxy::NsProxy,
|
||||
signal::constants::{SIGCONT, SIGKILL},
|
||||
signal::{
|
||||
constants::SIGCONT, sig_disposition::SigDispositions, SigEvents, SigEventsFilter,
|
||||
},
|
||||
Pid,
|
||||
},
|
||||
thread::{Thread, Tid},
|
||||
|
|
@ -141,25 +136,12 @@ impl PosixThread {
|
|||
&self.sig_mask
|
||||
}
|
||||
|
||||
pub fn sig_pending(&self) -> SigSet {
|
||||
self.sig_queues.sig_pending()
|
||||
}
|
||||
|
||||
/// Returns whether the thread has some pending signals
|
||||
/// that are not blocked.
|
||||
pub fn has_pending(&self) -> bool {
|
||||
let blocked = self.sig_mask().load(Ordering::Relaxed);
|
||||
self.sig_queues.has_pending(blocked)
|
||||
}
|
||||
|
||||
/// Returns whether the thread has pending SIGKILL signal.
|
||||
pub fn has_pending_sigkill(&self) -> bool {
|
||||
let blocked = SigSet::new_full() - SIGKILL;
|
||||
self.sig_queues.has_pending(blocked)
|
||||
pub(super) fn sig_queues(&self) -> &SigQueues {
|
||||
&self.sig_queues
|
||||
}
|
||||
|
||||
/// Returns whether the signal is blocked by the thread.
|
||||
pub(in crate::process) fn has_signal_blocked(&self, signum: SigNum) -> bool {
|
||||
pub fn has_signal_blocked(&self, signum: SigNum) -> bool {
|
||||
// FIXME: Some signals cannot be blocked, even set in sig_mask.
|
||||
self.sig_mask.contains(signum, Ordering::Relaxed)
|
||||
}
|
||||
|
|
@ -242,20 +224,12 @@ impl PosixThread {
|
|||
|
||||
/// Enqueues a thread-directed signal.
|
||||
///
|
||||
/// 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 for
|
||||
/// enqueue kernel signals or fault signals.
|
||||
/// 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: Box<dyn Signal>) {
|
||||
let process = self.process();
|
||||
let sig_dispositions = process.sig_dispositions().lock();
|
||||
let sig_dispositions = sig_dispositions.lock();
|
||||
|
||||
let signum = signal.num();
|
||||
if sig_dispositions.get(signum).will_ignore(signum) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.enqueue_signal_locked(signal, &sig_dispositions);
|
||||
self.sig_queues.enqueue(signal);
|
||||
self.wake_signalled_waker();
|
||||
}
|
||||
|
||||
/// Enqueues a thread-directed signal with locked dispositions.
|
||||
|
|
@ -305,10 +279,6 @@ impl PosixThread {
|
|||
self.prof_timer_manager.process_expired_timers();
|
||||
}
|
||||
|
||||
pub fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
|
||||
self.sig_queues.dequeue(mask)
|
||||
}
|
||||
|
||||
pub fn register_sigqueue_observer(
|
||||
&self,
|
||||
observer: Weak<dyn Observer<SigEvents>>,
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ use super::{
|
|||
};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{signal::Pollee, status::StopWaitStatus, UserNamespace, WaitOptions},
|
||||
process::{
|
||||
signal::{sig_queues::SigQueues, Pollee},
|
||||
status::StopWaitStatus,
|
||||
UserNamespace, WaitOptions,
|
||||
},
|
||||
sched::{AtomicNice, Nice},
|
||||
thread::{AsThread, Thread},
|
||||
time::clocks::ProfClock,
|
||||
|
|
@ -120,6 +124,8 @@ pub struct Process {
|
|||
// Signal
|
||||
/// Sig dispositions
|
||||
sig_dispositions: Mutex<Arc<Mutex<SigDispositions>>>,
|
||||
/// The process-level sigqueue.
|
||||
sig_queues: SigQueues,
|
||||
/// The signal that the process should receive when parent process exits.
|
||||
parent_death_signal: AtomicSigNum,
|
||||
|
||||
|
|
@ -234,6 +240,7 @@ impl Process {
|
|||
is_child_subreaper: AtomicBool::new(false),
|
||||
has_child_subreaper: AtomicBool::new(false),
|
||||
sig_dispositions: Mutex::new(sig_dispositions),
|
||||
sig_queues: SigQueues::new(),
|
||||
parent_death_signal: AtomicSigNum::new_empty(),
|
||||
exit_signal: AtomicSigNum::new_empty(),
|
||||
resource_limits,
|
||||
|
|
@ -621,44 +628,31 @@ impl Process {
|
|||
&self.sig_dispositions
|
||||
}
|
||||
|
||||
pub(super) fn sig_queues(&self) -> &SigQueues {
|
||||
&self.sig_queues
|
||||
}
|
||||
|
||||
/// Enqueues a process-directed signal.
|
||||
///
|
||||
/// This method should only be used for enqueue kernel signals and fault signals.
|
||||
///
|
||||
/// 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 have the signal unblocked, then this method
|
||||
/// chooses an arbitrary thread to which to deliver the signal.
|
||||
//
|
||||
// TODO: Restrict this method with the access control tool.
|
||||
/// 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) {
|
||||
if self.status.is_zombie() {
|
||||
return;
|
||||
}
|
||||
|
||||
let sig_dispositions = self.sig_dispositions.lock();
|
||||
let sig_dispositions = sig_dispositions.lock();
|
||||
self.sig_queues.enqueue(Box::new(signal));
|
||||
|
||||
// Drop the signal if it's ignored. See explanation at `enqueue_signal_locked`.
|
||||
let signum = signal.num();
|
||||
if sig_dispositions.get(signum).will_ignore(signum) {
|
||||
return;
|
||||
for task in self.tasks.lock().as_slice() {
|
||||
let posix_thread = task.as_posix_thread().unwrap();
|
||||
// FIXME: This behavior differs a bit from Linux.
|
||||
// Linux wakes up a single thread that neither blocks the signal
|
||||
// nor already has the same pending signal;
|
||||
// for simplicity we wake up all threads.
|
||||
// Reference: <https://elixir.bootlin.com/linux/v6.17/source/kernel/signal.c#L969>.
|
||||
posix_thread.wake_signalled_waker();
|
||||
}
|
||||
|
||||
let threads = self.tasks.lock();
|
||||
|
||||
// Enqueue the signal to the first thread that does not block the signal.
|
||||
for thread in threads.as_slice() {
|
||||
let posix_thread = thread.as_posix_thread().unwrap();
|
||||
if !posix_thread.has_signal_blocked(signal.num()) {
|
||||
posix_thread.enqueue_signal_locked(Box::new(signal), &sig_dispositions);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If all threads block the signal, enqueue the signal to the main thread.
|
||||
let thread = threads.main();
|
||||
let posix_thread = thread.as_posix_thread().unwrap();
|
||||
posix_thread.enqueue_signal_locked(Box::new(signal), &sig_dispositions);
|
||||
}
|
||||
|
||||
/// Clears the parent death signal.
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ pub mod c_types;
|
|||
pub mod constants;
|
||||
mod events;
|
||||
mod pause;
|
||||
mod pending;
|
||||
mod poll;
|
||||
pub mod sig_action;
|
||||
pub mod sig_disposition;
|
||||
|
|
@ -24,6 +25,7 @@ use ostd::{
|
|||
user::UserContextApi,
|
||||
};
|
||||
pub use pause::{with_sigmask_changed, Pause};
|
||||
pub use pending::HandlePendingSignal;
|
||||
pub use poll::{PollAdaptor, PollHandle, Pollable, Pollee, Poller};
|
||||
use sig_action::{SigAction, SigActionFlags, SigDefaultAction};
|
||||
use sig_mask::SigMask;
|
||||
|
|
@ -35,7 +37,11 @@ use crate::{
|
|||
cpu::LinuxAbi,
|
||||
current_userspace,
|
||||
prelude::*,
|
||||
process::{posix_thread::do_exit_group, signal::c_types::stack_t, TermStatus},
|
||||
process::{
|
||||
posix_thread::do_exit_group,
|
||||
signal::{c_types::stack_t, signals::Signal},
|
||||
TermStatus,
|
||||
},
|
||||
};
|
||||
|
||||
pub trait SignalContext {
|
||||
|
|
@ -61,38 +67,11 @@ pub fn handle_pending_signal(
|
|||
None
|
||||
};
|
||||
|
||||
let posix_thread = ctx.posix_thread;
|
||||
let current = ctx.process.as_ref();
|
||||
|
||||
let signal = {
|
||||
let sig_mask = posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||
if let Some(signal) = posix_thread.dequeue_signal(&sig_mask) {
|
||||
signal
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
let Some((signal, sig_action)) = dequeue_pending_signal(ctx) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let sig_num = signal.num();
|
||||
trace!("sig_num = {:?}, sig_name = {}", sig_num, sig_num.sig_name());
|
||||
|
||||
let sig_action = {
|
||||
let sig_dispositions = current.sig_dispositions().lock();
|
||||
let mut sig_dispositions = sig_dispositions.lock();
|
||||
let sig_action = sig_dispositions.get(sig_num);
|
||||
|
||||
if let SigAction::User { flags, .. } = &sig_action
|
||||
&& flags.contains(SigActionFlags::SA_RESETHAND)
|
||||
{
|
||||
// In Linux, SA_RESETHAND corresponds to SA_ONESHOT,
|
||||
// which means the user handler will be executed only once and then reset to the default.
|
||||
// Refer to https://elixir.bootlin.com/linux/v6.0.9/source/kernel/signal.c#L2761.
|
||||
sig_dispositions.set_default(sig_num);
|
||||
}
|
||||
|
||||
sig_action
|
||||
};
|
||||
trace!("sig action: {:x?}", sig_action);
|
||||
|
||||
match sig_action {
|
||||
SigAction::Ign => {
|
||||
trace!("Ignore signal {:?}", sig_num);
|
||||
|
|
@ -141,7 +120,7 @@ pub fn handle_pending_signal(
|
|||
SigDefaultAction::Core | SigDefaultAction::Term => {
|
||||
warn!(
|
||||
"{:?}: terminating on signal {}",
|
||||
current.executable_path(),
|
||||
ctx.process.executable_path(),
|
||||
sig_num.sig_name()
|
||||
);
|
||||
// We should exit current here, since we cannot restore a valid status from trap now.
|
||||
|
|
@ -155,6 +134,43 @@ pub fn handle_pending_signal(
|
|||
}
|
||||
}
|
||||
|
||||
fn dequeue_pending_signal(ctx: &Context) -> Option<(Box<dyn Signal>, SigAction)> {
|
||||
let posix_thread = ctx.posix_thread;
|
||||
|
||||
let sig_dispositions = ctx.process.sig_dispositions().lock();
|
||||
let mut sig_dispositions = sig_dispositions.lock();
|
||||
|
||||
let sig_mask = posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||
let (signal, sig_num, sig_action) = loop {
|
||||
let signal = ctx.dequeue_signal(&sig_mask)?;
|
||||
let sig_num = signal.num();
|
||||
let sig_action = sig_dispositions.get(sig_num);
|
||||
if sig_action.will_ignore(sig_num) {
|
||||
continue;
|
||||
}
|
||||
|
||||
break (signal, sig_num, sig_action);
|
||||
};
|
||||
|
||||
if let SigAction::User { flags, .. } = &sig_action
|
||||
&& flags.contains(SigActionFlags::SA_RESETHAND)
|
||||
{
|
||||
// In Linux, SA_RESETHAND corresponds to SA_ONESHOT,
|
||||
// which means the user handler will be executed only once and then reset to the default.
|
||||
// Reference: <https://elixir.bootlin.com/linux/v6.0.9/source/kernel/signal.c#L2761>.
|
||||
sig_dispositions.set_default(sig_num);
|
||||
}
|
||||
|
||||
trace!(
|
||||
"sig_num = {:?}, sig_name = {}, sig_action = {:#x?}",
|
||||
signal.num(),
|
||||
signal.num().sig_name(),
|
||||
sig_action
|
||||
);
|
||||
|
||||
Some((signal, sig_action))
|
||||
}
|
||||
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
pub fn handle_user_signal(
|
||||
ctx: &Context,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use ostd::sync::{WaitQueue, Waiter};
|
|||
use super::sig_mask::SigMask;
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::posix_thread::AsPosixThread,
|
||||
process::{posix_thread::AsPosixThread, signal::HandlePendingSignal},
|
||||
thread::AsThread,
|
||||
time::wait::{ManagedTimeout, TimeoutExt},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::sync::atomic::Ordering;
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{
|
||||
posix_thread::PosixThread,
|
||||
signal::{
|
||||
constants::SIGKILL,
|
||||
sig_mask::{SigMask, SigSet},
|
||||
signals::Signal,
|
||||
},
|
||||
Process,
|
||||
},
|
||||
};
|
||||
|
||||
/// Trait for handling pending signals.
|
||||
pub trait HandlePendingSignal {
|
||||
/// Returns the thread's pending signal set.
|
||||
///
|
||||
/// This includes signals that are currently blocked or ignored.
|
||||
fn pending_signals(&self) -> SigSet;
|
||||
|
||||
/// Returns if there are pending signals that are neither blocked nor ignored.
|
||||
///
|
||||
/// Note that ignored but not blocked signals may be dequeued silently.
|
||||
fn has_pending(&self) -> bool;
|
||||
|
||||
/// Returns if a SIGKILL signal is pending.
|
||||
fn has_pending_sigkill(&self) -> bool;
|
||||
|
||||
/// Dequeues the next pending signal that is not masked by `mask`.
|
||||
///
|
||||
/// Returns `None` if no such signal is available.
|
||||
fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>>;
|
||||
}
|
||||
|
||||
impl HandlePendingSignal for Context<'_> {
|
||||
fn pending_signals(&self) -> SigSet {
|
||||
self.posix_thread.sig_queues().sig_pending() | self.process.sig_queues().sig_pending()
|
||||
}
|
||||
|
||||
fn has_pending(&self) -> bool {
|
||||
let posix_thread = self.posix_thread;
|
||||
let process = self.process.as_ref();
|
||||
has_pending_signal(posix_thread, process)
|
||||
}
|
||||
|
||||
fn has_pending_sigkill(&self) -> bool {
|
||||
self.posix_thread.sig_queues().has_pending_signal(SIGKILL)
|
||||
|| self.process.sig_queues().has_pending_signal(SIGKILL)
|
||||
}
|
||||
|
||||
fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
|
||||
self.posix_thread
|
||||
.sig_queues()
|
||||
.dequeue(mask)
|
||||
.or_else(|| self.process.sig_queues().dequeue(mask))
|
||||
}
|
||||
}
|
||||
|
||||
impl HandlePendingSignal for PosixThread {
|
||||
fn pending_signals(&self) -> SigSet {
|
||||
self.sig_queues().sig_pending() | self.process().sig_queues().sig_pending()
|
||||
}
|
||||
|
||||
fn has_pending(&self) -> bool {
|
||||
let process = self.process();
|
||||
has_pending_signal(self, process.as_ref())
|
||||
}
|
||||
|
||||
fn has_pending_sigkill(&self) -> bool {
|
||||
self.sig_queues().has_pending_signal(SIGKILL)
|
||||
|| self.process().sig_queues().has_pending_signal(SIGKILL)
|
||||
}
|
||||
|
||||
fn dequeue_signal(&self, mask: &SigMask) -> Option<Box<dyn Signal>> {
|
||||
self.sig_queues()
|
||||
.dequeue(mask)
|
||||
.or_else(|| self.process().sig_queues().dequeue(mask))
|
||||
}
|
||||
}
|
||||
|
||||
fn has_pending_signal(posix_thread: &PosixThread, process: &Process) -> bool {
|
||||
// Fast path: No signals are pending.
|
||||
if posix_thread.sig_queues().is_empty() && process.sig_queues().is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Slow path: Some signals are pending.
|
||||
let sig_dispositions = process.sig_dispositions().lock();
|
||||
let sig_dispositions = sig_dispositions.lock();
|
||||
let blocked = posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||
|
||||
posix_thread
|
||||
.sig_queues()
|
||||
.has_pending(blocked, &sig_dispositions)
|
||||
|| process.sig_queues().has_pending(blocked, &sig_dispositions)
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::{constants::*, sig_action::SigAction, sig_num::SigNum};
|
||||
use crate::{prelude::*, process::signal::sig_action::SigActionFlags};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::signal::{sig_action::SigActionFlags, signals::Signal},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SigDispositions {
|
||||
|
|
@ -53,6 +56,11 @@ impl SigDispositions {
|
|||
fn num_to_idx(num: SigNum) -> usize {
|
||||
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
||||
}
|
||||
|
||||
pub fn will_ignore(&self, signal: &dyn Signal) -> bool {
|
||||
let signum = signal.num();
|
||||
self.get(signum).will_ignore(signum)
|
||||
}
|
||||
}
|
||||
|
||||
fn check_sigaction(sig_action: &SigAction) -> Result<()> {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ use super::{
|
|||
use crate::{
|
||||
events::{Observer, Subject},
|
||||
prelude::*,
|
||||
process::signal::sig_disposition::SigDispositions,
|
||||
};
|
||||
|
||||
pub struct SigQueues {
|
||||
|
|
@ -67,12 +68,22 @@ impl SigQueues {
|
|||
queues.sig_pending()
|
||||
}
|
||||
|
||||
/// Returns whether there's some pending signals that are not blocked
|
||||
pub fn has_pending(&self, blocked: SigMask) -> bool {
|
||||
if self.is_empty() {
|
||||
return false;
|
||||
}
|
||||
self.queues.lock().has_pending(blocked)
|
||||
/// Returns whether there's some pending signals that are not blocked and not ignored.
|
||||
///
|
||||
/// Note that ignored but not blocked signals may be dequeued silently.
|
||||
pub(in crate::process) fn has_pending(
|
||||
&self,
|
||||
blocked: SigMask,
|
||||
sig_dispositions: &SigDispositions,
|
||||
) -> bool {
|
||||
let mut queues = self.queues.lock();
|
||||
let (dequeued_signals, has_pending) = queues.has_pending(blocked, sig_dispositions);
|
||||
self.count.fetch_sub(dequeued_signals, Ordering::Relaxed);
|
||||
has_pending
|
||||
}
|
||||
|
||||
pub(in crate::process) fn has_pending_signal(&self, signum: SigNum) -> bool {
|
||||
self.queues.lock().has_pending_signal(signum)
|
||||
}
|
||||
|
||||
pub fn register_observer(
|
||||
|
|
@ -198,13 +209,69 @@ impl Queues {
|
|||
None
|
||||
}
|
||||
|
||||
/// Returns whether the `SigQueues` has some pending signals which are not blocked
|
||||
fn has_pending(&self, blocked: SigMask) -> bool {
|
||||
self.std_queues.iter().any(|signal| {
|
||||
signal
|
||||
.as_ref()
|
||||
.is_some_and(|signal| !blocked.contains(signal.num()))
|
||||
}) || self.rt_queues.iter().any(|rt_queue| !rt_queue.is_empty())
|
||||
/// Returns whether the `SigQueues` has some pending signals which are not blocked.
|
||||
///
|
||||
/// Note that signals are ignored but not blocked may be dequeued silently.
|
||||
fn has_pending(
|
||||
&mut self,
|
||||
blocked: SigMask,
|
||||
sig_dispositions: &SigDispositions,
|
||||
) -> (usize, bool) {
|
||||
let mut dequeued_signals = 0;
|
||||
|
||||
let has_pending = self.std_queues.iter_mut().any(|signal| {
|
||||
let Some(signal_ref) = signal.as_ref().map(AsRef::as_ref) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if blocked.contains(signal_ref.num()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dequeue signals that should be ignored but not blocked.
|
||||
if sig_dispositions.will_ignore(signal_ref) {
|
||||
dequeued_signals += 1;
|
||||
*signal = None;
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
}) || self.rt_queues.iter_mut().any(|rt_queue| {
|
||||
let Some(signal) = rt_queue.front() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if blocked.contains(signal.num()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dequeue signals that should be ignored but not blocked.
|
||||
if sig_dispositions.will_ignore(signal.as_ref()) {
|
||||
dequeued_signals += rt_queue.len();
|
||||
rt_queue.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
});
|
||||
|
||||
(dequeued_signals, has_pending)
|
||||
}
|
||||
|
||||
fn has_pending_signal(&self, signum: SigNum) -> bool {
|
||||
if signum.is_std() {
|
||||
self.get_std_queue(signum).is_some()
|
||||
} else if signum.is_real_time() {
|
||||
!self.get_rt_queue(signum).is_empty()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn get_std_queue(&self, signum: SigNum) -> &Option<Box<dyn Signal>> {
|
||||
debug_assert!(signum.is_std());
|
||||
let idx = (signum.as_u8() - MIN_STD_SIG_NUM) as usize;
|
||||
&self.std_queues[idx]
|
||||
}
|
||||
|
||||
fn get_std_queue_mut(&mut self, signum: SigNum) -> &mut Option<Box<dyn Signal>> {
|
||||
|
|
@ -213,6 +280,12 @@ impl Queues {
|
|||
&mut self.std_queues[idx]
|
||||
}
|
||||
|
||||
fn get_rt_queue(&self, signum: SigNum) -> &VecDeque<Box<dyn Signal>> {
|
||||
debug_assert!(signum.is_real_time());
|
||||
let idx = (signum.as_u8() - MIN_RT_SIG_NUM) as usize;
|
||||
&self.rt_queues[idx]
|
||||
}
|
||||
|
||||
fn get_rt_queue_mut(&mut self, signum: SigNum) -> &mut VecDeque<Box<dyn Signal>> {
|
||||
debug_assert!(signum.is_real_time());
|
||||
let idx = (signum.as_u8() - MIN_RT_SIG_NUM) as usize;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
sig_action::SigAction,
|
||||
sig_mask::SigSet,
|
||||
sig_num::SigNum,
|
||||
HandlePendingSignal,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -49,7 +50,10 @@ pub fn sys_rt_sigaction(
|
|||
let sig_action_c = ctx.user_space().read_val::<sigaction_t>(sig_action_addr)?;
|
||||
let sig_action = SigAction::from(sig_action_c);
|
||||
trace!("sig action = {:?}", sig_action);
|
||||
discard_signals_if_ignored(ctx, sig_num, &sig_action);
|
||||
if sig_action.will_ignore(sig_num) {
|
||||
discard_signals_if_ignored(ctx, sig_num);
|
||||
}
|
||||
|
||||
sig_dispositions.set(sig_num, sig_action)?
|
||||
} else {
|
||||
sig_dispositions.get(sig_num)
|
||||
|
|
@ -77,11 +81,7 @@ pub fn sys_rt_sigaction(
|
|||
// pending and whose default action is to ignore the signal
|
||||
// (for example, SIGCHLD), shall cause the pending signal to
|
||||
// be discarded, whether or not it is blocked
|
||||
fn discard_signals_if_ignored(ctx: &Context, signum: SigNum, sig_action: &SigAction) {
|
||||
if !sig_action.will_ignore(signum) {
|
||||
return;
|
||||
}
|
||||
|
||||
fn discard_signals_if_ignored(ctx: &Context, signum: SigNum) {
|
||||
let mask = SigSet::new_full() - signum;
|
||||
|
||||
for task in ctx.process.tasks().lock().as_slice() {
|
||||
|
|
@ -89,6 +89,6 @@ fn discard_signals_if_ignored(ctx: &Context, signum: SigNum, sig_action: &SigAct
|
|||
continue;
|
||||
};
|
||||
|
||||
posix_thread.dequeue_signal(&mask);
|
||||
while posix_thread.dequeue_signal(&mask).is_some() {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
use core::sync::atomic::Ordering;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::prelude::*;
|
||||
use crate::{prelude::*, process::signal::HandlePendingSignal};
|
||||
|
||||
pub fn sys_rt_sigpending(
|
||||
u_set_ptr: Vaddr,
|
||||
|
|
@ -24,7 +24,7 @@ pub fn sys_rt_sigpending(
|
|||
fn do_rt_sigpending(set_ptr: Vaddr, ctx: &Context) -> Result<()> {
|
||||
let combined_signals = {
|
||||
let sig_mask_value = ctx.posix_thread.sig_mask().load(Ordering::Relaxed);
|
||||
let sig_pending_value = ctx.posix_thread.sig_pending();
|
||||
let sig_pending_value = ctx.pending_signals();
|
||||
sig_mask_value & sig_pending_value
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use crate::{
|
|||
prelude::*,
|
||||
process::{
|
||||
posix_thread::{AsPosixThread, AsThreadLocal, ThreadLocal},
|
||||
signal::handle_pending_signal,
|
||||
signal::{handle_pending_signal, HandlePendingSignal},
|
||||
},
|
||||
syscall::handle_syscall,
|
||||
thread::{exception::handle_exception, AsThread},
|
||||
|
|
@ -61,8 +61,6 @@ pub fn create_new_user_task(
|
|||
let _ = current_userspace!().write_val(child_tid_ptr, ¤t_posix_thread.tid());
|
||||
}
|
||||
|
||||
let has_kernel_event_fn = || current_posix_thread.has_pending();
|
||||
|
||||
let ctx = Context {
|
||||
process: current_process,
|
||||
thread_local: current_thread_local,
|
||||
|
|
@ -71,6 +69,8 @@ pub fn create_new_user_task(
|
|||
task: ¤t_task,
|
||||
};
|
||||
|
||||
let has_kernel_event_fn = || ctx.has_pending();
|
||||
|
||||
if is_init_process {
|
||||
crate::init_in_first_process(&ctx);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue