Support O_CLOEXEC on open() or pipe2()
This commit is contained in:
		
							parent
							
								
									98b4508a0d
								
							
						
					
					
						commit
						d40af94aaf
					
				| @ -18,6 +18,7 @@ extern ssize_t occlum_readv(int fd, struct iovec* iov, int count); | |||||||
| extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count); | extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count); | ||||||
| extern off_t occlum_lseek(int fd, off_t offset, int whence); | extern off_t occlum_lseek(int fd, off_t offset, int whence); | ||||||
| extern int occlum_pipe(int fds[2]); | extern int occlum_pipe(int fds[2]); | ||||||
|  | extern int occlum_pipe2(int fds[2], int flags); | ||||||
| 
 | 
 | ||||||
| extern int occlum_spawn(int* child_pid, const char* path, | extern int occlum_spawn(int* child_pid, const char* path, | ||||||
|                         const char** argv, |                         const char** argv, | ||||||
|  | |||||||
| @ -4,71 +4,100 @@ use {std}; | |||||||
| 
 | 
 | ||||||
| pub type FileDesc = u32; | pub type FileDesc = u32; | ||||||
| 
 | 
 | ||||||
| // Invariant 1: fd < max_fd, where fd is any fd in the table
 | #[derive(Debug, Default)] | ||||||
| // Invariant 2: max_fd = table.size()
 |  | ||||||
| // Invariant 3: num_fds <= table.size()
 |  | ||||||
| #[derive(Clone, Debug, Default)] |  | ||||||
| #[repr(C)] | #[repr(C)] | ||||||
| pub struct FileTable { | pub struct FileTable { | ||||||
|     table: Vec<Option<FileRef>>, |     table: Vec<Option<FileTableEntry>>, | ||||||
|     max_fd: FileDesc, |     num_fds: usize, | ||||||
|     num_fds: u32, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | struct FileTableEntry { | ||||||
|  |     file: FileRef, | ||||||
|  |     close_on_spawn: bool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| impl FileTable { | impl FileTable { | ||||||
|     pub fn new() -> FileTable { |     pub fn new() -> FileTable { | ||||||
|         FileTable { |         FileTable { | ||||||
|             table: Vec::with_capacity(0), |             table: Vec::with_capacity(4), | ||||||
|             max_fd: 0, |  | ||||||
|             num_fds: 0, |             num_fds: 0, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn put(&mut self, file: FileRef) -> FileDesc { |     pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { | ||||||
|         let mut table = &mut self.table; |         let mut table = &mut self.table; | ||||||
| 
 | 
 | ||||||
|         let free_fd = if self.num_fds < self.max_fd { |         let min_free_fd = if self.num_fds < table.len() { | ||||||
|             table.iter().enumerate() |             table.iter().enumerate().find(|&(idx, opt)| opt.is_none()) | ||||||
|                 .find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc |                 .unwrap().0 | ||||||
|         } else { |         } else { | ||||||
|             table.push(None); |             table.push(None); | ||||||
|             self.max_fd += 1; |             table.len() - 1 | ||||||
|             self.num_fds |  | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         table[free_fd as usize] = Some(file); |         table[min_free_fd as usize] = Some(FileTableEntry::new(file, | ||||||
|  |                                                                close_on_spawn)); | ||||||
|         self.num_fds += 1; |         self.num_fds += 1; | ||||||
| 
 | 
 | ||||||
|         free_fd |         min_free_fd as FileDesc | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get(&self, fd: FileDesc) -> Option<FileRef> { |     pub fn get(&self, fd: FileDesc) -> Option<FileRef> { | ||||||
|         if fd >= self.max_fd { |         if fd as usize >= self.table.len() { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let table = &self.table; |         let table = &self.table; | ||||||
|         table[fd as usize].as_ref().map(|file_ref| file_ref.clone()) |         table[fd as usize].as_ref().map(|entry| entry.file.clone()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> { |     pub fn del(&mut self, fd: FileDesc) -> Option<FileRef> { | ||||||
|         if fd >= self.max_fd { |         if fd as usize >= self.table.len() { | ||||||
|             return None; |             return None; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let mut del_file = None; |         let mut del_entry = None; | ||||||
|         let table = &mut self.table; |         let table = &mut self.table; | ||||||
|         std::mem::swap(&mut del_file, &mut table[fd as usize]); |         std::mem::swap(&mut del_entry, &mut table[fd as usize]); | ||||||
|         if del_file.is_none() { |  | ||||||
|             return None; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         self.num_fds -= 1; |         self.num_fds -= 1; | ||||||
|         if fd + 1 == self.max_fd { |         del_entry.map(|entry| entry.file) | ||||||
|             self.max_fd = table.iter().enumerate().rev() |     } | ||||||
|                 .find(|&(idx, opt)| opt.is_some()) | } | ||||||
|                 .map_or(0, |(max_used_fd,opt)| max_used_fd + 1) as FileDesc; | 
 | ||||||
|         } | impl Clone for FileTable { | ||||||
|         del_file |     fn clone(&self) -> FileTable { | ||||||
|  |         // Only clone file descriptors that are not close-on-spawn
 | ||||||
|  |         let mut num_cloned_fds = 0; | ||||||
|  |         let cloned_table = self.table.iter().map(|entry| { | ||||||
|  |             match entry { | ||||||
|  |                 Some(file_table_entry) => { | ||||||
|  |                     match file_table_entry.close_on_spawn { | ||||||
|  |                         false => { | ||||||
|  |                             num_cloned_fds += 1; | ||||||
|  |                             Some(file_table_entry.clone()) | ||||||
|  |                         } | ||||||
|  |                         true => None | ||||||
|  |                     } | ||||||
|  |                 }, | ||||||
|  |                 None => None | ||||||
|  |             } | ||||||
|  |         }).collect(); | ||||||
|  | 
 | ||||||
|  |         FileTable { | ||||||
|  |             table: cloned_table, | ||||||
|  |             num_fds: num_cloned_fds, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | impl FileTableEntry { | ||||||
|  |     fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||||
|  |         FileTableEntry { | ||||||
|  |             file, | ||||||
|  |             close_on_spawn, | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ pub const O_RDWR   : u32 = 0x00000002; | |||||||
| pub const O_CREAT  : u32 = 0x00000040; | pub const O_CREAT  : u32 = 0x00000040; | ||||||
| pub const O_TRUNC  : u32 = 0x00000200; | pub const O_TRUNC  : u32 = 0x00000200; | ||||||
| pub const O_APPEND : u32 = 0x00000400; | pub const O_APPEND : u32 = 0x00000400; | ||||||
|  | pub const O_CLOEXEC: u32 = 0x00080000; | ||||||
| 
 | 
 | ||||||
| // TODO: use the type defined in Rust libc.
 | // TODO: use the type defined in Rust libc.
 | ||||||
| //
 | //
 | ||||||
| @ -54,10 +55,12 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> { | |||||||
|     let file_ref : Arc<Box<File>> = Arc::new(Box::new( |     let file_ref : Arc<Box<File>> = Arc::new(Box::new( | ||||||
|             SgxFile::new(sgx_file, is_readable, is_writable, is_append)?)); |             SgxFile::new(sgx_file, is_readable, is_writable, is_append)?)); | ||||||
| 
 | 
 | ||||||
|  |     let fd = { | ||||||
|         let current_ref = process::get_current(); |         let current_ref = process::get_current(); | ||||||
|     let mut current_process = current_ref.lock().unwrap(); |         let mut current = current_ref.lock().unwrap(); | ||||||
|     let fd = current_process.get_files_mut().put(file_ref); |         let close_on_spawn = flags & O_CLOEXEC != 0; | ||||||
| 
 |         current.get_files_mut().put(file_ref, close_on_spawn) | ||||||
|  |     }; | ||||||
|     Ok(fd) |     Ok(fd) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -111,13 +114,16 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn do_pipe() -> Result<[FileDesc; 2], Error> { | pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> { | ||||||
|     let current_ref = process::get_current(); |     let current_ref = process::get_current(); | ||||||
|     let mut current = current_ref.lock().unwrap(); |     let mut current = current_ref.lock().unwrap(); | ||||||
|     let pipe = Pipe::new()?; |     let pipe = Pipe::new()?; | ||||||
| 
 | 
 | ||||||
|     let mut file_table = current.get_files_mut(); |     let mut file_table = current.get_files_mut(); | ||||||
|     let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader))); |     let close_on_spawn = flags & O_CLOEXEC != 0; | ||||||
|     let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer))); |     let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), | ||||||
|  |                                    close_on_spawn); | ||||||
|  |     let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), | ||||||
|  |                                    close_on_spawn); | ||||||
|     Ok([reader_fd, writer_fd]) |     Ok([reader_fd, writer_fd]) | ||||||
| } | } | ||||||
|  | |||||||
| @ -80,9 +80,9 @@ fn init_files(parent_ref: &ProcessRef) -> Result<FileTable, Error> { | |||||||
|     let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new())); |     let stdout : Arc<Box<File>> = Arc::new(Box::new(StdoutFile::new())); | ||||||
|     // TODO: implement and use a real stderr
 |     // TODO: implement and use a real stderr
 | ||||||
|     let stderr = stdout.clone(); |     let stderr = stdout.clone(); | ||||||
|     file_table.put(stdin); |     file_table.put(stdin, false); | ||||||
|     file_table.put(stdout); |     file_table.put(stdout, false); | ||||||
|     file_table.put(stderr); |     file_table.put(stderr, false); | ||||||
|     Ok(file_table) |     Ok(file_table) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -195,6 +195,17 @@ fn do_brk(new_brk_addr: *const c_void) -> Result<*const c_void, Error> { | |||||||
|     vm::do_brk(new_brk_addr).map(|ret_brk_addr| ret_brk_addr as *const c_void) |     vm::do_brk(new_brk_addr).map(|ret_brk_addr| ret_brk_addr as *const c_void) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | fn do_pipe2(fds_u: *mut c_int, flags: c_int) -> Result<(), Error> { | ||||||
|  |     check_mut_array_from_user(fds_u, 2)?; | ||||||
|  |     // TODO: how to deal with open flags???
 | ||||||
|  |     let fds = fs::do_pipe2(flags as u32)?; | ||||||
|  |     unsafe { | ||||||
|  |         *fds_u.offset(0) = fds[0] as c_int; | ||||||
|  |         *fds_u.offset(1) = fds[1] as c_int; | ||||||
|  |     } | ||||||
|  |     Ok(()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| const MAP_FAILED : *const c_void = ((-1) as i64) as *const c_void; | const MAP_FAILED : *const c_void = ((-1) as i64) as *const c_void; | ||||||
| 
 | 
 | ||||||
| @ -237,19 +248,14 @@ pub extern "C" fn occlum_brk(addr: *const c_void) ->  *const c_void { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn do_pipe(fds_u: *mut c_int) -> Result<(), Error> { | #[no_mangle] | ||||||
|     check_mut_array_from_user(fds_u, 2)?; | pub extern "C" fn occlum_pipe(fds: *mut c_int) ->  c_int { | ||||||
|     let fds = fs::do_pipe()?; |     occlum_pipe2(fds, 0) | ||||||
|     unsafe { |  | ||||||
|         *fds_u.offset(0) = fds[0] as c_int; |  | ||||||
|         *fds_u.offset(1) = fds[1] as c_int; |  | ||||||
|     } |  | ||||||
|     Ok(()) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[no_mangle] | #[no_mangle] | ||||||
| pub extern "C" fn occlum_pipe(fds: *mut c_int) ->  c_int { | pub extern "C" fn occlum_pipe2(fds: *mut c_int, flags: c_int) ->  c_int { | ||||||
|     match do_pipe(fds) { |     match do_pipe2(fds, flags) { | ||||||
|         Ok(()) => { |         Ok(()) => { | ||||||
|             0 |             0 | ||||||
|         }, |         }, | ||||||
|  | |||||||
| @ -119,6 +119,12 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long | |||||||
|         ret = (long) occlum_pipe(fds); |         ret = (long) occlum_pipe(fds); | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  |     case SYS_pipe2: { | ||||||
|  |         DECL_SYSCALL_ARG(int*, fds, arg0); | ||||||
|  |         DECL_SYSCALL_ARG(int, flags, arg1); | ||||||
|  |         ret = (long) occlum_pipe2(fds, flags); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|         ret = occlum_unknown(num); |         ret = occlum_unknown(num); | ||||||
|         break; |         break; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user