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