1use core::{fmt::Debug, time::Duration};
50
51use alloc::vec;
52use alloc::vec::Vec;
53
54use crate::{
55 clock::AsTimeval,
56 file_descriptor::{FileDescriptor, FileDescriptorBased},
57};
58use iceoryx2_bb_concurrency::cell::UnsafeCell;
59use iceoryx2_log::fail;
60use iceoryx2_pal_posix::posix::{errno::Errno, MemZeroedStruct};
61use iceoryx2_pal_posix::*;
62
63pub trait SynchronousMultiplexing: FileDescriptorBased {}
65
66#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
67pub enum FileDescriptorSetWaitError {
68 Interrupt,
69 TooManyAttachedFileDescriptors,
70 InsufficientPermissions,
71 UnknownError(i32),
72}
73
74#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
75pub enum FileDescriptorSetAddError {
76 AlreadyAttached,
77 CapacityExceeded,
78}
79
80#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
83pub enum FileEvent {
84 Read,
85 Write,
86 Exceptional,
87 ReadWrite,
88 ReadExceptional,
89 WriteExceptional,
90 ReadWriteExceptional,
91}
92
93pub struct FileDescriptorSetGuard<'set, 'fd> {
94 set: &'set FileDescriptorSet,
95 fd: &'fd FileDescriptor,
96}
97
98impl<'fd> FileDescriptorSetGuard<'_, 'fd> {
99 pub fn file_descriptor(&self) -> &'fd FileDescriptor {
100 self.fd
101 }
102}
103
104impl Drop for FileDescriptorSetGuard<'_, '_> {
105 fn drop(&mut self) {
106 self.set.remove(unsafe { self.fd.native_handle() })
107 }
108}
109
110pub struct FileDescriptorSet {
113 internals: UnsafeCell<Internals>,
114}
115
116struct Internals {
117 fd_set: posix::fd_set,
118 file_descriptors: Vec<i32>,
119 max_fd: i32,
120}
121
122impl Debug for FileDescriptorSet {
123 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124 write!(
125 f,
126 "FileDescriptorSet {{ file_descriptors: {:?}, max_fd: {} }}",
127 self.internals().file_descriptors,
128 self.internals().max_fd
129 )
130 }
131}
132
133impl Default for FileDescriptorSet {
134 fn default() -> Self {
135 let fd_set = FileDescriptorSet {
136 internals: UnsafeCell::new(Internals {
137 fd_set: posix::fd_set::new_zeroed(),
138 file_descriptors: vec![],
139 max_fd: 0,
140 }),
141 };
142
143 unsafe { posix::FD_ZERO(&mut fd_set.internals_mut().fd_set) };
144
145 fd_set
146 }
147}
148
149impl FileDescriptorSet {
150 fn internals(&self) -> &Internals {
151 unsafe { &*self.internals.get() }
152 }
153
154 #[allow(clippy::mut_from_ref)]
155 fn internals_mut(&self) -> &mut Internals {
156 unsafe { &mut *self.internals.get() }
157 }
158
159 pub fn new() -> FileDescriptorSet {
160 FileDescriptorSet::default()
161 }
162
163 pub fn add<'set, 'fd, F: SynchronousMultiplexing>(
165 &'set self,
166 fd: &'fd F,
167 ) -> Result<FileDescriptorSetGuard<'set, 'fd>, FileDescriptorSetAddError> {
168 self.add_impl(fd.file_descriptor())
169 }
170
171 fn add_impl<'set, 'fd>(
172 &'set self,
173 fd: &'fd FileDescriptor,
174 ) -> Result<FileDescriptorSetGuard<'set, 'fd>, FileDescriptorSetAddError> {
175 let msg = "Unable to add file descriptor";
176 if self.internals().file_descriptors.len() >= Self::capacity() {
177 fail!(from self, with FileDescriptorSetAddError::CapacityExceeded,
178 "{msg} {:?} since the amount of file descriptors {} exceeds the maximum supported amount of file descriptors for a set {}.",
179 fd.file_descriptor(), self.internals().file_descriptors.len(), Self::capacity());
180 }
181
182 if self.contains_impl(fd) {
183 fail!(from self, with FileDescriptorSetAddError::AlreadyAttached,
184 "{msg} {:?} since it is already attached.", fd);
185 }
186
187 unsafe {
188 posix::FD_SET(
189 fd.file_descriptor().native_handle(),
190 &mut self.internals_mut().fd_set,
191 )
192 };
193 self.internals_mut().max_fd = core::cmp::max(
194 self.internals().max_fd,
195 unsafe { fd.file_descriptor().native_handle() } + 1,
196 );
197 self.internals_mut()
198 .file_descriptors
199 .push(unsafe { fd.file_descriptor().native_handle() });
200
201 Ok(FileDescriptorSetGuard { set: self, fd })
202 }
203
204 fn remove(&self, value: i32) {
205 unsafe { posix::FD_CLR(value, &mut self.internals_mut().fd_set) };
206
207 if self.internals_mut().max_fd == value + 1 {
208 self.internals_mut().max_fd = 0;
209 for fd in &self.internals().file_descriptors {
210 self.internals_mut().max_fd = core::cmp::max(self.internals().max_fd, fd + 1);
211 }
212 }
213
214 self.internals_mut()
215 .file_descriptors
216 .retain(|&v| value != v);
217 }
218
219 pub const fn capacity() -> usize {
221 posix::FD_SETSIZE
222 }
223
224 pub fn len(&self) -> usize {
226 self.internals().file_descriptors.len()
227 }
228
229 pub fn is_empty(&self) -> bool {
231 self.internals().file_descriptors.is_empty()
232 }
233
234 pub fn contains<T: SynchronousMultiplexing>(&self, fd: &T) -> bool {
236 self.contains_impl(fd.file_descriptor())
237 }
238
239 fn contains_impl(&self, fd: &FileDescriptor) -> bool {
240 unsafe { posix::FD_ISSET(fd.native_handle(), &self.internals().fd_set) }
241 }
242
243 pub fn blocking_wait<F: FnMut(&FileDescriptor)>(
246 &self,
247 event: FileEvent,
248 fd_callback: F,
249 ) -> Result<usize, FileDescriptorSetWaitError> {
250 self.wait(core::ptr::null_mut(), event, fd_callback)
251 }
252
253 pub fn timed_wait<F: FnMut(&FileDescriptor)>(
256 &self,
257 timeout: Duration,
258 event: FileEvent,
259 fd_callback: F,
260 ) -> Result<usize, FileDescriptorSetWaitError> {
261 let mut raw_timeout = timeout.as_timeval();
262 self.wait(&mut raw_timeout, event, fd_callback)
263 }
264
265 fn wait<F: FnMut(&FileDescriptor)>(
266 &self,
267 timeout: *mut posix::timeval,
268 event: FileEvent,
269 mut fd_callback: F,
270 ) -> Result<usize, FileDescriptorSetWaitError> {
271 let mut fd_set: posix::fd_set = self.internals().fd_set;
272
273 let read_fd: *mut posix::fd_set = match event {
274 FileEvent::Read
275 | FileEvent::ReadWrite
276 | FileEvent::ReadExceptional
277 | FileEvent::ReadWriteExceptional => &mut fd_set,
278 _ => core::ptr::null_mut::<posix::fd_set>(),
279 };
280 let write_fd: *mut posix::fd_set = match event {
281 FileEvent::Write
282 | FileEvent::ReadWrite
283 | FileEvent::WriteExceptional
284 | FileEvent::ReadWriteExceptional => &mut fd_set,
285 _ => core::ptr::null_mut::<posix::fd_set>(),
286 };
287 let exceptional_fd: *mut posix::fd_set = match event {
288 FileEvent::Exceptional
289 | FileEvent::ReadExceptional
290 | FileEvent::WriteExceptional
291 | FileEvent::ReadWriteExceptional => &mut fd_set,
292 _ => core::ptr::null_mut::<posix::fd_set>(),
293 };
294
295 let msg = "Failure while waiting for file descriptor events";
296 let number_of_notifications = unsafe {
297 posix::select(
298 self.internals().max_fd,
299 read_fd,
300 write_fd,
301 exceptional_fd,
302 timeout,
303 )
304 };
305
306 if number_of_notifications == -1 {
307 handle_errno!(FileDescriptorSetWaitError, from self,
308 fatal Errno::EBADF => ("This should never happen! {} since at least one of the attached file descriptors is invalid.", msg),
309 Errno::EINTR => (Interrupt, "{} since an interrupt signal was received.", msg),
310 Errno::EINVAL => (TooManyAttachedFileDescriptors,
311 "{} since the number of attached file descriptors exceed the system limit of ({}).",
312 msg, Self::capacity()),
313 Errno::EPERM => (InsufficientPermissions, "{} due to insufficient permissions.", msg),
314 v => (UnknownError(v as i32), "{} since an unknown error occurred ({}).", msg, v)
315 );
316 }
317
318 for raw_fd in &self.internals().file_descriptors {
319 if unsafe { posix::FD_ISSET(*raw_fd, &fd_set) } {
320 let fd = FileDescriptor::non_owning_new(*raw_fd).unwrap();
321 fd_callback(&fd);
322 }
323 }
324
325 Ok(number_of_notifications as _)
326 }
327}