#![no_std]
#![deny(warnings, missing_docs)]
extern crate alloc;
use alloc::boxed::Box;
use tg_kernel_context::LocalContext;
use tg_signal::{Signal, SignalAction, SignalNo, SignalResult, MAX_SIG};
mod default_action;
use default_action::DefaultAction;
mod signal_set;
use signal_set::SignalSet;
pub enum HandlingSignal {
Frozen,
UserSignal(LocalContext),
}
pub struct SignalImpl {
received: SignalSet,
mask: SignalSet,
handling: Option<HandlingSignal>,
actions: [Option<SignalAction>; MAX_SIG + 1],
}
impl SignalImpl {
pub fn new() -> Self {
Self {
received: SignalSet::empty(),
mask: SignalSet::empty(),
handling: None,
actions: [None; MAX_SIG + 1],
}
}
}
impl Default for SignalImpl {
fn default() -> Self {
Self::new()
}
}
impl SignalImpl {
fn fetch_signal(&mut self) -> Option<SignalNo> {
self.received.find_first_one(self.mask).map(|num| {
self.received.remove_bit(num);
num.into()
})
}
fn fetch_and_remove(&mut self, signal_no: SignalNo) -> bool {
if self.received.contain_bit(signal_no as usize)
&& !self.mask.contain_bit(signal_no as usize)
{
self.received.remove_bit(signal_no as usize);
true
} else {
false
}
}
}
impl Signal for SignalImpl {
fn from_fork(&mut self) -> Box<dyn Signal> {
Box::new(Self {
received: SignalSet::empty(),
mask: self.mask,
handling: None,
actions: {
let mut actions = [None; MAX_SIG + 1];
actions.copy_from_slice(&self.actions);
actions
},
})
}
fn clear(&mut self) {
for action in &mut self.actions {
action.take();
}
}
fn add_signal(&mut self, signal: SignalNo) {
self.received.add_bit(signal as usize)
}
fn is_handling_signal(&self) -> bool {
self.handling.is_some()
}
fn set_action(&mut self, signum: SignalNo, action: &SignalAction) -> bool {
if signum == SignalNo::SIGKILL || signum == SignalNo::SIGSTOP {
false
} else {
self.actions[signum as usize] = Some(*action);
true
}
}
fn get_action_ref(&self, signum: SignalNo) -> Option<SignalAction> {
if signum == SignalNo::SIGKILL || signum == SignalNo::SIGSTOP {
None
} else {
Some(self.actions[signum as usize].unwrap_or(SignalAction::default()))
}
}
fn update_mask(&mut self, mask: usize) -> usize {
self.mask.set_new(mask.into())
}
fn handle_signals(&mut self, current_context: &mut LocalContext) -> SignalResult {
if self.is_handling_signal() {
match self.handling.as_ref().unwrap() {
HandlingSignal::Frozen => {
if self.fetch_and_remove(SignalNo::SIGCONT) {
self.handling.take();
SignalResult::Handled
} else {
SignalResult::ProcessSuspended
}
} _ => SignalResult::IsHandlingSignal,
}
} else if let Some(signal) = self.fetch_signal() {
match signal {
SignalNo::SIGKILL => SignalResult::ProcessKilled(-(signal as i32)),
SignalNo::SIGSTOP => {
self.handling = Some(HandlingSignal::Frozen);
SignalResult::ProcessSuspended
}
_ => {
if let Some(action) = self.actions[signal as usize] {
self.handling = Some(HandlingSignal::UserSignal(current_context.clone()));
*current_context.pc_mut() = action.handler;
*current_context.a_mut(0) = signal as usize;
SignalResult::Handled
} else {
DefaultAction::from(signal).into()
}
}
}
} else {
SignalResult::NoSignal
}
}
fn sig_return(&mut self, current_context: &mut LocalContext) -> bool {
let handling_signal = self.handling.take();
match handling_signal {
Some(HandlingSignal::UserSignal(old_ctx)) => {
*current_context = old_ctx;
true
}
_ => {
self.handling = handling_signal;
false
}
}
}
}