• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use nix::sys::epoll::Epoll;
6 use nix::sys::epoll::EpollCreateFlags;
7 use nix::sys::epoll::EpollEvent;
8 use nix::sys::epoll::EpollFlags;
9 use nix::sys::epoll::EpollTimeout;
10 
11 use crate::rutabaga_os::OwnedDescriptor;
12 use crate::rutabaga_os::WaitEvent;
13 use crate::rutabaga_os::WaitTimeout;
14 use crate::rutabaga_os::WAIT_CONTEXT_MAX;
15 use crate::rutabaga_utils::RutabagaResult;
16 
17 pub struct WaitContext {
18     epoll_ctx: Epoll,
19 }
20 
21 impl WaitContext {
new() -> RutabagaResult<WaitContext>22     pub fn new() -> RutabagaResult<WaitContext> {
23         let epoll = Epoll::new(EpollCreateFlags::empty())?;
24         Ok(WaitContext { epoll_ctx: epoll })
25     }
26 
add(&mut self, connection_id: u64, descriptor: &OwnedDescriptor) -> RutabagaResult<()>27     pub fn add(&mut self, connection_id: u64, descriptor: &OwnedDescriptor) -> RutabagaResult<()> {
28         self.epoll_ctx.add(
29             descriptor,
30             EpollEvent::new(EpollFlags::EPOLLIN, connection_id),
31         )?;
32         Ok(())
33     }
34 
wait(&mut self, timeout: WaitTimeout) -> RutabagaResult<Vec<WaitEvent>>35     pub fn wait(&mut self, timeout: WaitTimeout) -> RutabagaResult<Vec<WaitEvent>> {
36         let mut events = [EpollEvent::empty(); WAIT_CONTEXT_MAX];
37 
38         let epoll_timeout = match timeout {
39             WaitTimeout::Finite(duration) => {
40                 // We shouldn't need timeouts greater than 60s.
41                 let timeout: u16 = duration.as_millis().try_into().unwrap_or(u16::MAX);
42                 EpollTimeout::from(timeout)
43             }
44             WaitTimeout::NoTimeout => EpollTimeout::NONE,
45         };
46 
47         let count = loop {
48             match self.epoll_ctx.wait(&mut events, epoll_timeout) {
49                 Err(nix::errno::Errno::EINTR) => (),
50                 result => break result?,
51             }
52         };
53 
54         let events = events[0..count]
55             .iter()
56             .map(|e| WaitEvent {
57                 connection_id: e.data(),
58                 readable: e.events() & EpollFlags::EPOLLIN == EpollFlags::EPOLLIN,
59                 hung_up: e.events() & EpollFlags::EPOLLHUP == EpollFlags::EPOLLHUP,
60             })
61             .collect();
62 
63         Ok(events)
64     }
65 
delete(&mut self, descriptor: &OwnedDescriptor) -> RutabagaResult<()>66     pub fn delete(&mut self, descriptor: &OwnedDescriptor) -> RutabagaResult<()> {
67         self.epoll_ctx.delete(descriptor)?;
68         Ok(())
69     }
70 }
71