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