relibc/platform/redox/
epoll.rs1use super::{
2 super::{Pal, PalEpoll, types::*},
3 Sys,
4};
5
6use crate::{
7 error::Errno,
8 header::{bits_sigset_t::sigset_t, errno::*, fcntl::*, sys_epoll::*},
9};
10use core::{mem, slice};
11use syscall::{data::Event, flag::EVENT_READ};
12
13fn epoll_to_event_flags(epoll: c_uint) -> syscall::EventFlags {
14 let mut event_flags = syscall::EventFlags::empty();
15
16 if epoll & EPOLLIN != 0 {
17 event_flags |= syscall::EventFlags::EVENT_READ;
18 }
19
20 if epoll & EPOLLOUT != 0 {
21 event_flags |= syscall::EventFlags::EVENT_WRITE;
22 }
23
24 let unsupported = !(EPOLLIN | EPOLLOUT);
26 if epoll & unsupported != 0 {
27 log::trace!("epoll unsupported flags 0x{:X}", epoll & unsupported);
28 }
29
30 event_flags
31}
32
33fn event_flags_to_epoll(flags: syscall::EventFlags) -> c_uint {
34 let mut epoll = 0;
35
36 if flags.contains(syscall::EventFlags::EVENT_READ) {
37 epoll |= EPOLLIN;
38 }
39
40 if flags.contains(syscall::EventFlags::EVENT_WRITE) {
41 epoll |= EPOLLOUT;
42 }
43
44 epoll
45}
46
47impl PalEpoll for Sys {
48 fn epoll_create1(flags: c_int) -> Result<c_int, Errno> {
49 Sys::open(c"/scheme/event".into(), O_RDWR | flags, 0)
50 }
51
52 unsafe fn epoll_ctl(
53 epfd: c_int,
54 op: c_int,
55 fd: c_int,
56 event: *mut epoll_event,
57 ) -> Result<(), Errno> {
58 match op {
59 EPOLL_CTL_ADD | EPOLL_CTL_MOD => {
60 Sys::write(
61 epfd,
62 &Event {
63 id: fd as usize,
64 flags: unsafe { epoll_to_event_flags((*event).events) },
65 data: unsafe { (*event).data.u64 as usize },
68 },
69 )?;
70 }
71 EPOLL_CTL_DEL => {
72 Sys::write(
73 epfd,
74 &Event {
75 id: fd as usize,
76 flags: syscall::EventFlags::empty(),
77 data: 0,
79 },
80 )?;
81 }
82 _ => return Err(Errno(EINVAL)),
83 }
84 Ok(())
85 }
86
87 unsafe fn epoll_pwait(
88 epfd: c_int,
89 events: *mut epoll_event,
90 maxevents: c_int,
91 timeout: c_int,
92 sigset: *const sigset_t,
93 ) -> Result<usize, Errno> {
94 assert_eq!(mem::size_of::<epoll_event>(), mem::size_of::<Event>());
95
96 if maxevents <= 0 {
97 return Err(Errno(EINVAL));
98 }
99
100 let timer_opt = if timeout != -1 {
101 Some(register_timeout(epfd, timeout)?)
102 } else {
103 None
104 };
105
106 let callback = || {
107 let res = syscall::read(epfd as usize, unsafe {
108 slice::from_raw_parts_mut(
109 events as *mut u8,
110 maxevents as usize * mem::size_of::<syscall::Event>(),
111 )
112 });
113 res
114 };
115
116 let bytes_read = if sigset.is_null() {
117 callback()
118 } else {
119 let allowset = !unsafe { *sigset };
121 redox_rt::signal::callback_or_signal_async(allowset, callback)
122 }?;
123
124 let read = bytes_read as usize / mem::size_of::<syscall::Event>();
125
126 let mut count = 0;
127 for i in 0..read {
128 unsafe {
129 let event_ptr = events.add(i);
130 let target_ptr = events.add(count);
131 let event = *(event_ptr as *mut Event);
132 *target_ptr = epoll_event {
133 events: event_flags_to_epoll(event.flags),
134 data: epoll_data {
135 u64: event.data as u64,
136 },
137 ..Default::default()
138 };
139 count += 1;
140 }
141 }
142
143 Ok(count)
144 }
145}
146
147fn register_timeout(epfd: i32, timeout: i32) -> Result<usize, Errno> {
148 if timeout < 0 {
149 return Err(Errno(EINVAL));
150 }
151 Sys::write(
152 epfd,
153 &Event {
154 id: syscall::EVENT_TIMEOUT_ID,
155 flags: EVENT_READ,
156 data: timeout as usize,
157 },
158 )
159}