Files
RedBear-OS/src/platform/redox/epoll.rs
T
2024-09-27 11:22:36 +02:00

168 lines
4.6 KiB
Rust

use super::{
super::{types::*, Pal, PalEpoll},
Sys,
};
use crate::{
error::{Errno, ResultExt},
fs::File,
header::{errno::*, fcntl::*, signal::sigset_t, sys_epoll::*},
io::prelude::*,
platform,
};
use core::{mem, slice};
use syscall::{
data::{Event, TimeSpec},
flag::EVENT_READ,
};
fn epoll_to_event_flags(epoll: c_uint) -> syscall::EventFlags {
let mut event_flags = syscall::EventFlags::empty();
if epoll & EPOLLIN != 0 {
event_flags |= syscall::EventFlags::EVENT_READ;
}
if epoll & EPOLLOUT != 0 {
event_flags |= syscall::EventFlags::EVENT_WRITE;
}
/*TODO: support more EPOLL flags
let unsupported = !(EPOLLIN | EPOLLOUT);
if epoll & unsupported != 0 {
eprintln!("epoll unsupported flags 0x{:X}", epoll & unsupported);
}
*/
event_flags
}
fn event_flags_to_epoll(flags: syscall::EventFlags) -> c_uint {
let mut epoll = 0;
if flags.contains(syscall::EventFlags::EVENT_READ) {
epoll |= EPOLLIN;
}
if flags.contains(syscall::EventFlags::EVENT_WRITE) {
epoll |= EPOLLOUT;
}
epoll
}
impl PalEpoll for Sys {
fn epoll_create1(flags: c_int) -> Result<c_int, Errno> {
Sys::open(c_str!("/scheme/event"), O_RDWR | flags, 0)
}
unsafe fn epoll_ctl(
epfd: c_int,
op: c_int,
fd: c_int,
event: *mut epoll_event,
) -> Result<(), Errno> {
match op {
EPOLL_CTL_ADD | EPOLL_CTL_MOD => {
Sys::write(
epfd,
&Event {
id: fd as usize,
flags: unsafe { epoll_to_event_flags((*event).events) },
// NOTE: Danger when using something smaller than 64-bit
// systems. If this is needed, use a box or something
data: unsafe { (*event).data.u64 as usize },
},
)?;
}
EPOLL_CTL_DEL => {
Sys::write(
epfd,
&Event {
id: fd as usize,
flags: syscall::EventFlags::empty(),
//TODO: Is data required?
data: 0,
},
)?;
}
_ => return Err(Errno(EINVAL)),
}
Ok(())
}
unsafe fn epoll_pwait(
epfd: c_int,
events: *mut epoll_event,
maxevents: c_int,
timeout: c_int,
_sigset: *const sigset_t,
) -> Result<usize, Errno> {
// TODO: sigset
assert_eq!(mem::size_of::<epoll_event>(), mem::size_of::<Event>());
if maxevents <= 0 {
return Err(Errno(EINVAL));
}
let timer_opt = if timeout != -1 {
let mut timer = File::open(c_str!("/scheme/time/4"), O_RDWR)?;
Sys::write(
epfd,
&Event {
id: timer.fd as usize,
flags: EVENT_READ,
data: 0,
},
)?;
let mut time = TimeSpec::default();
let _ = timer
.read(&mut time)
.map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?;
time.tv_sec += (timeout as i64) / 1000;
time.tv_nsec += (timeout % 1000) * 1000000;
let _ = timer
.write(&time)
.map_err(|err| Errno(err.raw_os_error().unwrap_or(EIO)))?;
Some(timer)
} else {
None
};
let bytes_read = Sys::read(epfd, unsafe {
slice::from_raw_parts_mut(
events as *mut u8,
maxevents as usize * mem::size_of::<syscall::Event>(),
)
})?;
let read = bytes_read as usize / mem::size_of::<syscall::Event>();
let mut count = 0;
for i in 0..read {
unsafe {
let event_ptr = events.add(i);
let target_ptr = events.add(count);
let event = *(event_ptr as *mut Event);
if let Some(ref timer) = timer_opt {
if event.id as c_int == timer.fd {
// Do not count timer event
continue;
}
}
*target_ptr = epoll_event {
events: event_flags_to_epoll(event.flags),
data: epoll_data {
u64: event.data as u64,
},
..Default::default()
};
count += 1;
}
}
Ok(count)
}
}