starnix_core/vfs/
pidfd.rs1use crate::mm::MemoryManager;
6use crate::task::{
7 CurrentTask, EventHandler, SignalHandler, SignalHandlerInner, ThreadGroup, ThreadGroupKey,
8 WaitCanceler, Waiter,
9};
10use crate::vfs::{
11 Anon, FileHandle, FileObject, FileOps, fileops_impl_dataless, fileops_impl_nonseekable,
12 fileops_impl_noop_sync,
13};
14use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
15use starnix_uapi::error;
16use starnix_uapi::errors::Errno;
17use starnix_uapi::open_flags::OpenFlags;
18use starnix_uapi::vfs::FdEvents;
19
20pub struct PidFdFileObject {
21 tg: ThreadGroupKey,
23
24 terminated_event: zx::EventPair,
26}
27
28impl PidFdFileObject {
29 fn get_signals_from_events(events: FdEvents) -> zx::Signals {
30 if events.contains(FdEvents::POLLIN) {
31 zx::Signals::EVENTPAIR_PEER_CLOSED
32 } else {
33 zx::Signals::NONE
34 }
35 }
36
37 fn get_events_from_signals(signals: zx::Signals) -> FdEvents {
38 let mut events = FdEvents::empty();
39
40 if signals.contains(zx::Signals::EVENTPAIR_PEER_CLOSED) {
41 events |= FdEvents::POLLIN;
42 }
43
44 events
45 }
46}
47
48pub fn new_pidfd<L>(
49 locked: &mut Locked<L>,
50 current_task: &CurrentTask,
51 proc: &ThreadGroup,
52 mm: &MemoryManager,
53 flags: OpenFlags,
54) -> FileHandle
55where
56 L: LockEqualOrBefore<FileOpsCore>,
57{
58 let terminated_event = mm.drop_notifier.event();
67
68 Anon::new_private_file(
69 locked,
70 current_task,
71 Box::new(PidFdFileObject { tg: proc.into(), terminated_event }),
72 flags,
73 "[pidfd]",
74 )
75}
76
77impl FileOps for PidFdFileObject {
78 fileops_impl_nonseekable!();
79 fileops_impl_dataless!();
80 fileops_impl_noop_sync!();
81
82 fn as_thread_group_key(&self, _file: &FileObject) -> Result<ThreadGroupKey, Errno> {
83 Ok(self.tg.clone())
84 }
85
86 fn wait_async(
87 &self,
88 _locked: &mut Locked<FileOpsCore>,
89 _file: &FileObject,
90 _current_task: &CurrentTask,
91 waiter: &Waiter,
92 events: FdEvents,
93 handler: EventHandler,
94 ) -> Option<WaitCanceler> {
95 let signal_handler = SignalHandler {
96 inner: SignalHandlerInner::ZxHandle(PidFdFileObject::get_events_from_signals),
97 event_handler: handler,
98 err_code: None,
99 };
100 let canceler = waiter
101 .wake_on_zircon_signals(
102 &self.terminated_event,
103 PidFdFileObject::get_signals_from_events(events),
104 signal_handler,
105 )
106 .unwrap(); Some(WaitCanceler::new_port(canceler))
108 }
109
110 fn query_events(
111 &self,
112 _locked: &mut Locked<FileOpsCore>,
113 _file: &FileObject,
114 _current_task: &CurrentTask,
115 ) -> Result<FdEvents, Errno> {
116 match self
117 .terminated_event
118 .wait_one(zx::Signals::EVENTPAIR_PEER_CLOSED, zx::MonotonicInstant::ZERO)
119 .to_result()
120 {
121 Err(zx::Status::TIMED_OUT) => Ok(FdEvents::empty()),
122 Ok(zx::Signals::EVENTPAIR_PEER_CLOSED) => Ok(FdEvents::POLLIN),
123 result => unreachable!("unexpected result: {result:?}"),
124 }
125 }
126}
127
128pub fn new_zombie_pidfd<L>(
129 locked: &mut Locked<L>,
130 current_task: &CurrentTask,
131 flags: OpenFlags,
132) -> FileHandle
133where
134 L: LockEqualOrBefore<FileOpsCore>,
135{
136 Anon::new_private_file(
137 locked,
138 current_task,
139 Box::new(ZombiePidFdFileObject {}),
140 flags,
141 "[pidfd]",
142 )
143}
144
145struct ZombiePidFdFileObject {}
146
147impl FileOps for ZombiePidFdFileObject {
148 fileops_impl_nonseekable!();
149 fileops_impl_dataless!();
150 fileops_impl_noop_sync!();
151
152 fn as_thread_group_key(&self, _file: &FileObject) -> Result<ThreadGroupKey, Errno> {
153 error!(EINVAL)
155 }
156
157 fn wait_async(
158 &self,
159 _locked: &mut Locked<FileOpsCore>,
160 _file: &FileObject,
161 _current_task: &CurrentTask,
162 _waiter: &Waiter,
163 _events: FdEvents,
164 _handler: EventHandler,
165 ) -> Option<WaitCanceler> {
166 None
168 }
169
170 fn query_events(
171 &self,
172 _locked: &mut Locked<FileOpsCore>,
173 _file: &FileObject,
174 _current_task: &CurrentTask,
175 ) -> Result<FdEvents, Errno> {
176 Ok(FdEvents::POLLIN)
177 }
178}