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