implement select and poll without test
This commit is contained in:
parent
f62809096e
commit
7bd2ce50f2
128
src/libos/src/fs/io_multiplexing.rs
Normal file
128
src/libos/src/fs/io_multiplexing.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
use super::*;
|
||||||
|
use crate::syscall::AsSocket;
|
||||||
|
use std::vec::Vec;
|
||||||
|
|
||||||
|
/// Forward to host `poll`
|
||||||
|
/// (sgx_libc doesn't have `select`)
|
||||||
|
pub fn do_select(
|
||||||
|
nfds: usize,
|
||||||
|
readfds: &mut libc::fd_set,
|
||||||
|
writefds: &mut libc::fd_set,
|
||||||
|
exceptfds: &mut libc::fd_set,
|
||||||
|
timeout: Option<libc::timeval>,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
// convert libos fd to Linux fd
|
||||||
|
let mut host_to_libos_fd = [0; libc::FD_SETSIZE];
|
||||||
|
let mut polls = Vec::<libc::pollfd>::new();
|
||||||
|
|
||||||
|
let current_ref = process::get_current();
|
||||||
|
let mut proc = current_ref.lock().unwrap();
|
||||||
|
let file_table_ref = proc.get_files().lock().unwrap();
|
||||||
|
|
||||||
|
for fd in 0..nfds {
|
||||||
|
let (r, w, e) = (readfds.is_set(fd), writefds.is_set(fd), exceptfds.is_set(fd));
|
||||||
|
if !(r || w || e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let host_fd = file_table_ref.get(fd as FileDesc)?.as_socket()?.fd();
|
||||||
|
|
||||||
|
host_to_libos_fd[host_fd as usize] = fd;
|
||||||
|
let mut events = 0;
|
||||||
|
if r { events |= libc::POLLIN; }
|
||||||
|
if w { events |= libc::POLLOUT; }
|
||||||
|
if e { events |= libc::POLLERR; }
|
||||||
|
|
||||||
|
polls.push(libc::pollfd {
|
||||||
|
fd: host_fd as c_int,
|
||||||
|
events,
|
||||||
|
revents: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeout = match timeout {
|
||||||
|
None => -1,
|
||||||
|
Some(tv) => (tv.tv_sec * 1000 + tv.tv_usec / 1000) as i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ret = unsafe {
|
||||||
|
libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout)
|
||||||
|
};
|
||||||
|
|
||||||
|
if ret < 0 {
|
||||||
|
return Err(Error::new(Errno::from_retval(ret as i32), ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert fd back and write fdset
|
||||||
|
readfds.clear();
|
||||||
|
writefds.clear();
|
||||||
|
exceptfds.clear();
|
||||||
|
|
||||||
|
for poll in polls.iter() {
|
||||||
|
let fd = host_to_libos_fd[poll.fd as usize];
|
||||||
|
if poll.revents & libc::POLLIN != 0 {
|
||||||
|
readfds.set(fd);
|
||||||
|
}
|
||||||
|
if poll.revents & libc::POLLOUT != 0 {
|
||||||
|
writefds.set(fd);
|
||||||
|
}
|
||||||
|
if poll.revents & libc::POLLERR != 0 {
|
||||||
|
exceptfds.set(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_poll(
|
||||||
|
polls: &mut [libc::pollfd],
|
||||||
|
timeout: c_int,
|
||||||
|
) -> Result<usize, Error> {
|
||||||
|
info!("poll: [..], timeout: {}", timeout);
|
||||||
|
|
||||||
|
let current_ref = process::get_current();
|
||||||
|
let mut proc = current_ref.lock().unwrap();
|
||||||
|
|
||||||
|
// convert libos fd to Linux fd
|
||||||
|
for poll in polls.iter_mut() {
|
||||||
|
let file_ref = proc.get_files().lock().unwrap().get(poll.fd as FileDesc)?;
|
||||||
|
let socket = file_ref.as_socket()?;
|
||||||
|
poll.fd = socket.fd();
|
||||||
|
}
|
||||||
|
let ret = unsafe {
|
||||||
|
libc::ocall::poll(polls.as_mut_ptr(), polls.len() as u64, timeout)
|
||||||
|
};
|
||||||
|
// recover fd ?
|
||||||
|
|
||||||
|
if ret < 0 {
|
||||||
|
Err(Error::new(Errno::from_retval(ret as i32), ""))
|
||||||
|
} else {
|
||||||
|
Ok(ret as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safe methods for `libc::fd_set`
|
||||||
|
trait FdSetExt {
|
||||||
|
fn set(&mut self, fd: usize);
|
||||||
|
fn clear(&mut self);
|
||||||
|
fn is_set(&mut self, fd: usize) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FdSetExt for libc::fd_set {
|
||||||
|
fn set(&mut self, fd: usize) {
|
||||||
|
assert!(fd < libc::FD_SETSIZE);
|
||||||
|
unsafe {
|
||||||
|
libc::FD_SET(fd as c_int, self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
libc::FD_ZERO(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_set(&mut self, fd: usize) -> bool {
|
||||||
|
assert!(fd < libc::FD_SETSIZE);
|
||||||
|
unsafe { libc::FD_ISSET(fd as c_int, self) }
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ pub use self::inode_file::{INodeExt, INodeFile, ROOT_INODE};
|
|||||||
pub use self::socket_file::SocketFile;
|
pub use self::socket_file::SocketFile;
|
||||||
use self::inode_file::OpenOptions;
|
use self::inode_file::OpenOptions;
|
||||||
pub use self::pipe::Pipe;
|
pub use self::pipe::Pipe;
|
||||||
|
pub use self::io_multiplexing::*;
|
||||||
|
|
||||||
mod file;
|
mod file;
|
||||||
mod file_table;
|
mod file_table;
|
||||||
@ -19,6 +20,7 @@ mod inode_file;
|
|||||||
mod socket_file;
|
mod socket_file;
|
||||||
mod pipe;
|
mod pipe;
|
||||||
mod sgx_impl;
|
mod sgx_impl;
|
||||||
|
mod io_multiplexing;
|
||||||
|
|
||||||
|
|
||||||
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
|
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
|
||||||
|
@ -81,6 +81,33 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
||||||
SYS_UNLINK => do_unlink(arg0 as *const i8),
|
SYS_UNLINK => do_unlink(arg0 as *const i8),
|
||||||
|
|
||||||
|
// IO multiplexing
|
||||||
|
SYS_SELECT => do_select(
|
||||||
|
arg0 as c_int,
|
||||||
|
arg1 as *mut libc::fd_set,
|
||||||
|
arg2 as *mut libc::fd_set,
|
||||||
|
arg3 as *mut libc::fd_set,
|
||||||
|
arg4 as *const libc::timeval,
|
||||||
|
),
|
||||||
|
SYS_POLL => do_poll(
|
||||||
|
arg0 as *mut libc::pollfd,
|
||||||
|
arg1 as libc::nfds_t,
|
||||||
|
arg2 as c_int,
|
||||||
|
),
|
||||||
|
SYS_EPOLL_CREATE => do_epoll_create1(arg0 as c_int),
|
||||||
|
SYS_EPOLL_CTL => do_epoll_ctl(
|
||||||
|
arg0 as c_int,
|
||||||
|
arg1 as c_int,
|
||||||
|
arg2 as c_int,
|
||||||
|
arg3 as *const libc::epoll_event,
|
||||||
|
),
|
||||||
|
SYS_EPOLL_WAIT => do_epoll_wait(
|
||||||
|
arg0 as c_int,
|
||||||
|
arg1 as *mut libc::epoll_event,
|
||||||
|
arg2 as c_int,
|
||||||
|
arg3 as c_int,
|
||||||
|
),
|
||||||
|
|
||||||
// process
|
// process
|
||||||
SYS_EXIT => do_exit(arg0 as i32),
|
SYS_EXIT => do_exit(arg0 as i32),
|
||||||
SYS_SPAWN => do_spawn(
|
SYS_SPAWN => do_spawn(
|
||||||
@ -936,7 +963,87 @@ fn do_recvfrom(
|
|||||||
Ok(ret as isize)
|
Ok(ret as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
trait AsSocket {
|
fn do_select(
|
||||||
|
nfds: c_int,
|
||||||
|
readfds: *mut libc::fd_set,
|
||||||
|
writefds: *mut libc::fd_set,
|
||||||
|
exceptfds: *mut libc::fd_set,
|
||||||
|
timeout: *const libc::timeval
|
||||||
|
) -> Result<isize, Error> {
|
||||||
|
// check arguments
|
||||||
|
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
|
||||||
|
return Err(Error::new(EINVAL, "nfds is negative or exceeds the resource limit"));
|
||||||
|
}
|
||||||
|
let nfds = nfds as usize;
|
||||||
|
|
||||||
|
let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
|
||||||
|
let readfds = if !readfds.is_null() {
|
||||||
|
check_mut_ptr(readfds)?;
|
||||||
|
unsafe { &mut *readfds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds0
|
||||||
|
};
|
||||||
|
let writefds = if !writefds.is_null() {
|
||||||
|
check_mut_ptr(writefds)?;
|
||||||
|
unsafe { &mut *writefds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds1
|
||||||
|
};
|
||||||
|
let exceptfds = if !exceptfds.is_null() {
|
||||||
|
check_mut_ptr(exceptfds)?;
|
||||||
|
unsafe { &mut *exceptfds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds2
|
||||||
|
};
|
||||||
|
let timeout = if !timeout.is_null() {
|
||||||
|
check_ptr(timeout)?;
|
||||||
|
Some(unsafe { timeout.read() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let n = fs::do_select(nfds, readfds, writefds, exceptfds, timeout)?;
|
||||||
|
Ok(n as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_poll(
|
||||||
|
fds: *mut libc::pollfd,
|
||||||
|
nfds: libc::nfds_t,
|
||||||
|
timeout: c_int,
|
||||||
|
) -> Result<isize, Error> {
|
||||||
|
check_mut_array(fds, nfds as usize)?;
|
||||||
|
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
|
||||||
|
|
||||||
|
let n = fs::do_poll(polls, timeout)?;
|
||||||
|
Ok(n as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_epoll_create1(flags: c_int) -> Result<isize, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_epoll_ctl(
|
||||||
|
epfd: c_int,
|
||||||
|
op: c_int,
|
||||||
|
fd: c_int,
|
||||||
|
event: *const libc::epoll_event,
|
||||||
|
) -> Result<isize, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_epoll_wait(
|
||||||
|
epfd: c_int,
|
||||||
|
events: *mut libc::epoll_event,
|
||||||
|
maxevents: c_int,
|
||||||
|
timeout: c_int,
|
||||||
|
) -> Result<isize, Error> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsSocket {
|
||||||
fn as_socket(&self) -> Result<&SocketFile, Error>;
|
fn as_socket(&self) -> Result<&SocketFile, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user