Merge branch 'ebadf-epoll' into 'master'
Workaround epoll edge cases See merge request redox-os/relibc!1368
This commit is contained in:
+38
-25
@@ -5,19 +5,19 @@
|
||||
use core::{mem, ptr, slice};
|
||||
|
||||
use crate::{
|
||||
error::Errno,
|
||||
fs::File,
|
||||
header::{
|
||||
bits_sigset_t::sigset_t,
|
||||
errno::EBADF,
|
||||
errno::{EBADF, EINTR},
|
||||
sys_epoll::{
|
||||
EPOLL_CLOEXEC, EPOLL_CTL_ADD, EPOLLERR, EPOLLHUP, EPOLLIN, EPOLLNVAL, EPOLLOUT,
|
||||
EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, epoll_create1, epoll_ctl,
|
||||
epoll_data, epoll_event, epoll_pwait,
|
||||
EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, epoll_data, epoll_event,
|
||||
},
|
||||
time::timespec,
|
||||
},
|
||||
platform::{
|
||||
self,
|
||||
ERRNO, PalEpoll, Sys,
|
||||
types::{c_int, c_short, c_ulong},
|
||||
},
|
||||
};
|
||||
@@ -77,10 +77,13 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
|
||||
];
|
||||
|
||||
let ep = {
|
||||
let epfd = epoll_create1(EPOLL_CLOEXEC);
|
||||
if epfd < 0 {
|
||||
return -1;
|
||||
}
|
||||
let epfd = match Sys::epoll_create1(EPOLL_CLOEXEC) {
|
||||
Ok(epfd) => epfd,
|
||||
Err(Errno(err)) => {
|
||||
ERRNO.set(err);
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
File::new(epfd)
|
||||
};
|
||||
|
||||
@@ -108,11 +111,14 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
|
||||
}
|
||||
}
|
||||
|
||||
if unsafe { epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &raw mut event) } < 0 {
|
||||
if platform::ERRNO.get() == EBADF {
|
||||
match unsafe { Sys::epoll_ctl(*ep, EPOLL_CTL_ADD, pfd.fd, &raw mut event) } {
|
||||
Ok(_) => {}
|
||||
Err(Errno(EBADF)) => {
|
||||
pfd.revents |= POLLNVAL;
|
||||
closed += 1;
|
||||
} else {
|
||||
}
|
||||
Err(Errno(err)) => {
|
||||
ERRNO.set(err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -124,29 +130,36 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
|
||||
}
|
||||
|
||||
let mut events: [epoll_event; 32] = unsafe { mem::zeroed() };
|
||||
let res = unsafe {
|
||||
epoll_pwait(
|
||||
match unsafe {
|
||||
Sys::epoll_pwait(
|
||||
*ep,
|
||||
events.as_mut_ptr(),
|
||||
events.len() as c_int,
|
||||
timeout,
|
||||
sigmask,
|
||||
)
|
||||
};
|
||||
if res < 0 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for event in events.iter().take(res as usize) {
|
||||
let pi = unsafe { event.data.u64 as usize };
|
||||
// TODO: Error status when fd does not match?
|
||||
if let Some(pfd) = fds.get_mut(pi) {
|
||||
for (p, ep) in event_map.iter() {
|
||||
if event.events & ep > 0 {
|
||||
pfd.revents |= p;
|
||||
} {
|
||||
Ok(res) => {
|
||||
for event in events.iter().take(res) {
|
||||
let pi = unsafe { event.data.u64 as usize };
|
||||
// TODO: Error status when fd does not match?
|
||||
if let Some(pfd) = fds.get_mut(pi) {
|
||||
for (p, ep) in event_map.iter() {
|
||||
if event.events & ep > 0 {
|
||||
pfd.revents |= p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Errno(err)) => {
|
||||
if err == EINTR && closed > 0 {
|
||||
// some fds are closed by signal
|
||||
} else {
|
||||
ERRNO.set(err);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
+40
-21
@@ -10,6 +10,7 @@ use crate::{
|
||||
io::prelude::*,
|
||||
};
|
||||
use core::{mem, slice};
|
||||
use log::warn;
|
||||
use syscall::{
|
||||
data::{Event, TimeSpec},
|
||||
flag::EVENT_READ,
|
||||
@@ -103,27 +104,21 @@ impl PalEpoll for Sys {
|
||||
}
|
||||
|
||||
let timer_opt = if timeout != -1 {
|
||||
let mut timer = File::open(c"/scheme/time/4".into(), 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)
|
||||
// TODO: Any of syscall inside this can fail, there's a race condition on kernel reusing fd numbers
|
||||
let mut i = 10;
|
||||
loop {
|
||||
match register_timeout(epfd, timeout) {
|
||||
Ok(timer) => break Some(timer),
|
||||
Err(_) if i > 0 => {
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
Err(_) => {
|
||||
warn!("Gave up writing timeout for epoll");
|
||||
break None;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -174,3 +169,27 @@ impl PalEpoll for Sys {
|
||||
Ok(count)
|
||||
}
|
||||
}
|
||||
|
||||
fn register_timeout(epfd: i32, timeout: i32) -> Result<File, Errno> {
|
||||
let mut timer = File::open(c"/scheme/time/4".into(), O_RDWR)?;
|
||||
if let Err(e) = Sys::write(
|
||||
epfd,
|
||||
&Event {
|
||||
id: timer.fd as usize,
|
||||
flags: EVENT_READ,
|
||||
data: 0,
|
||||
},
|
||||
) {
|
||||
return Err(e);
|
||||
}
|
||||
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)))?;
|
||||
Ok(timer)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user