xref: /relibc/src/header/poll/mod.rs (revision ed19381547d66b76981ea1e4ff942c5a4da45ab7)
1 //! poll implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/poll.h.html
2 
3 use core::{mem, slice};
4 
5 use crate::{
6     fs::File,
7     header::sys_epoll::{
8         epoll_create1, epoll_ctl, epoll_data, epoll_event, epoll_wait, EPOLLERR, EPOLLHUP, EPOLLIN,
9         EPOLLNVAL, EPOLLOUT, EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, EPOLL_CLOEXEC, EPOLL_CTL_ADD,
10     },
11     platform::types::*,
12 };
13 
14 pub const POLLIN: c_short = 0x001;
15 pub const POLLPRI: c_short = 0x002;
16 pub const POLLOUT: c_short = 0x004;
17 pub const POLLERR: c_short = 0x008;
18 pub const POLLHUP: c_short = 0x010;
19 pub const POLLNVAL: c_short = 0x020;
20 pub const POLLRDNORM: c_short = 0x040;
21 pub const POLLRDBAND: c_short = 0x080;
22 pub const POLLWRNORM: c_short = 0x100;
23 pub const POLLWRBAND: c_short = 0x200;
24 
25 pub type nfds_t = c_ulong;
26 
27 #[repr(C)]
28 pub struct pollfd {
29     pub fd: c_int,
30     pub events: c_short,
31     pub revents: c_short,
32 }
33 
34 pub fn poll_epoll(fds: &mut [pollfd], timeout: c_int) -> c_int {
35     let event_map = [
36         (POLLIN, EPOLLIN),
37         (POLLPRI, EPOLLPRI),
38         (POLLOUT, EPOLLOUT),
39         (POLLERR, EPOLLERR),
40         (POLLHUP, EPOLLHUP),
41         (POLLNVAL, EPOLLNVAL),
42         (POLLRDNORM, EPOLLRDNORM),
43         (POLLWRNORM, EPOLLWRNORM),
44         (POLLRDBAND, EPOLLRDBAND),
45         (POLLWRBAND, EPOLLWRBAND),
46     ];
47 
48     let ep = {
49         let epfd = epoll_create1(EPOLL_CLOEXEC);
50         if epfd < 0 {
51             return -1;
52         }
53         File::new(epfd)
54     };
55 
56     for i in 0..fds.len() {
57         let mut pfd = &mut fds[i];
58 
59         let mut event = epoll_event {
60             events: 0,
61             data: epoll_data { u64: i as u64 },
62             ..Default::default()
63         };
64 
65         for (p, ep) in event_map.iter() {
66             if pfd.events & p > 0 {
67                 event.events |= ep;
68             }
69         }
70 
71         pfd.revents = 0;
72 
73         if epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &mut event) < 0 {
74             return -1;
75         }
76     }
77 
78     let mut events: [epoll_event; 32] = unsafe { mem::zeroed() };
79     let res = epoll_wait(*ep, events.as_mut_ptr(), events.len() as c_int, timeout);
80     if res < 0 {
81         return -1;
82     }
83 
84     for event in events.iter().take(res as usize) {
85         let pi = unsafe { event.data.u64 as usize };
86         // TODO: Error status when fd does not match?
87         if let Some(pfd) = fds.get_mut(pi) {
88             for (p, ep) in event_map.iter() {
89                 if event.events & ep > 0 {
90                     pfd.revents |= p;
91                 }
92             }
93         }
94     }
95 
96     let mut count = 0;
97     for pfd in fds.iter() {
98         if pfd.revents > 0 {
99             count += 1;
100         }
101     }
102     count
103 }
104 
105 #[no_mangle]
106 pub unsafe extern "C" fn poll(fds: *mut pollfd, nfds: nfds_t, timeout: c_int) -> c_int {
107     trace_expr!(
108         poll_epoll(slice::from_raw_parts_mut(fds, nfds as usize), timeout),
109         "poll({:p}, {}, {})",
110         fds,
111         nfds,
112         timeout
113     )
114 }
115