use std::{mem, os::fd, ptr};
use dope_sys::{Errno, kernel, thread::signal};
use o3::base::marker::ThreadBound;
use crate::{
Uring,
system::signal::{Acquire, Source, Wait},
};
#[derive(Debug)]
pub struct Receiver {
fd: fd::OwnedFd,
previous: mem::MaybeUninit<libc::sigset_t>,
_thread: ThreadBound,
}
impl Receiver {
fn mask() -> libc::sigset_t {
let mut mask = mem::MaybeUninit::<libc::sigset_t>::zeroed();
unsafe { libc::sigemptyset(mask.as_mut_ptr()) };
unsafe { libc::sigaddset(mask.as_mut_ptr(), libc::SIGTERM) };
unsafe { mask.assume_init() }
}
}
impl fd::AsFd for Receiver {
fn as_fd(&self) -> fd::BorrowedFd<'_> {
self.fd.as_fd()
}
}
const _: () = {
assert!(mem::size_of::<Option<Receiver>>() == mem::size_of::<Receiver>());
};
impl signal::raw::Receiver for Receiver {
type Acquire = Acquire;
type Wait = Wait;
type Source<'a> = Source<'a>;
unsafe fn try_new() -> Result<Self, Acquire> {
use std::os::fd::OwnedFd;
use dope_sys::io::fd;
let mask = Self::mask();
let raw = unsafe { libc::signalfd(-1, &mask, libc::SFD_CLOEXEC | libc::SFD_NONBLOCK) };
let fd = unsafe {
<OwnedFd as fd::raw::Adopt>::try_adopt::<Errno>(raw, || {
kernel::raw::Code::last::<Uring>().into()
})
}
.map_err(Acquire::SignalFd)?;
let mut previous = mem::MaybeUninit::<libc::sigset_t>::uninit();
let result =
unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, &mask, previous.as_mut_ptr()) };
unsafe { kernel::raw::Status::new(result).try_pthread() }.map_err(Acquire::MaskBlock)?;
Ok(Self {
fd,
previous,
_thread: ThreadBound::NEW,
})
}
fn source(&self) -> Self::Source<'_> {
Source::new(self)
}
fn restore(&self) -> Result<(), signal::ReleaseFault> {
let result = unsafe {
libc::pthread_sigmask(libc::SIG_SETMASK, self.previous.as_ptr(), ptr::null_mut())
};
unsafe { kernel::raw::Status::new(result).try_pthread() }
.map_err(signal::ReleaseFault::Mask)
}
}