Add clone system call
This commit is contained in:
parent
684f0df286
commit
4cf8777592
@ -56,7 +56,7 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
|
|||||||
|
|
||||||
let fd = {
|
let fd = {
|
||||||
let close_on_spawn = flags.contains(OpenFlags::CLOEXEC);
|
let close_on_spawn = flags.contains(OpenFlags::CLOEXEC);
|
||||||
proc.get_files_mut().put(file_ref, close_on_spawn)
|
proc.get_files().lock().unwrap().put(file_ref, close_on_spawn)
|
||||||
};
|
};
|
||||||
Ok(fd)
|
Ok(fd)
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize, Error> {
|
|||||||
info!("write: fd: {}", fd);
|
info!("write: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.write(buf)
|
file_ref.write(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +73,7 @@ pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
|||||||
info!("read: fd: {}", fd);
|
info!("read: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.read(buf)
|
file_ref.read(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize, Error> {
|
|||||||
info!("writev: fd: {}", fd);
|
info!("writev: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.writev(bufs)
|
file_ref.writev(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize, Error> {
|
|||||||
info!("readv: fd: {}", fd);
|
info!("readv: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.readv(bufs)
|
file_ref.readv(bufs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize, Error
|
|||||||
info!("pwrite: fd: {}, offset: {}", fd, offset);
|
info!("pwrite: fd: {}, offset: {}", fd, offset);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.write_at(offset, buf)
|
file_ref.write_at(offset, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize, Er
|
|||||||
info!("pread: fd: {}, offset: {}", fd, offset);
|
info!("pread: fd: {}, offset: {}", fd, offset);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.read_at(offset, buf)
|
file_ref.read_at(offset, buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ pub fn do_fstat(fd: u32) -> Result<Stat, Error> {
|
|||||||
info!("fstat: fd: {}", fd);
|
info!("fstat: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
let stat = Stat::from(file_ref.metadata()?);
|
let stat = Stat::from(file_ref.metadata()?);
|
||||||
// TODO: handle symlink
|
// TODO: handle symlink
|
||||||
Ok(stat)
|
Ok(stat)
|
||||||
@ -137,7 +137,7 @@ pub fn do_lstat(path: &str) -> Result<Stat, Error> {
|
|||||||
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
|
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.seek(offset)
|
file_ref.seek(offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ pub fn do_fsync(fd: FileDesc) -> Result<(), Error> {
|
|||||||
info!("fsync: fd: {}", fd);
|
info!("fsync: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.sync_all()?;
|
file_ref.sync_all()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -154,7 +154,7 @@ pub fn do_fdatasync(fd: FileDesc) -> Result<(), Error> {
|
|||||||
info!("fdatasync: fd: {}", fd);
|
info!("fdatasync: fd: {}", fd);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.sync_data()?;
|
file_ref.sync_data()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<(), Error> {
|
|||||||
info!("ftruncate: fd: {}, len: {}", fd, len);
|
info!("ftruncate: fd: {}, len: {}", fd, len);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
file_ref.set_len(len as u64)?;
|
file_ref.set_len(len as u64)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -185,7 +185,7 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
|||||||
);
|
);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_ref = current_process.get_files().get(fd)?;
|
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
||||||
let info = file_ref.metadata()?;
|
let info = file_ref.metadata()?;
|
||||||
if info.type_ != FileType::Dir {
|
if info.type_ != FileType::Dir {
|
||||||
return Err(Error::new(ENOTDIR, ""));
|
return Err(Error::new(ENOTDIR, ""));
|
||||||
@ -207,8 +207,9 @@ pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize, Error> {
|
|||||||
|
|
||||||
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
|
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let file_table = current_process.get_files_mut();
|
let file_table_ref = current_process.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
file_table.del(fd)?;
|
file_table.del(fd)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -216,10 +217,11 @@ pub fn do_close(fd: FileDesc) -> Result<(), Error> {
|
|||||||
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
|
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
|
||||||
let flags = OpenFlags::from_bits_truncate(flags);
|
let flags = OpenFlags::from_bits_truncate(flags);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let current = current_ref.lock().unwrap();
|
||||||
let pipe = Pipe::new()?;
|
let pipe = Pipe::new()?;
|
||||||
|
|
||||||
let mut file_table = current.get_files_mut();
|
let file_table_ref = current.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
let close_on_spawn = flags.contains(OpenFlags::CLOEXEC);
|
let close_on_spawn = flags.contains(OpenFlags::CLOEXEC);
|
||||||
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn);
|
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);
|
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn);
|
||||||
@ -228,8 +230,9 @@ pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2], Error> {
|
|||||||
|
|
||||||
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> {
|
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let current = current_ref.lock().unwrap();
|
||||||
let file_table = current.get_files_mut();
|
let file_table_ref = current.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
let file = file_table.get(old_fd)?;
|
let file = file_table.get(old_fd)?;
|
||||||
let new_fd = file_table.put(file, false);
|
let new_fd = file_table.put(file, false);
|
||||||
Ok(new_fd)
|
Ok(new_fd)
|
||||||
@ -237,8 +240,9 @@ pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc, Error> {
|
|||||||
|
|
||||||
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> {
|
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> {
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let current = current_ref.lock().unwrap();
|
||||||
let file_table = current.get_files_mut();
|
let file_table_ref = current.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
let file = file_table.get(old_fd)?;
|
let file = file_table.get(old_fd)?;
|
||||||
if old_fd != new_fd {
|
if old_fd != new_fd {
|
||||||
file_table.put_at(new_fd, file, false);
|
file_table.put_at(new_fd, file, false);
|
||||||
@ -249,8 +253,9 @@ pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc, Error> {
|
|||||||
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc, Error> {
|
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc, Error> {
|
||||||
let flags = OpenFlags::from_bits_truncate(flags);
|
let flags = OpenFlags::from_bits_truncate(flags);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let current = current_ref.lock().unwrap();
|
||||||
let file_table = current.get_files_mut();
|
let file_table_ref = current.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
let file = file_table.get(old_fd)?;
|
let file = file_table.get(old_fd)?;
|
||||||
if old_fd == new_fd {
|
if old_fd == new_fd {
|
||||||
return errno!(EINVAL, "old_fd must not be equal to new_fd");
|
return errno!(EINVAL, "old_fd must not be equal to new_fd");
|
||||||
|
@ -6,6 +6,7 @@ pub mod table {
|
|||||||
pub use self::exit::{do_exit, do_wait4, ChildProcessFilter};
|
pub use self::exit::{do_exit, do_wait4, ChildProcessFilter};
|
||||||
pub use self::spawn::{do_spawn, FileAction};
|
pub use self::spawn::{do_spawn, FileAction};
|
||||||
pub use self::wait::{WaitQueue, Waiter};
|
pub use self::wait::{WaitQueue, Waiter};
|
||||||
|
pub use self::thread::{do_clone, CloneFlags, ThreadGroup};
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type pid_t = u32;
|
pub type pid_t = u32;
|
||||||
@ -18,16 +19,20 @@ pub struct Process {
|
|||||||
pgid: pid_t,
|
pgid: pid_t,
|
||||||
tgid: pid_t,
|
tgid: pid_t,
|
||||||
exit_status: i32,
|
exit_status: i32,
|
||||||
|
// TODO: move cwd, root_inode into a FileSystem structure
|
||||||
|
// TODO: should cwd be a String or INode?
|
||||||
cwd: String,
|
cwd: String,
|
||||||
parent: Option<ProcessRef>,
|
parent: Option<ProcessRef>,
|
||||||
children: Vec<ProcessWeakRef>,
|
children: Vec<ProcessWeakRef>,
|
||||||
waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>,
|
waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>,
|
||||||
vm: ProcessVM,
|
vm: ProcessVMRef,
|
||||||
file_table: FileTable,
|
file_table: FileTableRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ProcessRef = Arc<SgxMutex<Process>>;
|
pub type ProcessRef = Arc<SgxMutex<Process>>;
|
||||||
pub type ProcessWeakRef = std::sync::Weak<SgxMutex<Process>>;
|
pub type ProcessWeakRef = std::sync::Weak<SgxMutex<Process>>;
|
||||||
|
pub type FileTableRef = Arc<SgxMutex<FileTable>>;
|
||||||
|
pub type ProcessVMRef = Arc<SgxMutex<ProcessVM>>;
|
||||||
|
|
||||||
pub fn do_getpid() -> pid_t {
|
pub fn do_getpid() -> pid_t {
|
||||||
let current_ref = get_current();
|
let current_ref = get_current();
|
||||||
@ -57,6 +62,7 @@ mod process_table;
|
|||||||
mod spawn;
|
mod spawn;
|
||||||
mod task;
|
mod task;
|
||||||
mod wait;
|
mod wait;
|
||||||
|
mod thread;
|
||||||
|
|
||||||
use self::task::Task;
|
use self::task::Task;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -27,8 +27,8 @@ impl Process {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
cwd: &str,
|
cwd: &str,
|
||||||
task: Task,
|
task: Task,
|
||||||
vm: ProcessVM,
|
vm_ref: ProcessVMRef,
|
||||||
file_table: FileTable,
|
file_table_ref: FileTableRef,
|
||||||
) -> Result<(pid_t, ProcessRef), Error> {
|
) -> Result<(pid_t, ProcessRef), Error> {
|
||||||
let new_pid = process_table::alloc_pid();
|
let new_pid = process_table::alloc_pid();
|
||||||
let new_process_ref = Arc::new(SgxMutex::new(Process {
|
let new_process_ref = Arc::new(SgxMutex::new(Process {
|
||||||
@ -42,8 +42,8 @@ impl Process {
|
|||||||
parent: None,
|
parent: None,
|
||||||
children: Vec::new(),
|
children: Vec::new(),
|
||||||
waiting_children: None,
|
waiting_children: None,
|
||||||
vm: vm,
|
vm: vm_ref,
|
||||||
file_table: file_table,
|
file_table: file_table_ref,
|
||||||
}));
|
}));
|
||||||
Ok((new_pid, new_process_ref))
|
Ok((new_pid, new_process_ref))
|
||||||
}
|
}
|
||||||
@ -72,18 +72,12 @@ impl Process {
|
|||||||
pub fn get_cwd(&self) -> &str {
|
pub fn get_cwd(&self) -> &str {
|
||||||
&self.cwd
|
&self.cwd
|
||||||
}
|
}
|
||||||
pub fn get_vm(&self) -> &ProcessVM {
|
pub fn get_vm(&self) -> &ProcessVMRef {
|
||||||
&self.vm
|
&self.vm
|
||||||
}
|
}
|
||||||
pub fn get_vm_mut(&mut self) -> &mut ProcessVM {
|
pub fn get_files(&self) -> &FileTableRef {
|
||||||
&mut self.vm
|
|
||||||
}
|
|
||||||
pub fn get_files(&self) -> &FileTable {
|
|
||||||
&self.file_table
|
&self.file_table
|
||||||
}
|
}
|
||||||
pub fn get_files_mut(&mut self) -> &mut FileTable {
|
|
||||||
&mut self.file_table
|
|
||||||
}
|
|
||||||
pub fn get_parent(&self) -> &ProcessRef {
|
pub fn get_parent(&self) -> &ProcessRef {
|
||||||
self.parent.as_ref().unwrap()
|
self.parent.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ pub fn do_spawn<P: AsRef<Path>>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let (new_pid, new_process_ref) = {
|
let (new_pid, new_process_ref) = {
|
||||||
|
let cwd = elf_path.as_ref().parent().unwrap().to_str().unwrap();
|
||||||
let vm = init_vm::do_init(&elf_file, &elf_buf[..])?;
|
let vm = init_vm::do_init(&elf_file, &elf_buf[..])?;
|
||||||
let task = {
|
let task = {
|
||||||
let program_entry = {
|
let program_entry = {
|
||||||
@ -64,9 +65,12 @@ pub fn do_spawn<P: AsRef<Path>>(
|
|||||||
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 vm_ref = Arc::new(SgxMutex::new(vm));
|
||||||
|
let files_ref = {
|
||||||
let files = init_files(parent_ref, file_actions)?;
|
let files = init_files(parent_ref, file_actions)?;
|
||||||
let cwd = elf_path.as_ref().parent().unwrap().to_str().unwrap();
|
Arc::new(SgxMutex::new(files))
|
||||||
Process::new(cwd, task, vm, files)?
|
};
|
||||||
|
Process::new(cwd, task, vm_ref, files_ref)?
|
||||||
};
|
};
|
||||||
parent_adopts_new_child(&parent_ref, &new_process_ref);
|
parent_adopts_new_child(&parent_ref, &new_process_ref);
|
||||||
process_table::put(new_pid, new_process_ref.clone());
|
process_table::put(new_pid, new_process_ref.clone());
|
||||||
@ -79,7 +83,7 @@ fn init_files(parent_ref: &ProcessRef, file_actions: &[FileAction]) -> Result<Fi
|
|||||||
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 {
|
||||||
let mut cloned_file_table = parent.get_files().clone();
|
let mut cloned_file_table = parent.get_files().lock().unwrap().clone();
|
||||||
// Perform file actions to modify the cloned file table
|
// Perform file actions to modify the cloned file table
|
||||||
for file_action in file_actions {
|
for file_action in file_actions {
|
||||||
match file_action {
|
match file_action {
|
||||||
|
84
src/libos/src/process/thread.rs
Normal file
84
src/libos/src/process/thread.rs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub struct ThreadGroup {
|
||||||
|
threads: Vec<ProcessRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
pub struct CloneFlags : u32 {
|
||||||
|
const CLONE_VM = 0x00000100;
|
||||||
|
const CLONE_FS = 0x00000200;
|
||||||
|
const CLONE_FILES = 0x00000400;
|
||||||
|
const CLONE_SIGHAND = 0x00000800;
|
||||||
|
const CLONE_PTRACE = 0x00002000;
|
||||||
|
const CLONE_VFORK = 0x00004000;
|
||||||
|
const CLONE_PARENT = 0x00008000;
|
||||||
|
const CLONE_THREAD = 0x00010000;
|
||||||
|
const CLONE_NEWNS = 0x00020000;
|
||||||
|
const CLONE_SYSVSEM = 0x00040000;
|
||||||
|
const CLONE_SETTLS = 0x00080000;
|
||||||
|
const CLONE_PARENT_SETTID = 0x00100000;
|
||||||
|
const CLONE_CHILD_CLEARTID = 0x00200000;
|
||||||
|
const CLONE_DETACHED = 0x00400000;
|
||||||
|
const CLONE_UNTRACED = 0x00800000;
|
||||||
|
const CLONE_CHILD_SETTID = 0x01000000;
|
||||||
|
const CLONE_NEWCGROUP = 0x02000000;
|
||||||
|
const CLONE_NEWUTS = 0x04000000;
|
||||||
|
const CLONE_NEWIPC = 0x08000000;
|
||||||
|
const CLONE_NEWUSER = 0x10000000;
|
||||||
|
const CLONE_NEWPID = 0x20000000;
|
||||||
|
const CLONE_NEWNET = 0x40000000;
|
||||||
|
const CLONE_IO = 0x80000000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_clone(
|
||||||
|
flags: CloneFlags,
|
||||||
|
stack_addr: usize,
|
||||||
|
ptid: Option<*mut i32>,
|
||||||
|
ctid: Option<*mut i32>,
|
||||||
|
new_tls: usize
|
||||||
|
) -> Result<pid_t, Error> {
|
||||||
|
info!("clone: flags: {:?}, stack_addr: {:?}, ptid: {:?}, ctid: {:?}, new_tls: {:?}",
|
||||||
|
flags, stack_addr, ptid, ctid, new_tls);
|
||||||
|
|
||||||
|
let current_ref = get_current();
|
||||||
|
let current = current_ref.lock().unwrap();
|
||||||
|
|
||||||
|
let (new_thread_pid, new_thread_ref) = {
|
||||||
|
let task = new_thread_task(stack_addr, new_tls)?;
|
||||||
|
let vm_ref = current.get_vm().clone();
|
||||||
|
let files_ref = current.get_files().clone();
|
||||||
|
let cwd = ¤t.cwd;
|
||||||
|
Process::new(cwd, task, vm_ref, files_ref)?
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: always get parent lock first to avoid deadlock
|
||||||
|
{
|
||||||
|
let parent_ref = current.parent.as_ref().unwrap();
|
||||||
|
let mut parent = parent_ref.lock().unwrap();
|
||||||
|
let mut new_thread = new_thread_ref.lock().unwrap();
|
||||||
|
parent.children.push(Arc::downgrade(&new_thread_ref));
|
||||||
|
new_thread.parent = Some(parent_ref.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
process_table::put(new_thread_pid, new_thread_ref.clone());
|
||||||
|
task::enqueue_task(new_thread_ref);
|
||||||
|
Ok(new_thread_pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_thread_task(user_stack: usize, new_tls: usize) -> Result<Task, Error> {
|
||||||
|
// The calling convention of Occlum clone syscall requires the user to
|
||||||
|
// restore the entry point of the new thread at the top of the user stack.
|
||||||
|
let user_entry = unsafe {
|
||||||
|
*(user_stack as *mut usize)
|
||||||
|
// TODO: check user_entry is a cfi_label
|
||||||
|
};
|
||||||
|
Ok(Task {
|
||||||
|
user_stack_addr: user_stack,
|
||||||
|
user_entry_addr: user_entry,
|
||||||
|
user_fsbase_addr: new_tls,
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
@ -2,7 +2,7 @@ use {fs, process, std, vm};
|
|||||||
use fs::{FileDesc, off_t};
|
use fs::{FileDesc, off_t};
|
||||||
use fs::File;
|
use fs::File;
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use process::{ChildProcessFilter, FileAction, pid_t};
|
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use time::timeval_t;
|
use time::timeval_t;
|
||||||
@ -79,6 +79,13 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
arg3 as *const *const i8,
|
arg3 as *const *const i8,
|
||||||
arg4 as *const FdOp,
|
arg4 as *const FdOp,
|
||||||
),
|
),
|
||||||
|
SYS_CLONE => do_clone(
|
||||||
|
arg0 as u32,
|
||||||
|
arg1 as usize,
|
||||||
|
arg2 as *mut i32,
|
||||||
|
arg3 as *mut i32,
|
||||||
|
arg4 as usize,
|
||||||
|
),
|
||||||
SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32),
|
SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32),
|
||||||
SYS_GETPID => do_getpid(),
|
SYS_GETPID => do_getpid(),
|
||||||
SYS_GETPPID => do_getppid(),
|
SYS_GETPPID => do_getppid(),
|
||||||
@ -197,6 +204,40 @@ fn do_spawn(
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn do_clone(
|
||||||
|
flags: u32,
|
||||||
|
stack_addr: usize,
|
||||||
|
ptid: *mut i32,
|
||||||
|
ctid: *mut i32,
|
||||||
|
new_tls: usize,
|
||||||
|
) -> Result<isize, Error> {
|
||||||
|
let flags = CloneFlags::from_bits_truncate(flags);
|
||||||
|
check_mut_ptr(stack_addr as *mut u64)?;
|
||||||
|
let ptid = {
|
||||||
|
if ptid != ptr::null_mut() {
|
||||||
|
check_mut_ptr(ptid)?;
|
||||||
|
Some(ptid)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let ctid = {
|
||||||
|
if ctid != ptr::null_mut() {
|
||||||
|
check_mut_ptr(ctid)?;
|
||||||
|
Some(ctid)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
check_mut_ptr(new_tls as *mut u64)?;
|
||||||
|
|
||||||
|
let child_pid = process::do_clone(flags, stack_addr, ptid, ctid, new_tls)?;
|
||||||
|
|
||||||
|
Ok(child_pid as isize)
|
||||||
|
}
|
||||||
|
|
||||||
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize, Error> {
|
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize, Error> {
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
||||||
let fd = fs::do_open(&path, flags, mode)?;
|
let fd = fs::do_open(&path, flags, mode)?;
|
||||||
|
@ -19,15 +19,17 @@ pub use self::vm_range::{VMRange, VMRangeTrait};
|
|||||||
// TODO: accept fd and offset
|
// TODO: accept fd and offset
|
||||||
pub fn do_mmap(addr: usize, size: usize, flags: VMAreaFlags) -> Result<usize, Error> {
|
pub fn do_mmap(addr: usize, size: usize, flags: VMAreaFlags) -> Result<usize, Error> {
|
||||||
let current_ref = get_current();
|
let current_ref = get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let current_vm = current_process.get_vm_mut();
|
let current_vm_ref = current_process.get_vm();
|
||||||
|
let mut current_vm = current_vm_ref.lock().unwrap();
|
||||||
current_vm.mmap(addr, size, flags)
|
current_vm.mmap(addr, size, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_munmap(addr: usize, size: usize) -> Result<(), Error> {
|
pub fn do_munmap(addr: usize, size: usize) -> Result<(), Error> {
|
||||||
let current_ref = get_current();
|
let current_ref = get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let current_vm = current_process.get_vm_mut();
|
let current_vm_ref = current_process.get_vm();
|
||||||
|
let mut current_vm = current_vm_ref.lock().unwrap();
|
||||||
current_vm.munmap(addr, size)
|
current_vm.munmap(addr, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,15 +40,17 @@ pub fn do_mremap(
|
|||||||
options: &VMResizeOptions,
|
options: &VMResizeOptions,
|
||||||
) -> Result<usize, Error> {
|
) -> Result<usize, Error> {
|
||||||
let current_ref = get_current();
|
let current_ref = get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let current_vm = current_process.get_vm_mut();
|
let current_vm_ref = current_process.get_vm();
|
||||||
|
let mut current_vm = current_vm_ref.lock().unwrap();
|
||||||
current_vm.mremap(old_addr, old_size, options)
|
current_vm.mremap(old_addr, old_size, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_brk(addr: usize) -> Result<usize, Error> {
|
pub fn do_brk(addr: usize) -> Result<usize, Error> {
|
||||||
let current_ref = get_current();
|
let current_ref = get_current();
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
let current_process = current_ref.lock().unwrap();
|
||||||
let current_vm = current_process.get_vm_mut();
|
let current_vm_ref = current_process.get_vm();
|
||||||
|
let mut current_vm = current_vm_ref.lock().unwrap();
|
||||||
current_vm.brk(addr)
|
current_vm.brk(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
|||||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||||
TEST_DEPS := dev_null
|
TEST_DEPS := dev_null
|
||||||
# Tests: need to be compiled and run by test-% target
|
# Tests: need to be compiled and run by test-% target
|
||||||
TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link
|
TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link clone
|
||||||
# Benchmarks: need to be compiled and run by bench-% target
|
# Benchmarks: need to be compiled and run by bench-% target
|
||||||
BENCHES := spawn_and_exit_latency pipe_throughput
|
BENCHES := spawn_and_exit_latency pipe_throughput
|
||||||
|
|
||||||
|
5
test/clone/Makefile
Normal file
5
test/clone/Makefile
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include ../test_common.mk
|
||||||
|
|
||||||
|
EXTRA_C_FLAGS :=
|
||||||
|
EXTRA_LINK_FLAGS :=
|
||||||
|
BIN_ARGS :=
|
54
test/clone/main.c
Normal file
54
test/clone/main.c
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <sched.h>
|
||||||
|
|
||||||
|
#define NTHREADS 4
|
||||||
|
#define STACK_SIZE (8 * 1024)
|
||||||
|
|
||||||
|
// From file arch/x86_64/atomic_arch.h in musl libc. MIT License.
|
||||||
|
static inline void a_inc(volatile int *p)
|
||||||
|
{
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"lock ; incl %0"
|
||||||
|
: "=m"(*p) : "m"(*p) : "memory" );
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile int num_exit_threads = 0;
|
||||||
|
|
||||||
|
int thread_func(void* arg) {
|
||||||
|
int* tid = arg;
|
||||||
|
//printf("tid = %d\n", *tid);
|
||||||
|
a_inc(&num_exit_threads);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char* argv[]) {
|
||||||
|
unsigned int clone_flags = CLONE_VM | CLONE_FS | CLONE_FILES |
|
||||||
|
CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED;
|
||||||
|
|
||||||
|
printf("Creating %d threads...", NTHREADS);
|
||||||
|
int thread_ids[NTHREADS];
|
||||||
|
for (int tid = 0; tid < NTHREADS; tid++) {
|
||||||
|
void* thread_stack = malloc(STACK_SIZE);
|
||||||
|
if (thread_stack == NULL) {
|
||||||
|
printf("ERROR: malloc failed for thread %d\n", tid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_ids[tid] = tid;
|
||||||
|
void* thread_arg = &thread_ids[tid];
|
||||||
|
if (clone(thread_func, thread_stack, clone_flags, thread_arg) < 0) {
|
||||||
|
printf("ERROR: clone failed for thread %d\n", tid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("done.\n");
|
||||||
|
|
||||||
|
printf("Waiting for %d threads to exit...", NTHREADS);
|
||||||
|
// Wait for all threads to exit
|
||||||
|
while (num_exit_threads != NTHREADS);
|
||||||
|
printf("done.\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -9,7 +9,7 @@ S_FILES := $(C_SRCS:%.c=%.S)
|
|||||||
C_OBJS := $(C_SRCS:%.c=%.o)
|
C_OBJS := $(C_SRCS:%.c=%.o)
|
||||||
FS_PATH := ../fs
|
FS_PATH := ../fs
|
||||||
BIN_NAME := $(shell basename $(CUR_DIR))
|
BIN_NAME := $(shell basename $(CUR_DIR))
|
||||||
BIN_FS_PATH := /$(BIN_NAME)
|
BIN_FS_PATH := $(BIN_NAME)
|
||||||
BIN_PATH := $(FS_PATH)/$(BIN_FS_PATH)
|
BIN_PATH := $(FS_PATH)/$(BIN_FS_PATH)
|
||||||
OBJDUMP_FILE := bin.objdump
|
OBJDUMP_FILE := bin.objdump
|
||||||
READELF_FILE := bin.readelf
|
READELF_FILE := bin.readelf
|
||||||
|
Loading…
Reference in New Issue
Block a user