use super::{Kernel, RunState, err};
use crate::abi::errno::Errno;
use crate::vcpu::GuestMemory;
const SIG_DFL: u64 = 0;
const SIG_IGN: u64 = 1;
const NSIG: u64 = 64;
const SIGKILL: u64 = 9;
const SIGSTOP: u64 = 19;
impl Kernel {
pub(super) fn sys_rt_sigaction(
&mut self,
sig: u64,
act: u64,
oldact: u64,
mem: &mut GuestMemory,
) -> i64 {
if !(1..=NSIG).contains(&sig) {
return err(Errno::EINVAL);
}
if act != 0 && (sig == SIGKILL || sig == SIGSTOP) {
return err(Errno::EINVAL);
}
let idx = sig as usize;
if oldact != 0 {
let mut buf = [0u8; 32];
buf[0..8].copy_from_slice(&self.cur.handlers[idx].to_le_bytes());
if mem.write(oldact, &buf).is_err() {
return err(Errno::EFAULT);
}
}
if act != 0 {
let Ok(handler) = mem.read_u64(act) else {
return err(Errno::EFAULT);
};
self.cur.handlers[idx] = handler;
}
0
}
pub(super) fn sys_rt_sigprocmask(
&mut self,
how: u64,
set: u64,
oldset: u64,
mem: &mut GuestMemory,
) -> i64 {
const SIG_BLOCK: u64 = 0;
const SIG_UNBLOCK: u64 = 1;
const SIG_SETMASK: u64 = 2;
if oldset != 0 && mem.write(oldset, &self.cur.blocked.to_le_bytes()).is_err() {
return err(Errno::EFAULT);
}
if set != 0 {
let Ok(mask) = mem.read_u64(set) else {
return err(Errno::EFAULT);
};
match how {
SIG_BLOCK => self.cur.blocked |= mask,
SIG_UNBLOCK => self.cur.blocked &= !mask,
SIG_SETMASK => self.cur.blocked = mask,
_ => return err(Errno::EINVAL),
}
}
0
}
pub(super) fn sys_rt_sigpending(&mut self, set: u64, mem: &mut GuestMemory) -> i64 {
if set != 0 && mem.write(set, &self.cur.pending.to_le_bytes()).is_err() {
return err(Errno::EFAULT);
}
0
}
pub(super) fn sys_kill(&mut self, pid: i64, sig: u64) -> i64 {
if sig == 0 {
return if pid <= 0 || self.pid_exists(pid) {
0
} else {
err(Errno::ESRCH)
};
}
if sig > NSIG {
return err(Errno::EINVAL);
}
let bit = 1u64 << (sig - 1);
if pid <= 0 || pid == i64::from(self.cur.pid) {
self.cur.pending |= bit;
return 0;
}
for slot in self.procs.iter_mut().flatten() {
if i64::from(slot.info.pid) == pid {
slot.info.pending |= bit;
return 0;
}
}
err(Errno::ESRCH)
}
fn pid_exists(&self, pid: i64) -> bool {
pid == i64::from(self.cur.pid)
|| self
.procs
.iter()
.flatten()
.any(|p| i64::from(p.info.pid) == pid)
}
pub(super) fn deliver_pending_signals(&mut self) {
if !matches!(self.cur.run, RunState::Running) {
return;
}
let deliverable = self.cur.pending & !self.cur.blocked;
if deliverable == 0 {
return;
}
for sig in 1..=NSIG {
let bit = 1u64 << (sig - 1);
if deliverable & bit == 0 {
continue;
}
self.cur.pending &= !bit;
match self.cur.handlers[sig as usize] {
SIG_IGN => {}
h if h != SIG_DFL => {}
_ if is_default_ignored(sig) => {}
_ => {
self.cur.run = RunState::Zombie(128 + sig as i32);
return;
}
}
}
}
}
fn is_default_ignored(sig: u64) -> bool {
const SIGCHLD: u64 = 17;
const SIGCONT: u64 = 18;
const SIGURG: u64 = 23;
const SIGWINCH: u64 = 28;
matches!(sig, SIGCHLD | SIGCONT | SIGURG | SIGWINCH)
}