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