implement select and poll without test

This commit is contained in:
WangRunji 2019-04-09 00:04:44 +08:00
parent f62809096e
commit 7bd2ce50f2
3 changed files with 238 additions and 1 deletions

@ -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>;
} }