From d40af94aaf920818e05b942c34731684793aa65f Mon Sep 17 00:00:00 2001 From: "Tate, Hongliang Tian" Date: Sun, 6 Jan 2019 22:11:51 +0800 Subject: [PATCH] Support O_CLOEXEC on open() or pipe2() --- src/libos/include/syscall.h | 1 + src/libos/src/fs/file_table.rs | 93 ++++++++++++++++++--------- src/libos/src/fs/mod.rs | 20 ++++-- src/libos/src/process/spawn/mod.rs | 6 +- src/libos/src/syscall/mod.rs | 26 +++++--- src/libos/src/syscall/syscall_entry.c | 6 ++ 6 files changed, 100 insertions(+), 52 deletions(-) diff --git a/src/libos/include/syscall.h b/src/libos/include/syscall.h index a7cd296d..f4bc3f50 100644 --- a/src/libos/include/syscall.h +++ b/src/libos/include/syscall.h @@ -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 off_t occlum_lseek(int fd, off_t offset, int whence); 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, const char** argv, diff --git a/src/libos/src/fs/file_table.rs b/src/libos/src/fs/file_table.rs index b855390e..e1b22f02 100644 --- a/src/libos/src/fs/file_table.rs +++ b/src/libos/src/fs/file_table.rs @@ -4,71 +4,100 @@ use {std}; pub type FileDesc = u32; -// Invariant 1: fd < max_fd, where fd is any fd in the table -// Invariant 2: max_fd = table.size() -// Invariant 3: num_fds <= table.size() -#[derive(Clone, Debug, Default)] +#[derive(Debug, Default)] #[repr(C)] pub struct FileTable { - table: Vec>, - max_fd: FileDesc, - num_fds: u32, + table: Vec>, + num_fds: usize, } +#[derive(Debug, Clone)] +struct FileTableEntry { + file: FileRef, + close_on_spawn: bool, +} + + impl FileTable { pub fn new() -> FileTable { FileTable { - table: Vec::with_capacity(0), - max_fd: 0, + table: Vec::with_capacity(4), 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 free_fd = if self.num_fds < self.max_fd { - table.iter().enumerate() - .find(|&(idx, opt)| opt.is_none()).unwrap().0 as FileDesc + let min_free_fd = if self.num_fds < table.len() { + table.iter().enumerate().find(|&(idx, opt)| opt.is_none()) + .unwrap().0 } else { table.push(None); - self.max_fd += 1; - self.num_fds + table.len() - 1 }; - table[free_fd as usize] = Some(file); + table[min_free_fd as usize] = Some(FileTableEntry::new(file, + close_on_spawn)); self.num_fds += 1; - free_fd + min_free_fd as FileDesc } pub fn get(&self, fd: FileDesc) -> Option { - if fd >= self.max_fd { + if fd as usize >= self.table.len() { return None; } 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 { - if fd >= self.max_fd { + if fd as usize >= self.table.len() { return None; } - let mut del_file = None; + let mut del_entry = None; let table = &mut self.table; - std::mem::swap(&mut del_file, &mut table[fd as usize]); - if del_file.is_none() { - return None; - } - + std::mem::swap(&mut del_entry, &mut table[fd as usize]); self.num_fds -= 1; - if fd + 1 == self.max_fd { - 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; - } - del_file + del_entry.map(|entry| entry.file) + } +} + +impl Clone for FileTable { + 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, + } } } diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 5f3cb123..a6db8503 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -17,6 +17,7 @@ pub const O_RDWR : u32 = 0x00000002; pub const O_CREAT : u32 = 0x00000040; pub const O_TRUNC : u32 = 0x00000200; pub const O_APPEND : u32 = 0x00000400; +pub const O_CLOEXEC: u32 = 0x00080000; // TODO: use the type defined in Rust libc. // @@ -54,10 +55,12 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { let file_ref : Arc> = Arc::new(Box::new( SgxFile::new(sgx_file, is_readable, is_writable, is_append)?)); - let current_ref = process::get_current(); - let mut current_process = current_ref.lock().unwrap(); - let fd = current_process.get_files_mut().put(file_ref); - + let fd = { + let current_ref = process::get_current(); + let mut current = current_ref.lock().unwrap(); + let close_on_spawn = flags & O_CLOEXEC != 0; + current.get_files_mut().put(file_ref, close_on_spawn) + }; 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 mut current = current_ref.lock().unwrap(); let pipe = Pipe::new()?; let mut file_table = current.get_files_mut(); - let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader))); - let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer))); + let close_on_spawn = flags & O_CLOEXEC != 0; + 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]) } diff --git a/src/libos/src/process/spawn/mod.rs b/src/libos/src/process/spawn/mod.rs index 650fb52f..db4ab682 100644 --- a/src/libos/src/process/spawn/mod.rs +++ b/src/libos/src/process/spawn/mod.rs @@ -80,9 +80,9 @@ fn init_files(parent_ref: &ProcessRef) -> Result { let stdout : Arc> = Arc::new(Box::new(StdoutFile::new())); // TODO: implement and use a real stderr let stderr = stdout.clone(); - file_table.put(stdin); - file_table.put(stdout); - file_table.put(stderr); + file_table.put(stdin, false); + file_table.put(stdout, false); + file_table.put(stderr, false); Ok(file_table) } diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index 9c7abf0e..c9ab3a69 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -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) } +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; @@ -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> { - check_mut_array_from_user(fds_u, 2)?; - let fds = fs::do_pipe()?; - unsafe { - *fds_u.offset(0) = fds[0] as c_int; - *fds_u.offset(1) = fds[1] as c_int; - } - Ok(()) +#[no_mangle] +pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int { + occlum_pipe2(fds, 0) } #[no_mangle] -pub extern "C" fn occlum_pipe(fds: *mut c_int) -> c_int { - match do_pipe(fds) { +pub extern "C" fn occlum_pipe2(fds: *mut c_int, flags: c_int) -> c_int { + match do_pipe2(fds, flags) { Ok(()) => { 0 }, diff --git a/src/libos/src/syscall/syscall_entry.c b/src/libos/src/syscall/syscall_entry.c index 6dbe83c1..fc54b336 100644 --- a/src/libos/src/syscall/syscall_entry.c +++ b/src/libos/src/syscall/syscall_entry.c @@ -119,6 +119,12 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long ret = (long) occlum_pipe(fds); break; } + case SYS_pipe2: { + DECL_SYSCALL_ARG(int*, fds, arg0); + DECL_SYSCALL_ARG(int, flags, arg1); + ret = (long) occlum_pipe2(fds, flags); + break; + } default: ret = occlum_unknown(num); break;