1use crate::power::WakeupSourceOrigin;
6use crate::task::{
7 CurrentTask, EventHandler, ReadyItem, ReadyItemKey, WaitCanceler, WaitQueue, Waiter,
8};
9use crate::vfs::{
10 Anon, FileHandle, FileObject, FileObjectState, FileOps, WeakFileHandle, fileops_impl_dataless,
11 fileops_impl_nonseekable, fileops_impl_noop_sync,
12};
13use rustc_hash::{FxHashMap, FxHashSet};
14use starnix_logging::log_warn;
15use starnix_sync::{EpollStateLock, EpollWaitableStateLock, LockDepMutex, allow_subclass};
16use starnix_uapi::error;
17use starnix_uapi::errors::{EINTR, ETIMEDOUT, Errno};
18use starnix_uapi::open_flags::OpenFlags;
19use starnix_uapi::vfs::{EpollEvent, FdEvents};
20use std::collections::VecDeque;
21use std::collections::hash_map::Entry;
22use std::sync::Arc;
23
24const MAX_NESTED_DEPTH: u32 = 5;
27
28struct WaitObject {
34 target: WeakFileHandle,
35 events: FdEvents,
36 data: u64,
37 wait_canceler: Option<WaitCanceler>,
38 active_wakeup_source: Option<WakeupSourceOrigin>,
39}
40
41impl WaitObject {
42 fn target(&self) -> Option<FileHandle> {
47 self.target.upgrade()
48 }
49
50 fn deactivate_wakeup_source(&mut self, current_task: &CurrentTask) {
51 if let Some(origin) = self.active_wakeup_source.take() {
52 current_task.kernel().suspend_resume_manager.deactivate_wakeup_source(&origin);
53 }
54 }
55}
56
57pub type EpollKey = usize;
60
61#[derive(Default)]
64pub struct EpollFileObject {
65 waiter: Waiter,
66 state: LockDepMutex<EpollState, EpollStateLock>,
68 waitable_state: Arc<LockDepMutex<EpollWaitableState, EpollWaitableStateLock>>,
69 waiters: Arc<WaitQueue>,
72}
73
74#[derive(Default)]
75struct EpollState {
76 wait_objects: FxHashMap<ReadyItemKey, WaitObject>,
82 processing_list: VecDeque<ReadyItem>,
90 recheck_list: Vec<ReadyItemKey>,
96}
97
98#[derive(Default)]
99struct EpollWaitableState {
100 trigger_list: VecDeque<ReadyItem>,
103}
104
105impl EpollFileObject {
106 pub fn new_file(current_task: &CurrentTask) -> FileHandle {
108 let epoll = Box::new(EpollFileObject::default());
109
110 #[cfg(any(test, debug_assertions))]
111 {
112 let _l1 = epoll.state.lock();
113 let _l2 = epoll.waitable_state.lock();
114 }
115
116 Anon::new_private_file(current_task, epoll, OpenFlags::RDWR, "[eventpoll]")
117 }
118
119 fn wait_on_file(
120 &self,
121 current_task: &CurrentTask,
122 key: ReadyItemKey,
123 wait_object: &mut WaitObject,
124 ) -> Result<(), Errno> {
125 self.wait_on_file_edge_triggered(current_task, key, wait_object)?;
127
128 self.do_recheck(current_task, wait_object, key)?;
129
130 Ok(())
131 }
132
133 fn do_recheck(
134 &self,
135 current_task: &CurrentTask,
136 wait_object: &mut WaitObject,
137 key: ReadyItemKey,
138 ) -> Result<(), Errno> {
139 let Some(target) = wait_object.target() else { return Ok(()) };
140 let events = {
141 let _token = allow_subclass();
144 target.query_events(current_task)?
145 };
146 if !(events & wait_object.events).is_empty() {
147 self.waiter.wake_immediately(events, self.new_wait_handler(key));
148 if let Some(wait_canceler) = wait_object.wait_canceler.take() {
149 wait_canceler.cancel();
150 } else {
151 log_warn!("wait canceler should have been set by `wait_on_file_edge_triggered`");
152 }
153 }
154 Ok(())
155 }
156
157 fn wait_on_file_edge_triggered(
158 &self,
159 current_task: &CurrentTask,
160 key: ReadyItemKey,
161 wait_object: &mut WaitObject,
162 ) -> Result<(), Errno> {
163 let Some(target) = wait_object.target() else {
164 return Ok(());
165 };
166
167 wait_object.wait_canceler = target.wait_async(
168 current_task,
169 &self.waiter,
170 wait_object.events,
171 self.new_wait_handler(key),
172 );
173 if wait_object.wait_canceler.is_none() {
174 return error!(EPERM);
175 }
176 Ok(())
177 }
178
179 fn check_eloop(&self, parent: &FileHandle, depth_left: u32) -> Result<(), Errno> {
182 if depth_left == 0 {
183 return error!(ELOOP);
184 }
185
186 let state = self.state.lock();
187 for nested_object in state.wait_objects.values() {
188 let Some(child) = nested_object.target() else {
189 continue;
190 };
191 let Some(child_file) = child.downcast_file::<EpollFileObject>() else {
192 continue;
193 };
194
195 if Arc::ptr_eq(&child, parent) {
196 return error!(ELOOP);
197 }
198 let _token = allow_subclass();
200 child_file.check_eloop(parent, depth_left - 1)?;
201 }
202
203 Ok(())
204 }
205
206 pub fn add(
208 &self,
209 current_task: &CurrentTask,
210 file: &FileHandle,
211 epoll_file_handle: &FileHandle,
212 epoll_event: EpollEvent,
213 ) -> Result<(), Errno> {
214 if let Some(epoll_to_add) = file.downcast_file::<EpollFileObject>() {
216 epoll_to_add.check_eloop(epoll_file_handle, MAX_NESTED_DEPTH - 1)?;
219 }
220
221 let mut state = self.state.lock();
222 let key = file.id.as_epoll_key().into();
223 match state.wait_objects.entry(key) {
224 Entry::Occupied(_) => error!(EEXIST),
225 Entry::Vacant(entry) => {
226 let wait_object = entry.insert(WaitObject {
227 target: Arc::downgrade(file),
228 events: epoll_event.events() | FdEvents::POLLHUP | FdEvents::POLLERR,
229 data: epoll_event.data(),
230 wait_canceler: None,
231 active_wakeup_source: None,
232 });
233 self.wait_on_file(current_task, key, wait_object)
234 }
235 }
236 }
237
238 pub fn modify(
240 &self,
241 current_task: &CurrentTask,
242 file: &FileHandle,
243 epoll_event: EpollEvent,
244 ) -> Result<(), Errno> {
245 let mut state = self.state.lock();
246 let key = file.id.as_epoll_key();
247 state.recheck_list.retain(|x| *x != key.into());
248 let Some(wait_object) = state.wait_objects.get_mut(&key.into()) else {
249 return error!(ENOENT);
250 };
251 if let Some(wait_canceler) = wait_object.wait_canceler.take() {
252 wait_canceler.cancel();
253 }
254 wait_object.events = epoll_event.events() | FdEvents::POLLHUP | FdEvents::POLLERR;
255 wait_object.data = epoll_event.data();
256 if wait_object.events.contains(FdEvents::EPOLLWAKEUP)
260 && !epoll_event.events().contains(FdEvents::EPOLLWAKEUP)
261 {
262 wait_object.deactivate_wakeup_source(current_task);
263 }
264 self.wait_on_file(current_task, key.into(), wait_object)
265 }
266
267 pub fn delete(&self, current_task: &CurrentTask, file: &FileObject) -> Result<(), Errno> {
270 let mut state = self.state.lock();
271 let key = file.id.as_epoll_key().into();
272 if let Some(mut wait_object) = state.wait_objects.remove(&key) {
273 if let Some(wait_canceler) = wait_object.wait_canceler.take() {
274 wait_canceler.cancel();
275 }
276 state.recheck_list.retain(|x| *x != key);
277 wait_object.deactivate_wakeup_source(current_task);
279 Ok(())
280 } else {
281 error!(ENOENT)
282 }
283 }
284
285 fn process_triggered_events(
293 &self,
294 current_task: &CurrentTask,
295 pending_list: &mut Vec<ReadyItem>,
296 max_events: usize,
297 ) -> Result<(), Errno> {
298 let mut state = self.state.lock();
299 state.processing_list.append(&mut self.waitable_state.lock().trigger_list);
304 while pending_list.len() < max_events && !state.processing_list.is_empty() {
305 if let Some(pending) = state.processing_list.pop_front() {
306 if let Some(wait) = state.wait_objects.get_mut(&pending.key) {
307 if let Some(target) = wait.target.upgrade() {
311 let events = {
312 let _token = allow_subclass();
315 target.query_events(current_task)?
316 };
317 let ready = ReadyItem { key: pending.key, events };
318 if ready.events.intersects(wait.events) {
319 pending_list.push(ready);
320 } else {
321 self.wait_on_file(current_task, pending.key, wait)?;
323 }
324 }
325 }
326 }
327 }
328 Ok(())
329 }
330
331 fn wait_until_pending_event(
334 &self,
335 current_task: &CurrentTask,
336 max_events: usize,
337 mut wait_deadline: zx::MonotonicInstant,
338 ) -> Result<Vec<ReadyItem>, Errno> {
339 let mut pending_list = Vec::new();
340
341 loop {
342 self.process_triggered_events(current_task, &mut pending_list, max_events)?;
343
344 if pending_list.len() == max_events {
345 break; }
347
348 if !pending_list.is_empty() {
349 wait_deadline = zx::MonotonicInstant::ZERO;
353 }
354
355 match self.waiter.wait_until(current_task, wait_deadline) {
369 Err(err) if err == ETIMEDOUT => break,
370 Err(err) if err == EINTR => {
371 debug_assert!(
376 pending_list.is_empty(),
377 "Got EINTR from wait of {}ns with {} items pending.",
378 wait_deadline.into_nanos(),
379 pending_list.len()
380 );
381 return Err(err);
382 }
383 result => result?,
385 }
386 }
387
388 Ok(pending_list)
389 }
390
391 pub fn wait(
393 &self,
394 current_task: &CurrentTask,
395 max_events: usize,
396 deadline: zx::MonotonicInstant,
397 ) -> Result<Vec<EpollEvent>, Errno> {
398 {
399 let mut state = self.state.lock();
400 let recheck_list = std::mem::take(&mut state.recheck_list);
401 for key in &recheck_list {
402 let wait_object = state.wait_objects.get_mut(key).unwrap();
403 wait_object.deactivate_wakeup_source(current_task);
404 }
405 for (idx, key) in recheck_list.iter().enumerate() {
406 let wait_object = state.wait_objects.get_mut(key).unwrap();
407 if let Err(err) = self.do_recheck(current_task, wait_object, *key) {
408 state.recheck_list.extend(recheck_list[idx..].iter().copied());
411 return Err(err);
412 }
413 }
414 }
415
416 let pending_list = self.wait_until_pending_event(current_task, max_events, deadline)?;
417
418 let mut result = vec![];
421 let mut state = self.state.lock();
422 let state = &mut *state;
423 let mut seen = FxHashSet::with_capacity_and_hasher(pending_list.len(), Default::default());
424 for pending_event in pending_list.iter().filter(|e| seen.insert(e.key)) {
425 let Some(wait) = state.wait_objects.get_mut(&pending_event.key) else { continue };
428
429 let reported_events = pending_event.events & wait.events;
430 result.push(EpollEvent::new(reported_events, wait.data));
431
432 if wait.events.contains(FdEvents::EPOLLONESHOT) {
435 continue;
436 }
437
438 self.wait_on_file_edge_triggered(current_task, pending_event.key, wait)?;
439
440 if !wait.events.contains(FdEvents::EPOLLET) {
441 state.recheck_list.push(pending_event.key);
442 }
443
444 if !wait.events.contains(FdEvents::EPOLLET) {
446 if wait.events.contains(FdEvents::EPOLLWAKEUP) {
449 if let ReadyItemKey::Usize(key) = pending_event.key {
450 let origin = WakeupSourceOrigin::Epoll(key);
451 current_task
452 .kernel()
453 .suspend_resume_manager
454 .activate_wakeup_source_with_actor(
455 origin.clone(),
456 Some(current_task.command()),
457 );
458 wait.active_wakeup_source = Some(origin);
459 }
460 }
461 }
462 }
463
464 Ok(result)
465 }
466}
467
468impl FileOps for EpollFileObject {
469 fileops_impl_nonseekable!();
470 fileops_impl_noop_sync!();
471 fileops_impl_dataless!();
472
473 fn wait_async(
474 &self,
475 _file: &FileObject,
476 _current_task: &CurrentTask,
477 waiter: &Waiter,
478 events: FdEvents,
479 handler: EventHandler,
480 ) -> Option<WaitCanceler> {
481 Some(self.waiters.wait_async_fd_events(waiter, events, handler))
482 }
483
484 fn query_events(
485 &self,
486 _file: &FileObject,
487 current_task: &CurrentTask,
488 ) -> Result<FdEvents, Errno> {
489 let mut events = FdEvents::empty();
490 let state = self.state.lock();
491 if !state.processing_list.is_empty() || !self.waitable_state.lock().trigger_list.is_empty()
492 {
493 events |= FdEvents::POLLIN;
494 } else {
495 for key in &state.recheck_list {
496 let wait_object = state.wait_objects.get(key).unwrap();
497 let Some(target) = wait_object.target() else { continue };
498 let _token = allow_subclass();
501 if !(target.query_events(current_task)? & wait_object.events).is_empty() {
502 events |= FdEvents::POLLIN;
503 break;
504 }
505 }
506 }
507 Ok(events)
508 }
509
510 fn close(self: Box<Self>, _file: &FileObjectState, current_task: &CurrentTask) {
511 let mut guard = self.state.lock();
512 for wait_object in guard.wait_objects.values_mut() {
513 wait_object.deactivate_wakeup_source(current_task);
514 }
515 }
516}
517
518#[derive(Clone)]
519pub struct EpollEventHandler {
520 key: ReadyItemKey,
521 waitable_state: Arc<LockDepMutex<EpollWaitableState, EpollWaitableStateLock>>,
522 waiters: Arc<WaitQueue>,
523}
524
525impl EpollEventHandler {
526 pub fn handle(self, events: FdEvents) {
527 {
528 let mut waitable_state = self.waitable_state.lock();
529 waitable_state.trigger_list.push_back(ReadyItem { key: self.key, events });
530 }
531 self.waiters.notify_fd_events(FdEvents::POLLIN);
532 }
533}
534
535impl EpollFileObject {
536 fn new_wait_handler(&self, key: ReadyItemKey) -> EventHandler {
537 EventHandler::Epoll(EpollEventHandler {
538 key,
539 waitable_state: Arc::clone(&self.waitable_state),
540 waiters: Arc::clone(&self.waiters),
541 })
542 }
543}
544
545#[cfg(test)]
546mod tests {
547 use super::*;
548 use crate::fs::fuchsia::create_fuchsia_pipe;
549 use crate::task::Waiter;
550 use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
551 use crate::testing::{anon_test_file, spawn_kernel_and_run};
552 use crate::vfs::buffers::{VecInputBuffer, VecOutputBuffer};
553 use crate::vfs::eventfd::{EventFdType, new_eventfd};
554 use crate::vfs::fs_registry::FsRegistry;
555 use crate::vfs::pipe::{new_pipe, register_pipe_fs};
556 use crate::vfs::socket::{SocketDomain, SocketType, UnixSocket};
557 use starnix_lifecycle::AtomicCounter;
558 use starnix_sync::Mutex;
559 use starnix_uapi::vfs::{EpollEvent, FdEvents};
560 use syncio::Zxio;
561
562 #[::fuchsia::test]
563 async fn test_epoll_read_ready() {
564 static WRITE_COUNT: AtomicCounter<usize> = AtomicCounter::<usize>::new_const(0);
565 const EVENT_DATA: u64 = 42;
566
567 spawn_kernel_and_run(async |current_task| {
568 let kernel = current_task.kernel();
569 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
570
571 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
572
573 let test_string = "hello starnix".to_string();
574 let test_len = test_string.len();
575
576 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
577 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
578 epoll_file
579 .add(
580 ¤t_task,
581 &pipe_out,
582 &epoll_file_handle,
583 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
584 )
585 .unwrap();
586
587 let (sender, receiver) = std::sync::mpsc::channel();
588 let value = test_string.clone();
589 let closure = move |task: &CurrentTask| {
590 let bytes_written =
591 pipe_in.write(&task, &mut VecInputBuffer::new(value.as_bytes())).unwrap();
592 assert_eq!(bytes_written, test_len);
593 WRITE_COUNT.add(bytes_written);
594 sender.send(()).unwrap();
595 };
596 let req = SpawnRequestBuilder::new().with_sync_closure(closure).build();
597 kernel.kthreads.spawner().spawn_from_request(req);
598 let events =
599 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::INFINITE).unwrap();
600 receiver.recv().unwrap();
601 assert_eq!(1, events.len());
602 let event = &events[0];
603 assert!(event.events().contains(FdEvents::POLLIN));
604 assert_eq!(event.data(), EVENT_DATA);
605
606 let mut buffer = VecOutputBuffer::new(test_len);
607 let bytes_read = pipe_out.read(¤t_task, &mut buffer).unwrap();
608 assert_eq!(bytes_read, WRITE_COUNT.get());
609 assert_eq!(bytes_read, test_len);
610 assert_eq!(buffer.data(), test_string.as_bytes());
611 })
612 .await;
613 }
614
615 #[::fuchsia::test]
616 async fn test_epoll_ready_then_wait() {
617 const EVENT_DATA: u64 = 42;
618
619 spawn_kernel_and_run(async |current_task| {
620 let kernel = current_task.kernel();
621 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
622
623 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
624
625 let test_string = "hello starnix".to_string();
626 let test_bytes = test_string.as_bytes();
627 let test_len = test_bytes.len();
628
629 assert_eq!(
630 pipe_in.write(¤t_task, &mut VecInputBuffer::new(test_bytes)).unwrap(),
631 test_bytes.len()
632 );
633
634 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
635 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
636 epoll_file
637 .add(
638 ¤t_task,
639 &pipe_out,
640 &epoll_file_handle,
641 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
642 )
643 .unwrap();
644
645 let events =
646 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::INFINITE).unwrap();
647 assert_eq!(1, events.len());
648 let event = &events[0];
649 assert!(event.events().contains(FdEvents::POLLIN));
650 assert_eq!(event.data(), EVENT_DATA);
651
652 let mut buffer = VecOutputBuffer::new(test_len);
653 let bytes_read = pipe_out.read(¤t_task, &mut buffer).unwrap();
654 assert_eq!(bytes_read, test_len);
655 assert_eq!(buffer.data(), test_bytes);
656 })
657 .await;
658 }
659
660 #[::fuchsia::test]
661 async fn test_epoll_ctl_cancel() {
662 spawn_kernel_and_run(async |current_task| {
663 for do_cancel in [true, false] {
664 let event = new_eventfd(¤t_task, 0, EventFdType::Counter, true);
665 let waiter = Waiter::new();
666
667 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
668 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
669 const EVENT_DATA: u64 = 42;
670 epoll_file
671 .add(
672 ¤t_task,
673 &event,
674 &epoll_file_handle,
675 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
676 )
677 .unwrap();
678
679 if do_cancel {
680 epoll_file.delete(¤t_task, &event).unwrap();
681 }
682
683 let wait_canceler = event
684 .wait_async(¤t_task, &waiter, FdEvents::POLLIN, EventHandler::None)
685 .expect("wait_async");
686 if do_cancel {
687 wait_canceler.cancel();
688 }
689
690 let add_val = 1u64;
691
692 assert_eq!(
693 event
694 .write(¤t_task, &mut VecInputBuffer::new(&add_val.to_ne_bytes()))
695 .unwrap(),
696 std::mem::size_of::<u64>()
697 );
698
699 let events =
700 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
701
702 if do_cancel {
703 assert_eq!(0, events.len());
704 } else {
705 assert_eq!(1, events.len());
706 let event = &events[0];
707 assert!(event.events().contains(FdEvents::POLLIN));
708 assert_eq!(event.data(), EVENT_DATA);
709 }
710 }
711 })
712 .await;
713 }
714
715 #[::fuchsia::test]
716 async fn test_multiple_events() {
717 spawn_kernel_and_run(async |current_task| {
718 let (client1, server1) = zx::Socket::create_stream();
719 let (client2, server2) = zx::Socket::create_stream();
720 let pipe1 = create_fuchsia_pipe(¤t_task, client1, OpenFlags::RDWR)
721 .expect("create_fuchsia_pipe");
722 let pipe2 = create_fuchsia_pipe(¤t_task, client2, OpenFlags::RDWR)
723 .expect("create_fuchsia_pipe");
724 let server1_zxio = Zxio::create(server1.into_handle()).expect("Zxio::create");
725 let server2_zxio = Zxio::create(server2.into_handle()).expect("Zxio::create");
726
727 let poll = || {
728 let epoll_object = EpollFileObject::new_file(¤t_task);
729 let epoll_file = epoll_object.downcast_file::<EpollFileObject>().unwrap();
730 epoll_file
731 .add(¤t_task, &pipe1, &epoll_object, EpollEvent::new(FdEvents::POLLIN, 1))
732 .expect("epoll_file.add");
733 epoll_file
734 .add(¤t_task, &pipe2, &epoll_object, EpollEvent::new(FdEvents::POLLIN, 2))
735 .expect("epoll_file.add");
736 epoll_file.wait(¤t_task, 2, zx::MonotonicInstant::ZERO).expect("wait")
737 };
738
739 let fds = poll();
740 assert!(fds.is_empty());
741
742 assert_eq!(server1_zxio.write(&[0]).expect("write"), 1);
743
744 let fds = poll();
745 assert_eq!(fds.len(), 1);
746 assert_eq!(fds[0].events(), FdEvents::POLLIN);
747 assert_eq!(fds[0].data(), 1);
748 assert_eq!(pipe1.read(¤t_task, &mut VecOutputBuffer::new(64)).expect("read"), 1);
749
750 let fds = poll();
751 assert!(fds.is_empty());
752
753 assert_eq!(server2_zxio.write(&[0]).expect("write"), 1);
754
755 let fds = poll();
756 assert_eq!(fds.len(), 1);
757 assert_eq!(fds[0].events(), FdEvents::POLLIN);
758 assert_eq!(fds[0].data(), 2);
759 assert_eq!(pipe2.read(¤t_task, &mut VecOutputBuffer::new(64)).expect("read"), 1);
760
761 let fds = poll();
762 assert!(fds.is_empty());
763 })
764 .await;
765 }
766
767 #[::fuchsia::test]
768 async fn test_cancel_after_notify() {
769 spawn_kernel_and_run(async |current_task| {
770 let event = new_eventfd(¤t_task, 0, EventFdType::Counter, true);
771 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
772 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
773
774 const EVENT_DATA: u64 = 42;
776 epoll_file
777 .add(
778 ¤t_task,
779 &event,
780 &epoll_file_handle,
781 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
782 )
783 .unwrap();
784
785 let add_val = 1u64;
787 assert_eq!(
788 event
789 .write(¤t_task, &mut VecInputBuffer::new(&add_val.to_ne_bytes()))
790 .unwrap(),
791 std::mem::size_of::<u64>()
792 );
793
794 assert_eq!(
795 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap().len(),
796 1
797 );
798
799 epoll_file.delete(¤t_task, &event).unwrap();
801
802 assert_eq!(
804 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap().len(),
805 0
806 );
807 })
809 .await;
810 }
811
812 #[::fuchsia::test]
813 async fn test_add_then_modify() {
814 spawn_kernel_and_run(async |current_task| {
815 let (socket1, _socket2) = UnixSocket::new_pair(
816 ¤t_task,
817 SocketDomain::Unix,
818 SocketType::Stream,
819 OpenFlags::RDWR,
820 )
821 .expect("Failed to create socket pair.");
822
823 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
824 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
825
826 const EVENT_DATA: u64 = 42;
827 epoll_file
828 .add(
829 ¤t_task,
830 &socket1,
831 &epoll_file_handle,
832 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
833 )
834 .unwrap();
835 assert_eq!(
836 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap().len(),
837 0
838 );
839
840 let read_write_event = FdEvents::POLLIN | FdEvents::POLLOUT;
841 epoll_file
842 .modify(¤t_task, &socket1, EpollEvent::new(read_write_event, EVENT_DATA))
843 .unwrap();
844 let triggered_events =
845 epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
846 assert_eq!(1, triggered_events.len());
847 let event = &triggered_events[0];
848 assert_eq!(event.events(), FdEvents::POLLOUT);
849 assert_eq!(event.data(), EVENT_DATA);
850 })
851 .await;
852 }
853
854 #[::fuchsia::test]
855 async fn test_waiter_removal() {
856 spawn_kernel_and_run(async |current_task| {
857 let event = new_eventfd(¤t_task, 0, EventFdType::Counter, true);
858 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
859 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
860
861 const EVENT_DATA: u64 = 42;
862 epoll_file
863 .add(
864 ¤t_task,
865 &event,
866 &epoll_file_handle,
867 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
868 )
869 .unwrap();
870
871 std::mem::drop(event);
872
873 assert!(epoll_file.waiters.is_empty());
874 })
875 .await;
876 }
877
878 #[derive(Clone)]
884 struct ControlledEventsFile {
885 wait_queue: Arc<WaitQueue>,
886 events: Arc<Mutex<Result<FdEvents, Errno>>>,
887 }
888
889 impl ControlledEventsFile {
890 fn new(events: FdEvents) -> Self {
891 Self {
892 wait_queue: Arc::new(WaitQueue::default()),
893 events: Arc::new(Mutex::new(Ok(events))),
894 }
895 }
896
897 fn set_events(&self, events: Result<FdEvents, Errno>) {
898 *self.events.lock() = events;
899 }
900 }
901
902 impl FileOps for ControlledEventsFile {
903 fileops_impl_nonseekable!();
904 fileops_impl_noop_sync!();
905 fileops_impl_dataless!();
906
907 fn wait_async(
908 &self,
909 _file: &FileObject,
910 _current_task: &CurrentTask,
911 waiter: &Waiter,
912 events: FdEvents,
913 handler: EventHandler,
914 ) -> Option<WaitCanceler> {
915 Some(self.wait_queue.wait_async_fd_events(waiter, events, handler))
916 }
917
918 fn query_events(
919 &self,
920 _file: &FileObject,
921 _current_task: &CurrentTask,
922 ) -> Result<FdEvents, Errno> {
923 self.events.lock().clone()
924 }
925 }
926
927 #[::fuchsia::test]
928 async fn test_epoll_recheck_failure_deactivates_wakeup_sources() {
929 spawn_kernel_and_run(async |current_task| {
930 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
931 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
932
933 let ops1 = ControlledEventsFile::new(FdEvents::POLLIN);
934 let file1 = anon_test_file(¤t_task, Box::new(ops1.clone()), OpenFlags::RDWR);
935 let ops2 = ControlledEventsFile::new(FdEvents::POLLIN);
936 let file2 = anon_test_file(¤t_task, Box::new(ops2.clone()), OpenFlags::RDWR);
937
938 epoll_file
939 .add(
940 ¤t_task,
941 &file1,
942 &epoll_file_handle,
943 EpollEvent::new(FdEvents::POLLIN | FdEvents::EPOLLWAKEUP, 1),
944 )
945 .unwrap();
946 epoll_file
947 .add(
948 ¤t_task,
949 &file2,
950 &epoll_file_handle,
951 EpollEvent::new(FdEvents::POLLIN | FdEvents::EPOLLWAKEUP, 2),
952 )
953 .unwrap();
954
955 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
956 assert_eq!(events.len(), 2);
957 assert!(!current_task.kernel().suspend_resume_manager.lock().can_suspend());
958
959 ops1.set_events(error!(EPERM));
960 ops2.set_events(error!(EPERM));
961
962 assert!(epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).is_err());
963 assert!(current_task.kernel().suspend_resume_manager.lock().can_suspend());
964 })
965 .await;
966 }
967
968 #[::fuchsia::test]
969 async fn test_level_triggered_remains_ready_until_drained() {
970 spawn_kernel_and_run(async |current_task| {
975 let kernel = current_task.kernel();
976 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
977
978 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
979 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
980 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
981 const EVENT_DATA: u64 = 100;
982 epoll_file
983 .add(
984 ¤t_task,
985 &pipe_out,
986 &epoll_file_handle,
987 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
988 )
989 .unwrap();
990
991 let key: ReadyItemKey = pipe_out.id.as_epoll_key().into();
992
993 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[1, 2])).unwrap();
995
996 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
998 assert_eq!(events.len(), 1);
999 assert_eq!(events[0].data(), EVENT_DATA);
1000
1001 assert!(epoll_file.state.lock().recheck_list.contains(&key));
1003
1004 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1006 assert_eq!(events.len(), 1);
1007 assert_eq!(events[0].data(), EVENT_DATA);
1008
1009 let mut out_buf = VecOutputBuffer::new(10);
1011 assert_eq!(pipe_out.read(¤t_task, &mut out_buf).unwrap(), 2);
1012
1013 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1015 assert_eq!(events.len(), 0);
1016
1017 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[3])).unwrap();
1019 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1020 assert_eq!(events.len(), 1);
1021 assert_eq!(events[0].data(), EVENT_DATA);
1022 })
1023 .await;
1024 }
1025
1026 #[::fuchsia::test]
1027 async fn test_nested_epoll_delayed_drain() {
1028 spawn_kernel_and_run(async |current_task| {
1036 let kernel = current_task.kernel();
1037 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1038
1039 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1040 let epoll_inner_handle = EpollFileObject::new_file(¤t_task);
1041 let epoll_inner = epoll_inner_handle.downcast_file::<EpollFileObject>().unwrap();
1042 let epoll_outer_handle = EpollFileObject::new_file(¤t_task);
1043 let epoll_outer = epoll_outer_handle.downcast_file::<EpollFileObject>().unwrap();
1044
1045 const INNER_DATA: u64 = 1;
1046 const OUTER_DATA: u64 = 2;
1047
1048 epoll_inner
1049 .add(
1050 ¤t_task,
1051 &pipe_out,
1052 &epoll_inner_handle,
1053 EpollEvent::new(FdEvents::POLLIN, INNER_DATA),
1054 )
1055 .unwrap();
1056 epoll_outer
1057 .add(
1058 ¤t_task,
1059 &epoll_inner_handle,
1060 &epoll_outer_handle,
1061 EpollEvent::new(FdEvents::POLLIN, OUTER_DATA),
1062 )
1063 .unwrap();
1064
1065 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[1, 2])).unwrap();
1067
1068 let inner_events =
1070 epoll_inner.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1071 assert_eq!(inner_events.len(), 1);
1072
1073 let outer_events =
1076 epoll_outer.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1077 assert_eq!(outer_events.len(), 1);
1078 assert_eq!(outer_events[0].data(), OUTER_DATA);
1079
1080 let mut out_buf = VecOutputBuffer::new(10);
1082 assert_eq!(pipe_out.read(¤t_task, &mut out_buf).unwrap(), 2);
1083
1084 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[3, 4])).unwrap();
1086
1087 let outer_events2 =
1089 epoll_outer.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1090 assert_eq!(outer_events2.len(), 1);
1091 assert_eq!(outer_events2[0].data(), OUTER_DATA);
1092
1093 let inner_events2 =
1095 epoll_inner.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1096 assert_eq!(inner_events2.len(), 1);
1097 assert_eq!(inner_events2[0].data(), INNER_DATA);
1098 })
1099 .await;
1100 }
1101
1102 #[::fuchsia::test]
1103 async fn test_epoll_wait_with_external_waiter_preserves_wait_canceler() {
1104 spawn_kernel_and_run(async |current_task| {
1107 let kernel = current_task.kernel();
1108 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1109
1110 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1111 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
1112 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
1113 const EVENT_DATA: u64 = 42;
1114 epoll_file
1115 .add(
1116 ¤t_task,
1117 &pipe_out,
1118 &epoll_file_handle,
1119 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
1120 )
1121 .unwrap();
1122
1123 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[1])).unwrap();
1124
1125 let waiter = Waiter::new();
1127 let canceler = epoll_file_handle
1128 .wait_async(¤t_task, &waiter, FdEvents::POLLIN, EventHandler::None)
1129 .expect("wait_async on epoll_file");
1130
1131 assert!(!epoll_file.waiters.is_empty());
1132
1133 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1135 assert_eq!(events.len(), 1);
1136
1137 canceler.cancel();
1139 assert!(epoll_file.waiters.is_empty());
1140
1141 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1143 assert_eq!(events.len(), 1);
1144 })
1145 .await;
1146 }
1147
1148 #[::fuchsia::test]
1149 async fn test_multithreaded_epoll_concurrent_recheck() {
1150 spawn_kernel_and_run(async |current_task| {
1152 let kernel = current_task.kernel();
1153 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1154
1155 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1156 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
1157 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
1158 const EVENT_DATA: u64 = 42;
1159 epoll_file
1160 .add(
1161 ¤t_task,
1162 &pipe_out,
1163 &epoll_file_handle,
1164 EpollEvent::new(FdEvents::POLLIN, EVENT_DATA),
1165 )
1166 .unwrap();
1167
1168 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[1, 2])).unwrap();
1170
1171 let events1 = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1173 assert_eq!(events1.len(), 1);
1174
1175 let events2 = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1178 assert_eq!(events2.len(), 1);
1179
1180 let mut buf = VecOutputBuffer::new(10);
1182 assert_eq!(pipe_out.read(¤t_task, &mut buf).unwrap(), 2);
1183
1184 let events3 = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1187 assert_eq!(events3.len(), 0);
1188
1189 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[3])).unwrap();
1191 let events4 = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1192 assert_eq!(events4.len(), 1);
1193 })
1194 .await;
1195 }
1196
1197 #[::fuchsia::test]
1198 async fn test_epoll_query_events_checks_recheck_list() {
1199 spawn_kernel_and_run(async |current_task| {
1202 let kernel = current_task.kernel();
1203 register_pipe_fs(kernel.expando.get::<FsRegistry>().as_ref());
1204
1205 let (pipe_out, pipe_in) = new_pipe(¤t_task).unwrap();
1206 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
1207 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
1208 epoll_file
1209 .add(
1210 ¤t_task,
1211 &pipe_out,
1212 &epoll_file_handle,
1213 EpollEvent::new(FdEvents::POLLIN, 42),
1214 )
1215 .unwrap();
1216
1217 pipe_in.write(¤t_task, &mut VecInputBuffer::new(&[1, 2])).unwrap();
1218
1219 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1221 assert_eq!(events.len(), 1);
1222
1223 let queried = epoll_file_handle.query_events(¤t_task).unwrap();
1225 assert!(queried.contains(FdEvents::POLLIN));
1226
1227 let mut buf = VecOutputBuffer::new(10);
1229 assert_eq!(pipe_out.read(¤t_task, &mut buf).unwrap(), 2);
1230
1231 let queried = epoll_file_handle.query_events(¤t_task).unwrap();
1233 assert!(!queried.contains(FdEvents::POLLIN));
1234 })
1235 .await;
1236 }
1237
1238 #[::fuchsia::test]
1239 async fn test_recheck_list_query_error_preserves_remaining_keys() {
1240 spawn_kernel_and_run(async |current_task| {
1243 let epoll_file_handle = EpollFileObject::new_file(¤t_task);
1244 let epoll_file = epoll_file_handle.downcast_file::<EpollFileObject>().unwrap();
1245
1246 let ops1 = ControlledEventsFile::new(FdEvents::POLLIN);
1247 let file1 = anon_test_file(¤t_task, Box::new(ops1.clone()), OpenFlags::RDWR);
1248 let ops2 = ControlledEventsFile::new(FdEvents::POLLIN);
1249 let file2 = anon_test_file(¤t_task, Box::new(ops2.clone()), OpenFlags::RDWR);
1250
1251 let _key1: ReadyItemKey = file1.id.as_epoll_key().into();
1252 let key2: ReadyItemKey = file2.id.as_epoll_key().into();
1253
1254 epoll_file
1255 .add(
1256 ¤t_task,
1257 &file1,
1258 &epoll_file_handle,
1259 EpollEvent::new(FdEvents::POLLIN, 1),
1260 )
1261 .unwrap();
1262 epoll_file
1263 .add(
1264 ¤t_task,
1265 &file2,
1266 &epoll_file_handle,
1267 EpollEvent::new(FdEvents::POLLIN, 2),
1268 )
1269 .unwrap();
1270
1271 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1273 assert_eq!(events.len(), 2);
1274
1275 assert_eq!(epoll_file.state.lock().recheck_list.len(), 2);
1277
1278 ops1.set_events(error!(EPERM));
1280
1281 assert!(epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).is_err());
1283
1284 assert!(
1286 epoll_file.state.lock().recheck_list.contains(&key2),
1287 "file2 should remain on recheck_list despite file1's error"
1288 );
1289
1290 epoll_file.delete(¤t_task, &file1).unwrap();
1292
1293 let events = epoll_file.wait(¤t_task, 10, zx::MonotonicInstant::ZERO).unwrap();
1295 assert_eq!(events.len(), 1);
1296 assert_eq!(events[0].data(), 2);
1297 })
1298 .await;
1299 }
1300}