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