Skip to main content

relibc/platform/redox/
epoll.rs

1use 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    /*TODO: support more EPOLL flags  */
25    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                        // NOTE: Danger when using something smaller than 64-bit
66                        // systems. If this is needed, use a box or something
67                        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                        //TODO: Is data required?
78                        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            // Allowset is inverse of sigset mask
120            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}