use alloc::{
borrow::Cow,
sync::{Arc, Weak},
};
use core::{
sync::atomic::{AtomicBool, Ordering},
task::Context,
};
use ax_errno::{AxError, AxResult};
use axpoll::{IoEvents, PollSet, Pollable};
use crate::{
file::FileLike,
task::{ProcessData, Thread},
};
pub struct PidFd {
proc_data: Weak<ProcessData>,
exit_event: Arc<PollSet>,
thread_exit: Option<Arc<AtomicBool>>,
non_blocking: AtomicBool,
}
impl PidFd {
pub fn new_process(proc_data: &Arc<ProcessData>) -> Self {
Self {
proc_data: Arc::downgrade(proc_data),
exit_event: proc_data.exit_event.clone(),
thread_exit: None,
non_blocking: AtomicBool::new(false),
}
}
pub fn new_thread(thread: &Thread) -> Self {
Self {
proc_data: Arc::downgrade(&thread.proc_data),
exit_event: thread.exit_event.clone(),
thread_exit: Some(thread.exit.clone()),
non_blocking: AtomicBool::new(false),
}
}
pub fn process_data(&self) -> AxResult<Arc<ProcessData>> {
if let Some(thread_exit) = &self.thread_exit
&& thread_exit.load(Ordering::Acquire)
{
return Err(AxError::NoSuchProcess);
}
self.proc_data.upgrade().ok_or(AxError::NoSuchProcess)
}
}
impl FileLike for PidFd {
fn path(&self) -> Cow<'_, str> {
"anon_inode:[pidfd]".into()
}
fn set_nonblocking(&self, nonblocking: bool) -> AxResult {
self.non_blocking.store(nonblocking, Ordering::Release);
Ok(())
}
fn nonblocking(&self) -> bool {
self.non_blocking.load(Ordering::Acquire)
}
}
impl Pollable for PidFd {
fn poll(&self) -> IoEvents {
let mut events = IoEvents::empty();
events.set(
IoEvents::IN,
self.proc_data.strong_count() > 0
&& self
.thread_exit
.as_ref()
.is_none_or(|it| !it.load(Ordering::Acquire)),
);
events
}
fn register(&self, context: &mut Context<'_>, events: IoEvents) {
if events.contains(IoEvents::IN) {
self.exit_event.register(context.waker());
}
}
}