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 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,
|
||||
|
@ -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<Option<FileRef>>,
|
||||
max_fd: FileDesc,
|
||||
num_fds: u32,
|
||||
table: Vec<Option<FileTableEntry>>,
|
||||
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<FileRef> {
|
||||
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<FileRef> {
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<FileDesc, Error> {
|
||||
let file_ref : Arc<Box<File>> = 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])
|
||||
}
|
||||
|
@ -80,9 +80,9 @@ fn init_files(parent_ref: &ProcessRef) -> Result<FileTable, Error> {
|
||||
let stdout : Arc<Box<File>> = 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)
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
},
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user