use alloc::sync::Arc;
use core::task::Poll;
use axpoll::IoEvents;
use axpoll_set::PollSet;
use starry_signal::Signo;
use super::{PidRoleLease, ProcessData, Tid, TidNumber, future};
use crate::sync::{IrqMutex, Mutex};
struct RetiredLeader {
nice: i32,
tid_lease: PidRoleLease<Tid>,
}
pub(super) struct ProcessWaitState {
child_exit_event: Arc<PollSet>,
exit_event: Arc<PollSet>,
thread_exit_event: Arc<PollSet>,
exec_lock: Mutex<()>,
exit_signal: Option<Signo>,
wait_parent_tid: TidNumber,
retired_leader: IrqMutex<Option<RetiredLeader>>,
}
impl ProcessWaitState {
pub(super) fn new(exit_signal: Option<Signo>, wait_parent_tid: TidNumber) -> Self {
Self {
child_exit_event: Arc::default(),
exit_event: Arc::default(),
thread_exit_event: Arc::default(),
exec_lock: Mutex::new(()),
exit_signal,
wait_parent_tid,
retired_leader: IrqMutex::new(None),
}
}
pub(super) fn exit_event_arc(&self) -> Arc<PollSet> {
self.exit_event.clone()
}
}
pub async fn wait_on_pollset<T>(poll: &PollSet, mut check: impl FnMut() -> Option<T>) -> T {
future::poll_shared(
|| check().map_or(Poll::Pending, Poll::Ready),
|registrar| unsafe { registrar.register(poll, IoEvents::IN) },
)
.await
}
impl ProcessData {
pub fn child_exit_event(&self) -> &PollSet {
&self.wait.child_exit_event
}
pub fn exit_event(&self) -> &PollSet {
&self.wait.exit_event
}
pub fn thread_exit_event(&self) -> &PollSet {
&self.wait.thread_exit_event
}
pub fn exec_lock(&self) -> &Mutex<()> {
&self.wait.exec_lock
}
pub fn exit_signal(&self) -> Option<Signo> {
self.wait.exit_signal
}
pub fn wait_parent_tid(&self) -> TidNumber {
self.wait.wait_parent_tid
}
pub(crate) fn retire_leader(&self, nice: i32, tid_lease: PidRoleLease<Tid>) {
let previous = self
.wait
.retired_leader
.lock()
.replace(RetiredLeader { nice, tid_lease });
assert!(previous.is_none(), "process retired its leader twice");
}
pub(crate) fn retired_leader_transfer_ready(&self) -> bool {
self.wait
.retired_leader
.lock()
.as_ref()
.is_some_and(|leader| leader.tid_lease.task_transfer_ready())
}
pub fn retired_leader_nice(&self) -> Option<i32> {
self.wait
.retired_leader
.lock()
.as_ref()
.map(|leader| leader.nice)
}
pub(crate) fn take_retired_leader_for_zombie(&self) -> (i32, PidRoleLease<Tid>) {
let leader = self
.wait
.retired_leader
.lock()
.take()
.expect("process lost its retired leader state");
(leader.nice, leader.tid_lease)
}
pub(crate) fn take_retired_leader_for_exec(&self) -> (i32, PidRoleLease<Tid>) {
let leader = self
.wait
.retired_leader
.lock()
.take()
.expect("process lost its retired leader state");
assert!(
leader.tid_lease.task_transfer_ready(),
"exec transferred a leader identity before its exit path completed"
);
(leader.nice, leader.tid_lease)
}
pub fn is_clone_child(&self) -> bool {
self.wait.exit_signal != Some(Signo::SIGCHLD)
}
}