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;
|
||||
use self::inode_file::OpenOptions;
|
||||
pub use self::pipe::Pipe;
|
||||
pub use self::io_multiplexing::*;
|
||||
|
||||
mod file;
|
||||
mod file_table;
|
||||
@ -19,6 +20,7 @@ mod inode_file;
|
||||
mod socket_file;
|
||||
mod pipe;
|
||||
mod sgx_impl;
|
||||
mod io_multiplexing;
|
||||
|
||||
|
||||
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_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
|
||||
SYS_EXIT => do_exit(arg0 as i32),
|
||||
SYS_SPAWN => do_spawn(
|
||||
@ -936,7 +963,87 @@ fn do_recvfrom(
|
||||
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>;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user