Add pipe test
This commit is contained in:
parent
a2b62891cc
commit
a712bfe70a
@ -26,8 +26,8 @@ extern int occlum_dup2(int old_fd, int new_fd);
|
|||||||
extern int occlum_dup3(int old_fd, int new_fd, int flags);
|
extern int occlum_dup3(int old_fd, int new_fd, 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, const char** envp,
|
||||||
const char** envp);
|
void* file_actions);
|
||||||
extern int occlum_wait4(int child_pid, int* status, int options/*, struct rusage* rusage*/);
|
extern int occlum_wait4(int child_pid, int* status, int options/*, struct rusage* rusage*/);
|
||||||
extern void occlum_exit(int status);
|
extern void occlum_exit(int status);
|
||||||
extern unsigned int occlum_getpid(void);
|
extern unsigned int occlum_getpid(void);
|
||||||
|
@ -78,8 +78,9 @@ fn do_boot(path_str: &str) -> Result<(), Error> {
|
|||||||
|
|
||||||
let argv = std::vec::Vec::new();
|
let argv = std::vec::Vec::new();
|
||||||
let envp = std::vec::Vec::new();
|
let envp = std::vec::Vec::new();
|
||||||
|
let file_actions = Vec::new();
|
||||||
let parent = &process::IDLE_PROCESS;
|
let parent = &process::IDLE_PROCESS;
|
||||||
process::do_spawn(&path_str, &argv, &envp, parent)?;
|
process::do_spawn(&path_str, &argv, &envp, &file_actions, parent)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ pub use self::task::{get_current, run_task};
|
|||||||
pub mod table {
|
pub mod table {
|
||||||
pub use super::process_table::{get};
|
pub use super::process_table::{get};
|
||||||
}
|
}
|
||||||
pub use self::spawn::{do_spawn};
|
pub use self::spawn::{do_spawn, FileAction};
|
||||||
pub use self::exit::{do_exit, do_wait4, ChildProcessFilter};
|
pub use self::exit::{do_exit, do_wait4, ChildProcessFilter};
|
||||||
pub use self::wait::{Waiter, WaitQueue};
|
pub use self::wait::{Waiter, WaitQueue};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use fs::{File, StdinFile, StdoutFile/*, StderrFile*/, FileTable};
|
use fs::{File, FileDesc, StdinFile, StdoutFile/*, StderrFile*/, FileTable};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::sgxfs::SgxFile;
|
use std::sgxfs::SgxFile;
|
||||||
@ -14,8 +14,16 @@ mod init_vm;
|
|||||||
mod elf_helper;
|
mod elf_helper;
|
||||||
mod segment;
|
mod segment;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum FileAction {
|
||||||
|
// TODO: Add open action
|
||||||
|
// Open(...)
|
||||||
|
Dup2(FileDesc, FileDesc),
|
||||||
|
Close(FileDesc),
|
||||||
|
}
|
||||||
|
|
||||||
pub fn do_spawn<P: AsRef<Path>>(elf_path: &P, argv: &[CString], envp: &[CString],
|
pub fn do_spawn<P: AsRef<Path>>(elf_path: &P, argv: &[CString], envp: &[CString],
|
||||||
parent_ref: &ProcessRef)
|
file_actions: &[FileAction], parent_ref: &ProcessRef)
|
||||||
-> Result<u32, Error>
|
-> Result<u32, Error>
|
||||||
{
|
{
|
||||||
let mut elf_buf = {
|
let mut elf_buf = {
|
||||||
@ -55,7 +63,7 @@ pub fn do_spawn<P: AsRef<Path>>(elf_path: &P, argv: &[CString], envp: &[CString]
|
|||||||
let stack_top = vm.get_stack_top();
|
let stack_top = vm.get_stack_top();
|
||||||
init_task(program_entry, stack_top, argv, envp)?
|
init_task(program_entry, stack_top, argv, envp)?
|
||||||
};
|
};
|
||||||
let files = init_files(parent_ref)?;
|
let files = init_files(parent_ref, file_actions)?;
|
||||||
let exec_path = elf_path.as_ref().to_str().unwrap();
|
let exec_path = elf_path.as_ref().to_str().unwrap();
|
||||||
Process::new(exec_path, task, vm, files)?
|
Process::new(exec_path, task, vm, files)?
|
||||||
};
|
};
|
||||||
@ -65,12 +73,29 @@ pub fn do_spawn<P: AsRef<Path>>(elf_path: &P, argv: &[CString], envp: &[CString]
|
|||||||
Ok(new_pid)
|
Ok(new_pid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_files(parent_ref: &ProcessRef) -> Result<FileTable, Error> {
|
fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction])
|
||||||
|
-> Result<FileTable, Error>
|
||||||
|
{
|
||||||
// Usually, we just inherit the file table from the parent
|
// Usually, we just inherit the file table from the parent
|
||||||
let parent = parent_ref.lock().unwrap();
|
let parent = parent_ref.lock().unwrap();
|
||||||
let should_inherit_file_table = parent.get_pid() > 0;
|
let should_inherit_file_table = parent.get_pid() > 0;
|
||||||
if should_inherit_file_table {
|
if should_inherit_file_table {
|
||||||
return Ok(parent.get_files().clone());
|
let mut cloned_file_table = parent.get_files().clone();
|
||||||
|
// Perform file actions to modify the cloned file table
|
||||||
|
for file_action in file_actions {
|
||||||
|
match file_action {
|
||||||
|
FileAction::Dup2(old_fd, new_fd) => {
|
||||||
|
let file = cloned_file_table.get(*old_fd)?;
|
||||||
|
if old_fd != new_fd {
|
||||||
|
cloned_file_table.put_at(*new_fd, file, false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FileAction::Close(fd) => {
|
||||||
|
cloned_file_table.del(*fd)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(cloned_file_table);
|
||||||
}
|
}
|
||||||
drop(parent);
|
drop(parent);
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
|
use std::{ptr};
|
||||||
use {std, fs, process, vm};
|
use {std, fs, process, vm};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use fs::{off_t, FileDesc};
|
use fs::{off_t, FileDesc};
|
||||||
use vm::{VMAreaFlags, VMResizeOptions};
|
use vm::{VMAreaFlags, VMResizeOptions};
|
||||||
use process::{pid_t, ChildProcessFilter};
|
use process::{pid_t, ChildProcessFilter, FileAction};
|
||||||
// Use the internal syscall wrappers from sgx_tstd
|
// Use the internal syscall wrappers from sgx_tstd
|
||||||
//use std::libc_fs as fs;
|
//use std::libc_fs as fs;
|
||||||
//use std::libc_io as io;
|
//use std::libc_io as io;
|
||||||
@ -413,19 +414,77 @@ pub extern "C" fn occlum_unknown(num: u32)
|
|||||||
println!("[WARNING] Unknown syscall (num = {})", num);
|
println!("[WARNING] Unknown syscall (num = {})", num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This Rust-version of fdop correspond to the C-version one in Occlum.
|
||||||
|
* See <path_to_musl_libc>/src/process/fdop.h.
|
||||||
|
*/
|
||||||
|
const FDOP_CLOSE : u32 = 1;
|
||||||
|
const FDOP_DUP2 : u32 = 2;
|
||||||
|
const FDOP_OPEN : u32 = 3;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FdOp {
|
||||||
|
// We actually switch the prev and next fields in the libc definition.
|
||||||
|
prev: *const FdOp,
|
||||||
|
next: *const FdOp,
|
||||||
|
cmd: u32,
|
||||||
|
fd: u32,
|
||||||
|
srcfd: u32,
|
||||||
|
oflag: u32,
|
||||||
|
mode: u32,
|
||||||
|
path: *const u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_file_actions_from_user_safely(fdop_ptr: *const FdOp)
|
||||||
|
-> Result<Vec<FileAction>, Error>
|
||||||
|
{
|
||||||
|
let mut file_actions = Vec::new();
|
||||||
|
|
||||||
|
let mut fdop_ptr = fdop_ptr;
|
||||||
|
while fdop_ptr != ptr::null() {
|
||||||
|
check_ptr_from_user(fdop_ptr)?;
|
||||||
|
let fdop = unsafe { &*fdop_ptr };
|
||||||
|
|
||||||
|
let file_action = match fdop.cmd {
|
||||||
|
FDOP_CLOSE => {
|
||||||
|
FileAction::Close(fdop.fd)
|
||||||
|
},
|
||||||
|
FDOP_DUP2 => {
|
||||||
|
FileAction::Dup2(fdop.srcfd, fdop.fd)
|
||||||
|
},
|
||||||
|
FDOP_OPEN => {
|
||||||
|
return errno!(EINVAL, "Not implemented");
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
return errno!(EINVAL, "Unknown file action command");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
file_actions.push(file_action);
|
||||||
|
|
||||||
|
fdop_ptr = fdop.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(file_actions)
|
||||||
|
}
|
||||||
|
|
||||||
fn do_spawn(child_pid_ptr: *mut c_uint,
|
fn do_spawn(child_pid_ptr: *mut c_uint,
|
||||||
path: *const c_char,
|
path: *const c_char,
|
||||||
argv: *const *const c_char,
|
argv: *const *const c_char,
|
||||||
envp: *const *const c_char)
|
envp: *const *const c_char,
|
||||||
|
fdop_list: *const FdOp,
|
||||||
|
)
|
||||||
-> Result<(), Error>
|
-> Result<(), Error>
|
||||||
{
|
{
|
||||||
check_mut_ptr_from_user(child_pid_ptr)?;
|
check_mut_ptr_from_user(child_pid_ptr)?;
|
||||||
let path = clone_cstring_from_user_safely(path)?;
|
let path = clone_cstring_from_user_safely(path)?;
|
||||||
let argv = clone_cstrings_from_user_safely(argv)?;
|
let argv = clone_cstrings_from_user_safely(argv)?;
|
||||||
let envp = clone_cstrings_from_user_safely(envp)?;
|
let envp = clone_cstrings_from_user_safely(envp)?;
|
||||||
|
let file_actions = clone_file_actions_from_user_safely(fdop_list)?;
|
||||||
let parent = process::get_current();
|
let parent = process::get_current();
|
||||||
|
|
||||||
let child_pid = process::do_spawn(&path, &argv, &envp, &parent)?;
|
let child_pid = process::do_spawn(&path, &argv, &envp, &file_actions, &parent)?;
|
||||||
|
|
||||||
unsafe { *child_pid_ptr = child_pid };
|
unsafe { *child_pid_ptr = child_pid };
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -434,9 +493,10 @@ fn do_spawn(child_pid_ptr: *mut c_uint,
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn occlum_spawn(
|
pub extern "C" fn occlum_spawn(
|
||||||
child_pid: *mut c_uint, path: *const c_char,
|
child_pid: *mut c_uint, path: *const c_char,
|
||||||
argv: *const *const c_char, envp: *const *const c_char) -> c_int
|
argv: *const *const c_char, envp: *const *const c_char,
|
||||||
|
fdop_list: *const FdOp) -> c_int
|
||||||
{
|
{
|
||||||
match do_spawn(child_pid, path, argv, envp) {
|
match do_spawn(child_pid, path, argv, envp, fdop_list) {
|
||||||
Ok(()) => 0,
|
Ok(()) => 0,
|
||||||
Err(e) => { e.errno.as_retval() }
|
Err(e) => { e.errno.as_retval() }
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,8 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
|
|||||||
DECL_SYSCALL_ARG(const char*, path, arg1);
|
DECL_SYSCALL_ARG(const char*, path, arg1);
|
||||||
DECL_SYSCALL_ARG(const char**, argv, arg2);
|
DECL_SYSCALL_ARG(const char**, argv, arg2);
|
||||||
DECL_SYSCALL_ARG(const char**, envp, arg3);
|
DECL_SYSCALL_ARG(const char**, envp, arg3);
|
||||||
ret = occlum_spawn(child_pid, path, argv, envp);
|
DECL_SYSCALL_ARG(void*, file_actions, arg4);
|
||||||
|
ret = occlum_spawn(child_pid, path, argv, envp, file_actions);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SYS_wait4: {
|
case SYS_wait4: {
|
||||||
|
@ -31,6 +31,7 @@ pub struct ProcessVM {
|
|||||||
heap_vma: VMArea,
|
heap_vma: VMArea,
|
||||||
stack_vma: VMArea,
|
stack_vma: VMArea,
|
||||||
mmap_vmas: Vec<Box<VMArea>>,
|
mmap_vmas: Vec<Box<VMArea>>,
|
||||||
|
brk: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessVM {
|
impl ProcessVM {
|
||||||
@ -46,6 +47,8 @@ impl ProcessVM {
|
|||||||
let (code_vma, data_vma, heap_vma, stack_vma) =
|
let (code_vma, data_vma, heap_vma, stack_vma) =
|
||||||
ProcessVM::alloc_vmas(&mut data_domain, code_size, data_size,
|
ProcessVM::alloc_vmas(&mut data_domain, code_size, data_size,
|
||||||
heap_size, stack_size)?;
|
heap_size, stack_size)?;
|
||||||
|
// Initial value of the program break
|
||||||
|
let brk = heap_vma.get_start();
|
||||||
// No mmapped vmas initially
|
// No mmapped vmas initially
|
||||||
let mmap_vmas = Vec::new();
|
let mmap_vmas = Vec::new();
|
||||||
|
|
||||||
@ -56,6 +59,7 @@ impl ProcessVM {
|
|||||||
heap_vma,
|
heap_vma,
|
||||||
stack_vma,
|
stack_vma,
|
||||||
mmap_vmas,
|
mmap_vmas,
|
||||||
|
brk,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +132,7 @@ impl ProcessVM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brk(&self) -> usize {
|
pub fn get_brk(&self) -> usize {
|
||||||
self.get_heap_vma().get_end()
|
self.brk
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_mmap_start(&self) -> usize {
|
pub fn get_mmap_start(&self) -> usize {
|
||||||
@ -196,17 +200,17 @@ impl ProcessVM {
|
|||||||
if new_brk == 0 {
|
if new_brk == 0 {
|
||||||
return Ok(self.get_brk());
|
return Ok(self.get_brk());
|
||||||
}
|
}
|
||||||
|
else if new_brk < self.heap_vma.get_start() {
|
||||||
|
return errno!(EINVAL, "New brk address is too low");
|
||||||
|
}
|
||||||
|
else if new_brk <= self.heap_vma.get_end() {
|
||||||
|
self.brk = new_brk;
|
||||||
|
return Ok(new_brk);
|
||||||
|
}
|
||||||
|
|
||||||
let resize_options = {
|
let resize_options = {
|
||||||
let brk_start = self.get_brk_start();
|
let brk_start = self.get_brk_start();
|
||||||
|
let new_heap_size = align_up(new_brk, 4096) - brk_start;
|
||||||
let new_heap_size = {
|
|
||||||
if new_brk < brk_start {
|
|
||||||
return Err(Error::new(Errno::EINVAL, "Invalid brk"));
|
|
||||||
}
|
|
||||||
new_brk - brk_start
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut options = VMResizeOptions::new(new_heap_size)?;
|
let mut options = VMResizeOptions::new(new_heap_size)?;
|
||||||
options.addr(VMAddrOption::Fixed(brk_start));
|
options.addr(VMAddrOption::Fixed(brk_start));
|
||||||
options
|
options
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
CUR_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
||||||
|
|
||||||
TEST_SUITES := empty hello_world malloc file getpid spawn
|
TEST_SUITES := empty hello_world malloc file getpid spawn pipe
|
||||||
BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
|
BUILD_TEST_SUITES := $(TEST_SUITES:%=%)
|
||||||
RUN_TEST_SUITES := $(TEST_SUITES:%=test-%)
|
RUN_TEST_SUITES := $(TEST_SUITES:%=test-%)
|
||||||
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)
|
CLEAN_TEST_SUITES := $(TEST_SUITES:%=clean-%)
|
||||||
|
@ -9,6 +9,11 @@ int main(void) {
|
|||||||
for (size_t buf_size = MIN_SIZE; buf_size <= MAX_SIZE; buf_size *= 4) {
|
for (size_t buf_size = MIN_SIZE; buf_size <= MAX_SIZE; buf_size *= 4) {
|
||||||
printf("buf_size = %lu\n", buf_size);
|
printf("buf_size = %lu\n", buf_size);
|
||||||
void* buf = malloc(buf_size);
|
void* buf = malloc(buf_size);
|
||||||
|
/* FIXME: why the first call to malloc always fail?
|
||||||
|
if (buf == NULL) {
|
||||||
|
printf("ERROR: failed to malloc for a buffer of %lu size\n", buf_size);
|
||||||
|
}
|
||||||
|
*/
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
printf("Done.\n");
|
printf("Done.\n");
|
||||||
|
4
test/pipe/Makefile
Normal file
4
test/pipe/Makefile
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS :=
|
||||||
|
EXTRA_LINK_FLAGS :=
|
53
test/pipe/main.c
Normal file
53
test/pipe/main.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
// XXX: this is a hack! remove this in the future
|
||||||
|
void* ptr = malloc(64);
|
||||||
|
free(ptr);
|
||||||
|
|
||||||
|
int pipe_fds[2];
|
||||||
|
if (pipe(pipe_fds) < 0) {
|
||||||
|
printf("ERROR: failed to create a pipe\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int pipe_rd_fd = pipe_fds[0];
|
||||||
|
int pipe_wr_fd = pipe_fds[1];
|
||||||
|
|
||||||
|
posix_spawn_file_actions_t file_actions;
|
||||||
|
posix_spawn_file_actions_init(&file_actions);
|
||||||
|
posix_spawn_file_actions_adddup2(&file_actions, pipe_wr_fd, STDOUT_FILENO);
|
||||||
|
posix_spawn_file_actions_addclose(&file_actions, pipe_rd_fd);
|
||||||
|
|
||||||
|
int child_pid;
|
||||||
|
if (posix_spawn(&child_pid, "hello_world/bin.encrypted", &file_actions,
|
||||||
|
NULL, NULL, NULL) < 0) {
|
||||||
|
printf("ERROR: failed to spawn a child process\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(pipe_wr_fd);
|
||||||
|
|
||||||
|
const char* expected_str = "Hello World\n";
|
||||||
|
size_t expected_len = strlen(expected_str);
|
||||||
|
char actual_str[32] = {0};
|
||||||
|
ssize_t actual_len;
|
||||||
|
do {
|
||||||
|
actual_len = read(pipe_rd_fd, actual_str, sizeof(actual_str) - 1);
|
||||||
|
} while (actual_len == 0);
|
||||||
|
if (strncmp(expected_str, actual_str, expected_len) != 0) {
|
||||||
|
printf("ERROR: received string is not as expected\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = 0;
|
||||||
|
if (wait4(child_pid, &status, 0, NULL) < 0) {
|
||||||
|
printf("ERROR: failed to wait4 the child process\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user