use ax_errno::{AxError, AxResult};
use bitflags::bitflags;
use linux_raw_sys::general::{O_CLOEXEC, O_NONBLOCK};
use starry_signal::SignalSet;
use starry_vm::VmPtr;
use crate::{
file::{FileLike, add_file_like, signalfd::Signalfd},
syscall::signal::check_sigset_size,
};
const SFD_CLOEXEC: u32 = O_CLOEXEC;
const SFD_NONBLOCK: u32 = O_NONBLOCK;
bitflags! {
#[derive(Debug, Clone, Copy, Default)]
pub struct SignalfdFlags: u32 {
const CLOEXEC = SFD_CLOEXEC;
const NONBLOCK = SFD_NONBLOCK;
}
}
pub fn sys_signalfd4(
fd: i32,
mask: *const SignalSet,
sigsetsize: usize,
flags: u32,
) -> AxResult<isize> {
check_sigset_size(sigsetsize)?;
let flags = SignalfdFlags::from_bits(flags).ok_or(AxError::InvalidInput)?;
let mask = unsafe { mask.vm_read_uninit()?.assume_init() };
if fd != -1 {
let signalfd = Signalfd::from_fd(fd)?;
signalfd.update_mask(mask);
return Ok(fd as _);
}
let signalfd = Signalfd::new(mask);
signalfd.set_nonblocking(flags.contains(SignalfdFlags::NONBLOCK))?;
add_file_like(signalfd as _, flags.contains(SignalfdFlags::CLOEXEC)).map(|fd| fd as _)
}
#[cfg(axtest)]
pub(crate) fn signalfd_flags_validation_rules_hold_for_test() -> bool {
use linux_raw_sys::general::{O_CLOEXEC, O_NONBLOCK};
let valid_flags = 0u32;
assert!(SignalfdFlags::from_bits(valid_flags).is_some());
let cloexec_only = O_CLOEXEC as u32;
assert!(SignalfdFlags::from_bits(cloexec_only).is_some());
let nonblock_only = O_NONBLOCK as u32;
assert!(SignalfdFlags::from_bits(nonblock_only).is_some());
let all_valid = O_CLOEXEC as u32 | O_NONBLOCK as u32;
assert!(SignalfdFlags::from_bits(all_valid).is_some());
let invalid_flags = 0xFFFF;
assert!(SignalfdFlags::from_bits(invalid_flags).is_none());
true
}