Merge remote-tracking branch 'official/master' into net
# Conflicts: # src/libos/src/fs/mod.rs # src/libos/src/syscall/mod.rs # test/Makefile
This commit is contained in:
		
						commit
						b5697ab611
					
				
							
								
								
									
										52
									
								
								src/libos/src/fs/access.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										52
									
								
								src/libos/src/fs/access.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| //int faccessat(int dirfd, const char *pathname, int mode, int flags);
 | ||||
| //int access(const char *pathname, int mode);
 | ||||
| 
 | ||||
| bitflags! { | ||||
|     pub struct AccessModes : u32 { | ||||
|         const X_OK = 1; | ||||
|         const W_OK = 2; | ||||
|         const R_OK = 4; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl AccessModes { | ||||
|     pub fn from_u32(bits: u32) -> Result<AccessModes, Error> { | ||||
|         AccessModes::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid mode")) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| bitflags! { | ||||
|     pub struct AccessFlags : u32 { | ||||
|         const AT_SYMLINK_NOFOLLOW = 0x100; | ||||
|         const AT_EACCESS          = 0x200; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl AccessFlags { | ||||
|     pub fn from_u32(bits: u32) -> Result<AccessFlags, Error> { | ||||
|         AccessFlags::from_bits(bits).ok_or_else(|| Error::new(Errno::EINVAL, "invalid flags")) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub const AT_FDCWD : i32 = -100; | ||||
| 
 | ||||
| pub fn do_faccessat(dirfd: Option<FileDesc>, path: &str, mode: AccessModes, flags: AccessFlags) -> Result<(), Error> { | ||||
|     match dirfd { | ||||
|         // TODO: handle dirfd
 | ||||
|         Some(dirfd) => errno!(ENOSYS, "cannot accept dirfd"), | ||||
|         None => do_access(path, mode), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn do_access(path: &str, mode: AccessModes) -> Result<(), Error> { | ||||
|     let current_ref = process::get_current(); | ||||
|     let mut current = current_ref.lock().unwrap(); | ||||
|     let inode = current.lookup_inode(path)?; | ||||
|     //let metadata = inode.get_metadata();
 | ||||
|     // TODO: check metadata.mode with mode
 | ||||
|     Ok(()) | ||||
| } | ||||
| @ -11,12 +11,6 @@ pub struct FileTable { | ||||
|     num_fds: usize, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| struct FileTableEntry { | ||||
|     file: FileRef, | ||||
|     close_on_spawn: bool, | ||||
| } | ||||
| 
 | ||||
| impl FileTable { | ||||
|     pub fn new() -> FileTable { | ||||
|         FileTable { | ||||
| @ -25,12 +19,38 @@ impl FileTable { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn dup(&mut self, fd: FileDesc, min_fd: FileDesc, close_on_spawn: bool) -> Result<FileDesc, Error> { | ||||
|         let file_ref = self.get(fd)?; | ||||
| 
 | ||||
|         let min_fd = min_fd as usize; | ||||
|         let min_free_fd = { | ||||
|             let mut table = &mut self.table; | ||||
| 
 | ||||
|             // Make sure that min_fd does not exceed the capacity of the table
 | ||||
|             if min_fd >= table.len() { | ||||
|                 let expand_size = min_fd - table.len() + 1; | ||||
|                 for _ in 0..expand_size { | ||||
|                     table.push(None) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             table.iter() | ||||
|                 .enumerate() | ||||
|                 .skip(min_fd as usize) | ||||
|                 .find(|&(idx, opt)| opt.is_none()) | ||||
|                 .unwrap().0 | ||||
|         } as FileDesc; | ||||
| 
 | ||||
|         self.put_at(min_free_fd, file_ref, close_on_spawn); | ||||
| 
 | ||||
|         Ok(min_free_fd) | ||||
|     } | ||||
| 
 | ||||
|     pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { | ||||
|         let mut table = &mut self.table; | ||||
| 
 | ||||
|         let min_free_fd = if self.num_fds < table.len() { | ||||
|             table | ||||
|                 .iter() | ||||
|             table.iter() | ||||
|                 .enumerate() | ||||
|                 .find(|&(idx, opt)| opt.is_none()) | ||||
|                 .unwrap() | ||||
| @ -59,13 +79,30 @@ impl FileTable { | ||||
|     } | ||||
| 
 | ||||
|     pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { | ||||
|         let entry = self.get_entry(fd)?; | ||||
|         Ok(entry.file.clone()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_entry(&self, fd: FileDesc) -> Result<&FileTableEntry, Error> { | ||||
|         if fd as usize >= self.table.len() { | ||||
|             return errno!(EBADF, "Invalid file descriptor"); | ||||
|         } | ||||
| 
 | ||||
|         let table = &self.table; | ||||
|         match table[fd as usize].as_ref() { | ||||
|             Some(table_entry) => Ok(table_entry.file.clone()), | ||||
|             Some(table_entry) => Ok(table_entry), | ||||
|             None => errno!(EBADF, "Invalid file descriptor"), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_entry_mut(&mut self, fd: FileDesc) -> Result<&mut FileTableEntry, Error> { | ||||
|         if fd as usize >= self.table.len() { | ||||
|             return errno!(EBADF, "Invalid file descriptor"); | ||||
|         } | ||||
| 
 | ||||
|         let table = &mut self.table; | ||||
|         match table[fd as usize].as_mut() { | ||||
|             Some(table_entry) => Ok(table_entry), | ||||
|             None => errno!(EBADF, "Invalid file descriptor"), | ||||
|         } | ||||
|     } | ||||
| @ -114,11 +151,33 @@ impl Clone for FileTable { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct FileTableEntry { | ||||
|     file: FileRef, | ||||
|     close_on_spawn: bool, | ||||
| } | ||||
| 
 | ||||
| impl FileTableEntry { | ||||
|     fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||
|     pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||
|         FileTableEntry { | ||||
|             file, | ||||
|             close_on_spawn, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_file(&self) -> &FileRef { | ||||
|         &self.file | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_close_on_spawn(&self) -> bool { | ||||
|         self.close_on_spawn | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_file_mut(&mut self) -> &mut FileRef { | ||||
|         &mut self.file | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_close_on_spawn(&mut self, close_on_spawn: bool) { | ||||
|         self.close_on_spawn = close_on_spawn; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -13,6 +13,7 @@ pub use self::socket_file::SocketFile; | ||||
| use self::inode_file::OpenOptions; | ||||
| pub use self::pipe::Pipe; | ||||
| pub use self::io_multiplexing::*; | ||||
| pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; | ||||
| 
 | ||||
| mod file; | ||||
| mod file_table; | ||||
| @ -21,6 +22,7 @@ mod socket_file; | ||||
| mod pipe; | ||||
| mod sgx_impl; | ||||
| mod io_multiplexing; | ||||
| mod access; | ||||
| 
 | ||||
| 
 | ||||
| pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> { | ||||
| @ -387,7 +389,7 @@ fn split_path(path: &str) -> (&str, &str) { | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     struct OpenFlags: u32 { | ||||
|     pub struct OpenFlags: u32 { | ||||
|         /// read only
 | ||||
|         const RDONLY = 0; | ||||
|         /// write only
 | ||||
| @ -611,3 +613,89 @@ pub unsafe fn write_cstr(ptr: *mut u8, s: &str) { | ||||
|     ptr.copy_from(s.as_ptr(), s.len()); | ||||
|     ptr.add(s.len()).write(0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub enum FcntlCmd { | ||||
|     /// Duplicate the file descriptor fd using the lowest-numbered available
 | ||||
|     /// file descriptor greater than or equal to arg.
 | ||||
|     DupFd(FileDesc), | ||||
|     /// As for `DupFd`, but additionally set the close-on-exec flag for the
 | ||||
|     /// duplicate file descriptor.
 | ||||
|     DupFdCloexec(FileDesc), | ||||
|     /// Return (as the function result) the file descriptor flags
 | ||||
|     GetFd(), | ||||
|     /// Set the file descriptor to be close-on-exec or not
 | ||||
|     SetFd(u32), | ||||
|     /// Get the file status flags
 | ||||
|     GetFl(), | ||||
|     /// Set the file status flags
 | ||||
|     SetFl(OpenFlags), | ||||
| } | ||||
| 
 | ||||
| pub const F_DUPFD : u32             = 0; | ||||
| pub const F_GETFD : u32             = 1; | ||||
| pub const F_SETFD : u32             = 2; | ||||
| pub const F_GETFL : u32             = 3; | ||||
| pub const F_SETFL : u32             = 4; | ||||
| pub const F_DUPFD_CLOEXEC : u32     = 1030; | ||||
| 
 | ||||
| pub const FD_CLOEXEC : u32          = 1; | ||||
| 
 | ||||
| impl FcntlCmd { | ||||
|     #[deny(unreachable_patterns)] | ||||
|     pub fn from_raw(cmd: u32, arg: u64) -> Result<FcntlCmd, Error> { | ||||
|         Ok(match cmd { | ||||
|             F_DUPFD => FcntlCmd::DupFd(arg as FileDesc), | ||||
|             F_DUPFD_CLOEXEC => FcntlCmd::DupFdCloexec(arg as FileDesc), | ||||
|             F_GETFD => FcntlCmd::GetFd(), | ||||
|             F_SETFD => FcntlCmd::SetFd(arg as u32), | ||||
|             F_GETFL => FcntlCmd::GetFl(), | ||||
|             F_SETFL => FcntlCmd::SetFl(OpenFlags::from_bits_truncate(arg as u32)), | ||||
|             _ => return errno!(EINVAL, "invalid command"), | ||||
|         }) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize, Error> { | ||||
|     info!("do_fcntl: {:?}, {:?}", &fd, cmd); | ||||
|     let current_ref = process::get_current(); | ||||
|     let mut current = current_ref.lock().unwrap(); | ||||
|     let files_ref = current.get_files(); | ||||
|     let mut files = files_ref.lock().unwrap(); | ||||
|     Ok(match cmd { | ||||
|         FcntlCmd::DupFd(min_fd) => { | ||||
|             let dup_fd = files.dup(fd, *min_fd, false)?; | ||||
|             dup_fd as isize | ||||
|         }, | ||||
|         FcntlCmd::DupFdCloexec(min_fd) => { | ||||
|             let dup_fd = files.dup(fd, *min_fd, true)?; | ||||
|             dup_fd as isize | ||||
|         }, | ||||
|         FcntlCmd::GetFd() => { | ||||
|             let entry = files.get_entry(fd)?; | ||||
|             let fd_flags = if entry.is_close_on_spawn() { | ||||
|                 FD_CLOEXEC | ||||
|             } else { | ||||
|                 0 | ||||
|             }; | ||||
|             fd_flags as isize | ||||
|         }, | ||||
|         FcntlCmd::SetFd(fd_flags) => { | ||||
|             let entry = files.get_entry_mut(fd)?; | ||||
|             entry.set_close_on_spawn((fd_flags & FD_CLOEXEC) != 0); | ||||
|             0 | ||||
|         }, | ||||
|         FcntlCmd::GetFl() => { | ||||
|             unimplemented!(); | ||||
|         }, | ||||
|         FcntlCmd::SetFl(flags) => { | ||||
|             unimplemented!(); | ||||
|         }, | ||||
|     }) | ||||
| } | ||||
| 
 | ||||
| pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize, Error> { | ||||
|     // TODO: support symbolic links
 | ||||
|     errno!(EINVAL, "not a symbolic link") | ||||
| } | ||||
|  | ||||
| @ -41,6 +41,7 @@ mod syscall; | ||||
| mod time; | ||||
| mod util; | ||||
| mod vm; | ||||
| mod misc; | ||||
| 
 | ||||
| use prelude::*; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										7
									
								
								src/libos/src/misc/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								src/libos/src/misc/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| mod uname; | ||||
| mod rlimit; | ||||
| 
 | ||||
| pub use self::uname::{utsname_t, do_uname}; | ||||
| pub use self::rlimit::{rlimit_t, resource_t, ResourceLimits, ResourceLimitsRef, do_prlimit}; | ||||
							
								
								
									
										123
									
								
								src/libos/src/misc/rlimit.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										123
									
								
								src/libos/src/misc/rlimit.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,123 @@ | ||||
| use super::*; | ||||
| use process::{pid_t}; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub struct ResourceLimits { | ||||
|     rlimits: [rlimit_t; RLIMIT_COUNT], | ||||
| } | ||||
| pub type ResourceLimitsRef = Arc<SgxMutex<ResourceLimits>>; | ||||
| 
 | ||||
| impl ResourceLimits { | ||||
|     pub fn get(&self, resource: resource_t) -> &rlimit_t { | ||||
|         &self.rlimits[resource as usize] | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_mut(&mut self, resource: resource_t) -> &mut rlimit_t { | ||||
|         &mut self.rlimits[resource as usize] | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Default for ResourceLimits { | ||||
|     fn default() -> ResourceLimits { | ||||
|         // TODO: set appropriate limits for resources
 | ||||
|         let mut rlimits = ResourceLimits { | ||||
|             rlimits: [ Default::default(); RLIMIT_COUNT ], | ||||
|         }; | ||||
|         rlimits | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| #[allow(non_camel_case_types)] | ||||
| pub struct rlimit_t { | ||||
|     cur: u64, | ||||
|     max: u64, | ||||
| } | ||||
| 
 | ||||
| impl Default for rlimit_t { | ||||
|     fn default() -> rlimit_t { | ||||
|         rlimit_t { | ||||
|             cur: u64::max_value(), | ||||
|             max: u64::max_value(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| #[allow(non_camel_case_types)] | ||||
| pub enum resource_t { | ||||
|     RLIMIT_CPU          = 0, | ||||
|     RLIMIT_FSIZE        = 1, | ||||
|     RLIMIT_DATA         = 2, | ||||
|     RLIMIT_STACK        = 3, | ||||
|     RLIMIT_CORE         = 4, | ||||
|     RLIMIT_RSS          = 5, | ||||
|     RLIMIT_NPROC        = 6, | ||||
|     RLIMIT_NOFILE       = 7, | ||||
|     RLIMIT_MEMLOCK      = 8, | ||||
|     RLIMIT_AS           = 9, | ||||
|     RLIMIT_LOCKS        = 10, | ||||
|     RLIMIT_SIGPENDING   = 11, | ||||
|     RLIMIT_MSGQUEUE     = 12, | ||||
|     RLIMIT_NICE         = 13, | ||||
|     RLIMIT_RTPRIO       = 14, | ||||
| } | ||||
| const RLIMIT_COUNT: usize = 15; | ||||
| 
 | ||||
| impl resource_t { | ||||
|     pub fn from_u32(bits: u32) -> Result<resource_t, Error> { | ||||
|         match bits { | ||||
|             0  => Ok(resource_t::RLIMIT_CPU), | ||||
|             1  => Ok(resource_t::RLIMIT_FSIZE), | ||||
|             2  => Ok(resource_t::RLIMIT_DATA), | ||||
|             3  => Ok(resource_t::RLIMIT_STACK), | ||||
|             4  => Ok(resource_t::RLIMIT_CORE), | ||||
|             5  => Ok(resource_t::RLIMIT_RSS), | ||||
|             6  => Ok(resource_t::RLIMIT_NPROC), | ||||
|             7  => Ok(resource_t::RLIMIT_NOFILE), | ||||
|             8  => Ok(resource_t::RLIMIT_MEMLOCK), | ||||
|             9  => Ok(resource_t::RLIMIT_AS), | ||||
|             10 => Ok(resource_t::RLIMIT_LOCKS), | ||||
|             11 => Ok(resource_t::RLIMIT_SIGPENDING), | ||||
|             12 => Ok(resource_t::RLIMIT_MSGQUEUE), | ||||
|             13 => Ok(resource_t::RLIMIT_NICE), | ||||
|             14 => Ok(resource_t::RLIMIT_RTPRIO), | ||||
|             _ => errno!(EINVAL, "invalid resource"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| pub fn do_prlimit( | ||||
|     pid: pid_t, | ||||
|     resource: resource_t, | ||||
|     new_limit: Option<&rlimit_t>, | ||||
|     old_limit: Option<&mut rlimit_t>, | ||||
| ) -> Result<(), Error> { | ||||
|     let process_ref = if pid == 0 { | ||||
|         process::get_current() | ||||
|     } | ||||
|     else { | ||||
|         process::get(pid)? | ||||
|     }; | ||||
|     let mut process = process_ref.lock().unwrap(); | ||||
|     let rlimits_ref = process.get_rlimits(); | ||||
|     let mut rlimits = rlimits_ref.lock().unwrap(); | ||||
|     if let Some(old_limit) = old_limit { | ||||
|         *old_limit = *rlimits.get(resource) | ||||
|     } | ||||
|     if let Some(new_limit) = new_limit { | ||||
|         *rlimits.get_mut(resource) = *new_limit; | ||||
|     } | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| pub fn do_getrlimit(resource: resource_t, old_limit: &mut rlimit_t) -> Result<(), Error> { | ||||
|     do_prlimit(0 as pid_t, resource, None, Some(old_limit)) | ||||
| } | ||||
| 
 | ||||
| pub fn do_setrlimit(resource: resource_t, new_limit: &rlimit_t) -> Result<(), Error> { | ||||
|     do_prlimit(0 as pid_t, resource, Some(new_limit), None) | ||||
| } | ||||
							
								
								
									
										51
									
								
								src/libos/src/misc/uname.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										51
									
								
								src/libos/src/misc/uname.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | ||||
| use super::*; | ||||
| use std::ffi::{CStr, CString}; | ||||
| 
 | ||||
| /// A sample of `struct utsname`
 | ||||
| /// ```
 | ||||
| ///   sysname = Linux
 | ||||
| ///   nodename = tian-nuc
 | ||||
| ///   release = 4.15.0-42-generic
 | ||||
| ///   version = #45~16.04.1-Ubuntu SMP Mon Nov 19 13:02:27 UTC 2018
 | ||||
| ///   machine = x86_64
 | ||||
| ///   domainname = (none)
 | ||||
| /// ```
 | ||||
| ///
 | ||||
| /// By the way, UTS stands for UNIX Timesharing System.
 | ||||
| #[repr(C)] | ||||
| #[derive(Copy, Clone)] | ||||
| pub struct utsname_t { | ||||
|     sysname: [u8; 65], | ||||
|     nodename: [u8; 65], | ||||
|     release: [u8; 65], | ||||
|     version: [u8; 65], | ||||
|     machine: [u8; 65], | ||||
|     domainname: [u8; 65], | ||||
| } | ||||
| 
 | ||||
| pub fn do_uname(name: &mut utsname_t) -> Result<(), Error> { | ||||
|     copy_from_cstr_to_u8_array(&SYSNAME, &mut name.sysname); | ||||
|     copy_from_cstr_to_u8_array(&NODENAME, &mut name.nodename); | ||||
|     copy_from_cstr_to_u8_array(&RELEASE, &mut name.release); | ||||
|     copy_from_cstr_to_u8_array(&VERSION, &mut name.version); | ||||
|     copy_from_cstr_to_u8_array(&MACHINE, &mut name.machine); | ||||
|     copy_from_cstr_to_u8_array(&DOMAINNAME, &mut name.domainname); | ||||
|     Ok(()) | ||||
| } | ||||
| 
 | ||||
| lazy_static! { | ||||
|     static ref SYSNAME : CString = CString::new("Occlum").unwrap(); | ||||
|     static ref NODENAME: CString = CString::new("occlum-node").unwrap(); | ||||
|     static ref RELEASE: CString = CString::new("0.1").unwrap(); | ||||
|     static ref VERSION: CString = CString::new("0.1").unwrap(); | ||||
|     static ref MACHINE: CString = CString::new("x86-64").unwrap(); | ||||
|     static ref DOMAINNAME: CString = CString::new("").unwrap(); | ||||
| } | ||||
| 
 | ||||
| fn copy_from_cstr_to_u8_array(src: &CStr, dst: &mut [u8]) { | ||||
|     let src : &[u8] = src.to_bytes_with_nul(); | ||||
|     let len = min(dst.len() - 1, src.len()); | ||||
|     dst[..len].copy_from_slice(&src[..len]); | ||||
|     dst[len] = 0; | ||||
| } | ||||
| 
 | ||||
| @ -22,6 +22,7 @@ pub use std::iter::Iterator; | ||||
| pub use std::rc::Rc; | ||||
| pub use std::string::String; | ||||
| pub use std::vec::Vec; | ||||
| pub use std::cmp::{min, max}; | ||||
| 
 | ||||
| pub use errno::Errno; | ||||
| pub use errno::Errno::*; | ||||
| @ -53,3 +54,7 @@ pub fn align_up(addr: usize, align: usize) -> usize { | ||||
| pub fn align_down(addr: usize, align: usize) -> usize { | ||||
|     addr & !(align - 1) | ||||
| } | ||||
| 
 | ||||
| pub fn unbox<T>(value: Box<T>) -> T { | ||||
|     *value | ||||
| } | ||||
|  | ||||
| @ -1,8 +1,6 @@ | ||||
| pub use self::process::{Status, IDLE_PROCESS}; | ||||
| pub use self::task::{get_current, run_task}; | ||||
| pub mod table { | ||||
|     pub use super::process_table::get; | ||||
| } | ||||
| pub use self::process_table::{get}; | ||||
| pub use self::exit::{do_exit, do_wait4, ChildProcessFilter}; | ||||
| pub use self::spawn::{do_spawn, FileAction}; | ||||
| pub use self::wait::{WaitQueue, Waiter}; | ||||
| @ -30,6 +28,7 @@ pub struct Process { | ||||
|     waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>, | ||||
|     vm: ProcessVMRef, | ||||
|     file_table: FileTableRef, | ||||
|     rlimits: ResourceLimitsRef, | ||||
| } | ||||
| 
 | ||||
| pub type ProcessRef = Arc<SgxMutex<Process>>; | ||||
| @ -79,3 +78,4 @@ use self::task::Task; | ||||
| use super::*; | ||||
| use fs::{File, FileRef, FileTable}; | ||||
| use vm::{ProcessVM, VMRangeTrait}; | ||||
| use misc::{ResourceLimitsRef}; | ||||
|  | ||||
| @ -10,7 +10,7 @@ lazy_static! { | ||||
|             task: Default::default(), | ||||
|             status: Default::default(), | ||||
|             pid: 0, | ||||
|             pgid: 0, | ||||
|             pgid: 1, | ||||
|             tgid: 0, | ||||
|             exit_status: 0, | ||||
|             cwd: "/".to_owned(), | ||||
| @ -20,6 +20,7 @@ lazy_static! { | ||||
|             waiting_children: Default::default(), | ||||
|             vm: Default::default(), | ||||
|             file_table: Default::default(), | ||||
|             rlimits: Default::default(), | ||||
|         })) | ||||
|     }; | ||||
| } | ||||
| @ -30,13 +31,14 @@ impl Process { | ||||
|         task: Task, | ||||
|         vm_ref: ProcessVMRef, | ||||
|         file_table_ref: FileTableRef, | ||||
|         rlimits_ref: ResourceLimitsRef, | ||||
|     ) -> Result<(pid_t, ProcessRef), Error> { | ||||
|         let new_pid = process_table::alloc_pid(); | ||||
|         let new_process_ref = Arc::new(SgxMutex::new(Process { | ||||
|             task: task, | ||||
|             status: Default::default(), | ||||
|             pid: new_pid, | ||||
|             pgid: new_pid, | ||||
|             pgid: 1, // TODO: implement pgid
 | ||||
|             tgid: new_pid, | ||||
|             cwd: cwd.to_owned(), | ||||
|             clear_child_tid: None, | ||||
| @ -46,6 +48,7 @@ impl Process { | ||||
|             waiting_children: None, | ||||
|             vm: vm_ref, | ||||
|             file_table: file_table_ref, | ||||
|             rlimits: rlimits_ref, | ||||
|         })); | ||||
|         Ok((new_pid, new_process_ref)) | ||||
|     } | ||||
| @ -97,6 +100,9 @@ impl Process { | ||||
|             self.cwd += path; | ||||
|         } | ||||
|     } | ||||
|     pub fn get_rlimits(&self) -> &ResourceLimitsRef { | ||||
|         &self.rlimits | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for Process { | ||||
|  | ||||
| @ -14,8 +14,10 @@ pub fn remove(pid: pid_t) { | ||||
|     PROCESS_TABLE.lock().unwrap().remove(&pid); | ||||
| } | ||||
| 
 | ||||
| pub fn get(pid: pid_t) -> Option<ProcessRef> { | ||||
|     PROCESS_TABLE.lock().unwrap().get(&pid).map(|pr| pr.clone()) | ||||
| pub fn get(pid: pid_t) -> Result<ProcessRef, Error> { | ||||
|     PROCESS_TABLE.lock().unwrap().get(&pid) | ||||
|         .map(|pr| pr.clone()) | ||||
|         .ok_or_else(|| Error::new(Errno::ENOENT, "process not found")) | ||||
| } | ||||
| 
 | ||||
| static NEXT_PID: AtomicU32 = AtomicU32::new(1); | ||||
|  | ||||
| @ -6,6 +6,7 @@ use std::ffi::{CStr, CString}; | ||||
| use std::path::Path; | ||||
| use std::sgxfs::SgxFile; | ||||
| use vm::{ProcessVM, VMRangeTrait}; | ||||
| use misc::{ResourceLimitsRef}; | ||||
| 
 | ||||
| use super::*; | ||||
| use super::task::Task; | ||||
| @ -72,7 +73,8 @@ pub fn do_spawn<P: AsRef<Path>>( | ||||
|             let files = init_files(parent_ref, file_actions)?; | ||||
|             Arc::new(SgxMutex::new(files)) | ||||
|         }; | ||||
|         Process::new(&cwd, task, vm_ref, files_ref)? | ||||
|         let rlimits_ref = Default::default(); | ||||
|         Process::new(&cwd, task, vm_ref, files_ref, rlimits_ref)? | ||||
|     }; | ||||
|     parent_adopts_new_child(&parent_ref, &new_process_ref); | ||||
|     process_table::put(new_pid, new_process_ref.clone()); | ||||
|  | ||||
| @ -51,8 +51,9 @@ pub fn do_clone( | ||||
|         let task = new_thread_task(stack_addr, new_tls)?; | ||||
|         let vm_ref = current.get_vm().clone(); | ||||
|         let files_ref = current.get_files().clone(); | ||||
|         let rlimits_ref = current.get_rlimits().clone(); | ||||
|         let cwd = ¤t.cwd; | ||||
|         Process::new(cwd, task, vm_ref, files_ref)? | ||||
|         Process::new(cwd, task, vm_ref, files_ref, rlimits_ref)? | ||||
|     }; | ||||
| 
 | ||||
|     if let Some(ctid) = ctid { | ||||
| @ -67,6 +68,8 @@ pub fn do_clone( | ||||
|         let mut new_thread = new_thread_ref.lock().unwrap(); | ||||
|         parent.children.push(Arc::downgrade(&new_thread_ref)); | ||||
|         new_thread.parent = Some(parent_ref.clone()); | ||||
| 
 | ||||
|         new_thread.tgid = current.tgid; | ||||
|     } | ||||
| 
 | ||||
|     process_table::put(new_thread_pid, new_thread_ref.clone()); | ||||
|  | ||||
| @ -7,7 +7,7 @@ | ||||
| //! 3. Dispatch the syscall to `do_*` (at this file)
 | ||||
| //! 4. Do some memory checks then call `mod::do_*` (at each module)
 | ||||
| 
 | ||||
| use fs::{File, SocketFile, FileDesc, FileRef, EpollOp}; | ||||
| use fs::{File, SocketFile, FileDesc, FileRef, EpollOp, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; | ||||
| use prelude::*; | ||||
| use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | ||||
| use std::ffi::{CStr, CString}; | ||||
| @ -16,6 +16,7 @@ use time::timeval_t; | ||||
| use util::mem_util::from_user::*; | ||||
| use vm::{VMAreaFlags, VMResizeOptions}; | ||||
| use {fs, process, std, vm}; | ||||
| use misc::{utsname_t, resource_t, rlimit_t}; | ||||
| 
 | ||||
| use super::*; | ||||
| 
 | ||||
| @ -66,6 +67,8 @@ pub extern "C" fn dispatch_syscall( | ||||
|         SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat), | ||||
|         SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat), | ||||
|         SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat), | ||||
|         SYS_ACCESS => do_access(arg0 as *const i8, arg1 as u32), | ||||
|         SYS_FACCESSAT => do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32), | ||||
|         SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), | ||||
|         SYS_FSYNC => do_fsync(arg0 as FileDesc), | ||||
|         SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc), | ||||
| @ -80,6 +83,8 @@ pub extern "C" fn dispatch_syscall( | ||||
|         SYS_RMDIR => do_rmdir(arg0 as *const i8), | ||||
|         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), | ||||
|         SYS_UNLINK => do_unlink(arg0 as *const i8), | ||||
|         SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), | ||||
|         SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), | ||||
| 
 | ||||
|         // IO multiplexing
 | ||||
|         SYS_SELECT => do_select( | ||||
| @ -119,9 +124,19 @@ pub extern "C" fn dispatch_syscall( | ||||
|             arg4 as *const FdOp, | ||||
|         ), | ||||
|         SYS_WAIT4 => do_wait4(arg0 as i32, arg1 as *mut i32), | ||||
| 
 | ||||
|         SYS_GETPID => do_getpid(), | ||||
|         SYS_GETTID => do_gettid(), | ||||
|         SYS_GETPPID => do_getppid(), | ||||
|         SYS_GETPGID => do_getpgid(), | ||||
| 
 | ||||
|         SYS_GETUID => do_getuid(), | ||||
|         SYS_GETGID => do_getgid(), | ||||
|         SYS_GETEUID => do_geteuid(), | ||||
|         SYS_GETEGID => do_getegid(), | ||||
| 
 | ||||
|         SYS_RT_SIGACTION => do_rt_sigaction(), | ||||
|         SYS_RT_SIGPROCMASK => do_rt_sigprocmask(), | ||||
| 
 | ||||
|         SYS_CLONE => do_clone( | ||||
|             arg0 as u32, | ||||
| @ -171,6 +186,11 @@ pub extern "C" fn dispatch_syscall( | ||||
| 
 | ||||
|         SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), | ||||
| 
 | ||||
|         SYS_UNAME => do_uname(arg0 as *mut utsname_t), | ||||
| 
 | ||||
|         SYS_PRLIMIT64 => do_prlimit(arg0 as pid_t, arg1 as u32, arg2 as *const rlimit_t, arg3 as *mut rlimit_t), | ||||
| 
 | ||||
| 
 | ||||
|         // socket
 | ||||
|         SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), | ||||
|         SYS_CONNECT => do_connect( | ||||
| @ -658,6 +678,30 @@ fn do_getppid() -> Result<isize, Error> { | ||||
|     Ok(ppid as isize) | ||||
| } | ||||
| 
 | ||||
| fn do_getpgid() -> Result<isize, Error> { | ||||
|     let pgid = process::do_getpgid(); | ||||
|     Ok(pgid as isize) | ||||
| } | ||||
| 
 | ||||
| // TODO: implement uid, gid, euid, egid
 | ||||
| 
 | ||||
| fn do_getuid() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_getgid() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_geteuid() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_getegid() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> { | ||||
|     check_mut_array(fds_u, 2)?; | ||||
|     // TODO: how to deal with open flags???
 | ||||
| @ -778,6 +822,21 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize, Error> { | ||||
|     let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); | ||||
|     let buf = { | ||||
|         check_array(buf, size)?; | ||||
|         unsafe { std::slice::from_raw_parts_mut(buf, size) } | ||||
|     }; | ||||
|     let len = fs::do_readlink(&path, buf)?; | ||||
|     Ok(len as isize) | ||||
| } | ||||
| 
 | ||||
| fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> { | ||||
|     let cmd = FcntlCmd::from_raw(cmd, arg)?; | ||||
|     fs::do_fcntl(fd, &cmd) | ||||
| } | ||||
| 
 | ||||
| fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { | ||||
|     let code = process::ArchPrctlCode::from_u32(code)?; | ||||
|     check_mut_ptr(addr)?; | ||||
| @ -1087,3 +1146,62 @@ impl AsSocket for FileRef { | ||||
|             .ok_or(Error::new(Errno::EBADF, "not a socket")) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn do_uname(name: *mut utsname_t) -> Result<isize, Error> { | ||||
|     check_mut_ptr(name)?; | ||||
|     let name = unsafe { &mut *name }; | ||||
|     misc::do_uname(name).map(|_| 0) | ||||
| } | ||||
| 
 | ||||
| fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: *mut rlimit_t) -> Result<isize, Error> { | ||||
|     let resource = resource_t::from_u32(resource)?; | ||||
|     let new_limit = { | ||||
|         if new_limit != ptr::null() { | ||||
|             check_ptr(new_limit)?; | ||||
|             Some(unsafe { &*new_limit }) | ||||
|         } | ||||
|         else { | ||||
|             None | ||||
|         } | ||||
|     }; | ||||
|     let old_limit = { | ||||
|         if old_limit != ptr::null_mut() { | ||||
|             check_mut_ptr(old_limit)?; | ||||
|             Some(unsafe { &mut *old_limit }) | ||||
|         } | ||||
|         else { | ||||
|             None | ||||
|         } | ||||
|     }; | ||||
|     misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0) | ||||
| } | ||||
| 
 | ||||
| fn do_access(path: *const i8, mode: u32) -> Result<isize, Error> { | ||||
|     let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); | ||||
|     let mode = AccessModes::from_u32(mode)?; | ||||
|     fs::do_access(&path, mode).map(|_| 0) | ||||
| } | ||||
| 
 | ||||
| fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize, Error> { | ||||
|     let dirfd = if dirfd >= 0 { | ||||
|         Some(dirfd as FileDesc) | ||||
|     } else if dirfd == AT_FDCWD { | ||||
|         None | ||||
|     } else { | ||||
|         return errno!(EINVAL, "invalid dirfd"); | ||||
|     }; | ||||
|     let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); | ||||
|     let mode = AccessModes::from_u32(mode)?; | ||||
|     let flags = AccessFlags::from_u32(flags)?; | ||||
|     fs::do_faccessat(dirfd, &path, mode, flags).map(|_| 0) | ||||
| } | ||||
| 
 | ||||
| // TODO: implement signals
 | ||||
| 
 | ||||
| fn do_rt_sigaction() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| fn do_rt_sigprocmask() -> Result<isize, Error> { | ||||
|     Ok(0) | ||||
| } | ||||
|  | ||||
| @ -3,17 +3,15 @@ use prelude::*; | ||||
| use process::{get_current, Process, ProcessRef}; | ||||
| use std::fmt; | ||||
| 
 | ||||
| // TODO: Rename VMSpace to VMUniverse
 | ||||
| 
 | ||||
| #[macro_use] | ||||
| mod vm_range; | ||||
| mod process_vm; | ||||
| mod vm_area; | ||||
| mod vm_domain; | ||||
| mod vm_space; | ||||
| mod process_vm; | ||||
| 
 | ||||
| pub use self::process_vm::ProcessVM; | ||||
| pub use self::vm_range::{VMRange, VMRangeTrait}; | ||||
| pub use self::vm_area::{VMSpace, VMDomain, VMArea, VMAreaFlags, VM_AREA_FLAG_R, VM_AREA_FLAG_W, VM_AREA_FLAG_X}; | ||||
| pub use self::process_vm::ProcessVM; | ||||
| 
 | ||||
| 
 | ||||
| // TODO: separate proc and flags
 | ||||
| // TODO: accept fd and offset
 | ||||
| @ -56,23 +54,6 @@ pub fn do_brk(addr: usize) -> Result<usize, Error> { | ||||
| 
 | ||||
| pub const PAGE_SIZE: usize = 4096; | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct VMSpace { | ||||
|     range: VMRange, | ||||
|     guard_type: VMGuardAreaType, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Default)] | ||||
| pub struct VMDomain { | ||||
|     range: VMRange, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Default)] | ||||
| pub struct VMArea { | ||||
|     range: VMRange, | ||||
|     flags: VMAreaFlags, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq)] | ||||
| pub enum VMGuardAreaType { | ||||
|     None, | ||||
| @ -80,32 +61,14 @@ pub enum VMGuardAreaType { | ||||
|     Dynamic { size: usize }, | ||||
| } | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default, PartialEq)] | ||||
| pub struct VMAreaFlags(pub u32); | ||||
| 
 | ||||
| pub const VM_AREA_FLAG_R: u32 = 0x1; | ||||
| pub const VM_AREA_FLAG_W: u32 = 0x2; | ||||
| pub const VM_AREA_FLAG_X: u32 = 0x4; | ||||
| 
 | ||||
| impl VMAreaFlags { | ||||
|     pub fn can_execute(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_X == VM_AREA_FLAG_X | ||||
|     } | ||||
| 
 | ||||
|     pub fn can_write(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_W == VM_AREA_FLAG_W | ||||
|     } | ||||
| 
 | ||||
|     pub fn can_read(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_R == VM_AREA_FLAG_R | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, PartialEq)] | ||||
| #[derive(Clone, PartialEq, Default)] | ||||
| pub struct VMAllocOptions { | ||||
|     size: usize, | ||||
|     addr: VMAddrOption, | ||||
|     growth: Option<VMGrowthType>, | ||||
|     growth: VMGrowthType, | ||||
|     description: String, | ||||
|     fill_zeros: bool, | ||||
| } | ||||
| 
 | ||||
| impl VMAllocOptions { | ||||
| @ -128,7 +91,17 @@ impl VMAllocOptions { | ||||
|     } | ||||
| 
 | ||||
|     pub fn growth(&mut self, growth: VMGrowthType) -> Result<&mut Self, Error> { | ||||
|         self.growth = Some(growth); | ||||
|         self.growth = growth; | ||||
|         Ok(self) | ||||
|     } | ||||
| 
 | ||||
|     pub fn description(&mut self, description: &str) -> Result<&mut Self, Error> { | ||||
|         self.description = description.to_owned(); | ||||
|         Ok(self) | ||||
|     } | ||||
| 
 | ||||
|     pub fn fill_zeros(&mut self, fill_zeros: bool) -> Result<&mut Self, Error> { | ||||
|         self.fill_zeros = fill_zeros; | ||||
|         Ok(self) | ||||
|     } | ||||
| } | ||||
| @ -143,15 +116,6 @@ impl fmt::Debug for VMAllocOptions { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Default for VMAllocOptions { | ||||
|     fn default() -> VMAllocOptions { | ||||
|         VMAllocOptions { | ||||
|             size: 0, | ||||
|             addr: VMAddrOption::Any, | ||||
|             growth: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq)] | ||||
| pub enum VMAddrOption { | ||||
| @ -161,6 +125,12 @@ pub enum VMAddrOption { | ||||
|     Beyond(usize), // Must be greater or equal to the given address
 | ||||
| } | ||||
| 
 | ||||
| impl Default for VMAddrOption { | ||||
|     fn default() -> VMAddrOption { | ||||
|         VMAddrOption::Any | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl VMAddrOption { | ||||
|     pub fn is_addr_given(&self) -> bool { | ||||
|         match self { | ||||
| @ -179,18 +149,27 @@ impl VMAddrOption { | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /// How VMRange may grow:
 | ||||
| #[derive(Clone, Copy, Debug, PartialEq)] | ||||
| pub enum VMGrowthType { | ||||
|     Fixed, | ||||
|     Upward,   // e.g., mmaped regions grow upward
 | ||||
|     Downward, // e.g., stacks grows downward
 | ||||
|     Fixed, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Debug)] | ||||
| impl Default for VMGrowthType { | ||||
|     fn default() -> VMGrowthType { | ||||
|         VMGrowthType::Fixed | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Clone, Debug, Default)] | ||||
| pub struct VMResizeOptions { | ||||
|     new_size: usize, | ||||
|     new_addr: Option<VMAddrOption>, | ||||
|     new_addr: VMAddrOption, | ||||
|     fill_zeros: bool, | ||||
| } | ||||
| 
 | ||||
| impl VMResizeOptions { | ||||
| @ -205,16 +184,12 @@ impl VMResizeOptions { | ||||
|     } | ||||
| 
 | ||||
|     pub fn addr(&mut self, new_addr: VMAddrOption) -> &mut Self { | ||||
|         self.new_addr = Some(new_addr); | ||||
|         self.new_addr = new_addr; | ||||
|         self | ||||
|     } | ||||
| 
 | ||||
|     pub fn fill_zeros(&mut self, fill_zeros: bool) -> &mut Self { | ||||
|         self.fill_zeros = fill_zeros; | ||||
|         self | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Default for VMResizeOptions { | ||||
|     fn default() -> VMResizeOptions { | ||||
|         VMResizeOptions { | ||||
|             new_size: 0, | ||||
|             new_addr: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -11,7 +11,7 @@ lazy_static! { | ||||
|             (addr, size) | ||||
|         }; | ||||
|         let vm_space = unsafe { | ||||
|             match VMSpace::new(addr, size, VMGuardAreaType::None) { | ||||
|             match VMSpace::new(addr, size, VMGuardAreaType::None, "DATA_SPACE") { | ||||
|                 Ok(vm_space) => vm_space, | ||||
|                 Err(_) => panic!("Failed to create a VMSpace"), | ||||
|             } | ||||
| @ -27,11 +27,11 @@ extern "C" { | ||||
| #[derive(Debug, Default)] | ||||
| pub struct ProcessVM { | ||||
|     //code_domain: VMDomain,
 | ||||
|     data_domain: VMDomain, | ||||
|     code_vma: VMArea, | ||||
|     data_vma: VMArea, | ||||
|     heap_vma: VMArea, | ||||
|     stack_vma: VMArea, | ||||
|     data_domain: Option<Box<VMDomain>>, | ||||
|     code_vma: Option<Box<VMArea>>, | ||||
|     data_vma: Option<Box<VMArea>>, | ||||
|     heap_vma: Option<Box<VMArea>>, | ||||
|     stack_vma: Option<Box<VMArea>>, | ||||
|     mmap_vmas: Vec<Box<VMArea>>, | ||||
|     brk: usize, | ||||
| } | ||||
| @ -44,29 +44,39 @@ impl ProcessVM { | ||||
|         stack_size: usize, | ||||
|         mmap_size: usize, | ||||
|     ) -> Result<ProcessVM, Error> { | ||||
|         let data_domain_size = code_size + data_size + heap_size + stack_size + mmap_size; | ||||
|         let mut data_domain = DATA_SPACE.lock().unwrap().alloc_domain(data_domain_size)?; | ||||
| 
 | ||||
|         let (code_vma, data_vma, heap_vma, stack_vma) = ProcessVM::alloc_vmas( | ||||
|             &mut data_domain, | ||||
|             code_size, | ||||
|             data_size, | ||||
|             heap_size, | ||||
|             stack_size, | ||||
|         )?; | ||||
|         // Allocate the data domain from the global data space
 | ||||
|         let mut data_domain = { | ||||
|             let data_domain_size = code_size + data_size + heap_size | ||||
|                                  + stack_size + mmap_size; | ||||
|             let data_domain = DATA_SPACE.lock().unwrap().alloc_domain( | ||||
|                                     data_domain_size, "data_domain")?; | ||||
|             data_domain | ||||
|         }; | ||||
|         // Allocate vmas from the data domain
 | ||||
|         let (code_vma, data_vma, heap_vma, stack_vma) = | ||||
|             match ProcessVM::alloc_vmas(&mut data_domain, code_size, | ||||
|                                         data_size, heap_size, stack_size) { | ||||
|                 Err(e) => { | ||||
|                     // Note: we need to handle error here so that we can
 | ||||
|                     // deallocate the data domain explictly.
 | ||||
|                     DATA_SPACE.lock().unwrap().dealloc_domain(data_domain); | ||||
|                     return Err(e); | ||||
|                 }, | ||||
|                 Ok(vmas) => vmas, | ||||
|             }; | ||||
|         // Initial value of the program break
 | ||||
|         let brk = heap_vma.get_start(); | ||||
|         // No mmapped vmas initially
 | ||||
|         let mmap_vmas = Vec::new(); | ||||
| 
 | ||||
|         let vm = ProcessVM { | ||||
|             data_domain, | ||||
|             code_vma, | ||||
|             data_vma, | ||||
|             heap_vma, | ||||
|             stack_vma, | ||||
|             mmap_vmas, | ||||
|             brk, | ||||
|             data_domain: Some(Box::new(data_domain)), | ||||
|             code_vma: Some(Box::new(code_vma)), | ||||
|             data_vma: Some(Box::new(data_vma)), | ||||
|             heap_vma: Some(Box::new(heap_vma)), | ||||
|             stack_vma: Some(Box::new(stack_vma)), | ||||
|             mmap_vmas: mmap_vmas, | ||||
|             brk: brk, | ||||
|         }; | ||||
|         Ok(vm) | ||||
|     } | ||||
| @ -79,11 +89,13 @@ impl ProcessVM { | ||||
|         stack_size: usize, | ||||
|     ) -> Result<(VMArea, VMArea, VMArea, VMArea), Error> { | ||||
|         let mut addr = data_domain.get_start(); | ||||
| 
 | ||||
|         let mut alloc_vma_continuously = | ||||
|             |addr: &mut usize, size, flags, growth| -> Result<_, Error> { | ||||
|             |addr: &mut usize, desc, size, flags, growth, fill_zeros| -> Result<_, Error> { | ||||
|                 let mut options = VMAllocOptions::new(size)?; | ||||
|                 options.addr(VMAddrOption::Fixed(*addr))?.growth(growth)?; | ||||
|                 options.addr(VMAddrOption::Fixed(*addr))? | ||||
|                     .growth(growth)? | ||||
|                     .description(desc)? | ||||
|                     .fill_zeros(fill_zeros)?; | ||||
|                 let new_vma = data_domain.alloc_area(&options, flags)?; | ||||
|                 *addr += size; | ||||
|                 Ok(new_vma) | ||||
| @ -92,39 +104,42 @@ impl ProcessVM { | ||||
|         let rx_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_X); | ||||
|         let rw_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_W); | ||||
| 
 | ||||
|         let code_vma = alloc_vma_continuously(&mut addr, code_size, rx_flags, VMGrowthType::Fixed)?; | ||||
|         let data_vma = alloc_vma_continuously(&mut addr, data_size, rw_flags, VMGrowthType::Fixed)?; | ||||
|         let heap_vma = alloc_vma_continuously(&mut addr, 0, rw_flags, VMGrowthType::Upward)?; | ||||
|         let code_vma = alloc_vma_continuously(&mut addr, "code_vma", code_size, | ||||
|                                               rx_flags, VMGrowthType::Fixed, true)?; | ||||
|         let data_vma = alloc_vma_continuously(&mut addr, "data_vma", data_size, | ||||
|                                               rw_flags, VMGrowthType::Fixed, true)?; | ||||
|         let heap_vma = alloc_vma_continuously(&mut addr, "heap_vma", 0, | ||||
|                                               rw_flags, VMGrowthType::Upward, true)?; | ||||
|         // Preserve the space for heap
 | ||||
|         addr += heap_size; | ||||
|         // After the heap is the stack
 | ||||
|         let stack_vma = | ||||
|             alloc_vma_continuously(&mut addr, stack_size, rw_flags, VMGrowthType::Downward)?; | ||||
|         let stack_vma = alloc_vma_continuously(&mut addr, "stack_vma", stack_size, | ||||
|                                                rw_flags, VMGrowthType::Downward, false)?; | ||||
|         Ok((code_vma, data_vma, heap_vma, stack_vma)) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_base_addr(&self) -> usize { | ||||
|         self.code_vma.get_start() | ||||
|         self.get_code_vma().get_start() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_code_vma(&self) -> &VMArea { | ||||
|         &self.code_vma | ||||
|         &self.code_vma.as_ref().unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_data_vma(&self) -> &VMArea { | ||||
|         &self.data_vma | ||||
|         &self.data_vma.as_ref().unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_heap_vma(&self) -> &VMArea { | ||||
|         &self.heap_vma | ||||
|         &self.heap_vma.as_ref().unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_stack_vma(&self) -> &VMArea { | ||||
|         &self.stack_vma | ||||
|         &self.stack_vma.as_ref().unwrap() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_stack_top(&self) -> usize { | ||||
|         self.stack_vma.get_end() | ||||
|         self.get_stack_vma().get_end() | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_mmap_vmas(&self) -> &[Box<VMArea>] { | ||||
| @ -156,36 +171,37 @@ impl ProcessVM { | ||||
|                     if addr < mmap_start_addr { | ||||
|                         return Err(Error::new(Errno::EINVAL, "Beyond valid memory range")); | ||||
|                     } | ||||
|                     VMAddrOption::Fixed(addr) | ||||
|                     // TODO: Fixed or Hint? Should hanle mmap flags
 | ||||
|                     VMAddrOption::Hint(addr) | ||||
|                 })? | ||||
|                 .growth(VMGrowthType::Upward)?; | ||||
|             alloc_options | ||||
|         }; | ||||
|         // TODO: when failed, try to resize data_domain
 | ||||
|         let new_mmap_vma = self.data_domain.alloc_area(&alloc_options, flags)?; | ||||
|         let new_mmap_vma = self.get_data_domain_mut() | ||||
|             .alloc_area(&alloc_options, flags)?; | ||||
|         let addr = new_mmap_vma.get_start(); | ||||
|         self.mmap_vmas.push(Box::new(new_mmap_vma)); | ||||
|         Ok(addr) | ||||
|     } | ||||
| 
 | ||||
|     pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> { | ||||
|     // TODO: handle the case when the given range [addr, addr + size)
 | ||||
|     // does not match exactly with any vma. For example, when this range
 | ||||
|     // cover multiple ranges or cover some range partially.
 | ||||
| 
 | ||||
|     pub fn munmap(&mut self, addr: usize, size: usize) -> Result<(), Error> { | ||||
|         let mmap_vma_i = { | ||||
|             let mmap_vma_i = self | ||||
|                 .get_mmap_vmas() | ||||
|                 .iter() | ||||
|                 .position(|vma| vma.get_start() == addr && vma.get_end() == addr + size); | ||||
|             if mmap_vma_i.is_none() { | ||||
|                 return Ok(()); | ||||
|                 return errno!(EINVAL, "memory area not found"); | ||||
|             } | ||||
|             mmap_vma_i.unwrap() | ||||
|         }; | ||||
| 
 | ||||
|         let mut removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); | ||||
|         self.data_domain.dealloc_area(&mut removed_mmap_vma); | ||||
|         let removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); | ||||
|         self.get_data_domain_mut().dealloc_area(unbox(removed_mmap_vma)); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| @ -200,43 +216,52 @@ impl ProcessVM { | ||||
|     } | ||||
| 
 | ||||
|     pub fn brk(&mut self, new_brk: usize) -> Result<usize, Error> { | ||||
|         let (heap_start, heap_end) = { | ||||
|             let heap_vma = self.heap_vma.as_ref().unwrap(); | ||||
|             (heap_vma.get_start(), heap_vma.get_end()) | ||||
|         }; | ||||
|         if new_brk == 0 { | ||||
|             return Ok(self.get_brk()); | ||||
|         } else if new_brk < self.heap_vma.get_start() { | ||||
|         } else if new_brk < heap_start { | ||||
|             return errno!(EINVAL, "New brk address is too low"); | ||||
|         } else if new_brk <= self.heap_vma.get_end() { | ||||
|         } else if new_brk > heap_end { | ||||
|             let resize_options = { | ||||
|                 let new_heap_end = align_up(new_brk, PAGE_SIZE); | ||||
|                 let new_heap_size = new_heap_end - heap_start; | ||||
|                 let mut options = VMResizeOptions::new(new_heap_size)?; | ||||
|                 options.addr(VMAddrOption::Fixed(heap_start)) | ||||
|                     .fill_zeros(true); | ||||
|                 options | ||||
|             }; | ||||
|             let heap_vma = self.heap_vma.as_mut().unwrap(); | ||||
|             let data_domain = self.data_domain.as_mut().unwrap(); | ||||
|             data_domain.resize_area(heap_vma, &resize_options)?; | ||||
|         } | ||||
|         self.brk = new_brk; | ||||
|         return Ok(new_brk); | ||||
|     } | ||||
| 
 | ||||
|         // TODO: init the memory with zeros for the expanded area
 | ||||
|         let resize_options = { | ||||
|             let brk_start = self.get_brk_start(); | ||||
|             let new_heap_size = align_up(new_brk, 4096) - brk_start; | ||||
|             let mut options = VMResizeOptions::new(new_heap_size)?; | ||||
|             options.addr(VMAddrOption::Fixed(brk_start)); | ||||
|             options | ||||
|         }; | ||||
|         self.data_domain | ||||
|             .resize_area(&mut self.heap_vma, &resize_options)?; | ||||
|         Ok(new_brk) | ||||
|     fn get_data_domain_mut(&mut self) -> &mut Box<VMDomain> { | ||||
|         self.data_domain.as_mut().unwrap() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for ProcessVM { | ||||
|     fn drop(&mut self) { | ||||
|         let data_domain = &mut self.data_domain; | ||||
| 
 | ||||
|         // Remove all vma from the domain
 | ||||
|         data_domain.dealloc_area(&mut self.code_vma); | ||||
|         data_domain.dealloc_area(&mut self.data_vma); | ||||
|         data_domain.dealloc_area(&mut self.heap_vma); | ||||
|         data_domain.dealloc_area(&mut self.stack_vma); | ||||
|         for mmap_vma in &mut self.mmap_vmas { | ||||
|             data_domain.dealloc_area(mmap_vma); | ||||
|         { | ||||
|             let data_domain = self.data_domain.as_mut().unwrap(); | ||||
|             data_domain.dealloc_area(unbox(self.code_vma.take().unwrap())); | ||||
|             data_domain.dealloc_area(unbox(self.data_vma.take().unwrap())); | ||||
|             data_domain.dealloc_area(unbox(self.heap_vma.take().unwrap())); | ||||
|             data_domain.dealloc_area(unbox(self.stack_vma.take().unwrap())); | ||||
|             for mmap_vma in self.mmap_vmas.drain(..) { | ||||
|                 data_domain.dealloc_area(unbox(mmap_vma)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Remove the domain from its parent space
 | ||||
|         DATA_SPACE.lock().unwrap().dealloc_domain(data_domain); | ||||
|         DATA_SPACE.lock().unwrap().dealloc_domain( | ||||
|             unbox(self.data_domain.take().unwrap())); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,93 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| impl super::VMArea { | ||||
| #[derive(Debug)] | ||||
| pub struct VMSpace { | ||||
|     range: VMRange, | ||||
|     guard_type: VMGuardAreaType, | ||||
| } | ||||
| 
 | ||||
| impl_vmrange_trait_for!(VMSpace, range); | ||||
| 
 | ||||
| impl VMSpace { | ||||
|     pub unsafe fn new( | ||||
|         addr: usize, | ||||
|         size: usize, | ||||
|         guard_type: VMGuardAreaType, | ||||
|         desc: &str, | ||||
|     ) -> Result<VMSpace, Error> { | ||||
|         let addr = align_up(addr, PAGE_SIZE); | ||||
|         let size = align_down(size, PAGE_SIZE); | ||||
|         let range = unsafe { VMRange::new(addr, addr + size, VMGrowthType::Fixed, desc)? }; | ||||
|         Ok(VMSpace { range, guard_type }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_guard_type(&self) -> VMGuardAreaType { | ||||
|         self.guard_type | ||||
|     } | ||||
| 
 | ||||
|     pub fn alloc_domain(&mut self, size: usize, desc: &str) -> Result<VMDomain, Error> { | ||||
|         let mut options = VMAllocOptions::new(size)?; | ||||
|         options.growth(VMGrowthType::Upward)? | ||||
|             .description(desc)?; | ||||
| 
 | ||||
|         let new_range = self.range.alloc_subrange(&options)?; | ||||
|         Ok(VMDomain { range: new_range }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn dealloc_domain(&mut self, mut domain: VMDomain) { | ||||
|         self.range.dealloc_subrange(&mut domain.range) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_domain(&mut self, domain: &mut VMDomain, new_size: usize) -> Result<(), Error> { | ||||
|         let options = VMResizeOptions::new(new_size)?; | ||||
|         self.range.resize_subrange(&mut domain.range, &options) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct VMDomain { | ||||
|     range: VMRange, | ||||
| } | ||||
| 
 | ||||
| impl_vmrange_trait_for!(VMDomain, range); | ||||
| 
 | ||||
| impl VMDomain { | ||||
|     pub fn alloc_area( | ||||
|         &mut self, | ||||
|         options: &VMAllocOptions, | ||||
|         flags: VMAreaFlags, | ||||
|     ) -> Result<VMArea, Error> { | ||||
|         let new_range = self.range.alloc_subrange(options)?; | ||||
|         Ok(VMArea { | ||||
|             range: new_range, | ||||
|             flags: flags, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn dealloc_area(&mut self, mut area: VMArea) { | ||||
|         self.range.dealloc_subrange(&mut area.range) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_area( | ||||
|         &mut self, | ||||
|         area: &mut VMArea, | ||||
|         options: &VMResizeOptions, | ||||
|     ) -> Result<(), Error> { | ||||
|         self.range.resize_subrange(&mut area.range, options) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct VMArea { | ||||
|     range: VMRange, | ||||
|     flags: VMAreaFlags, | ||||
| } | ||||
| 
 | ||||
| impl_vmrange_trait_for!(VMArea, range); | ||||
| 
 | ||||
| impl VMArea { | ||||
|     pub fn get_flags(&self) -> &VMAreaFlags { | ||||
|         &self.flags | ||||
|     } | ||||
| @ -9,3 +96,25 @@ impl super::VMArea { | ||||
|         &mut self.flags | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| #[derive(Copy, Clone, Debug, Default, PartialEq)] | ||||
| pub struct VMAreaFlags(pub u32); | ||||
| 
 | ||||
| pub const VM_AREA_FLAG_R: u32 = 0x1; | ||||
| pub const VM_AREA_FLAG_W: u32 = 0x2; | ||||
| pub const VM_AREA_FLAG_X: u32 = 0x4; | ||||
| 
 | ||||
| impl VMAreaFlags { | ||||
|     pub fn can_execute(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_X == VM_AREA_FLAG_X | ||||
|     } | ||||
| 
 | ||||
|     pub fn can_write(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_W == VM_AREA_FLAG_W | ||||
|     } | ||||
| 
 | ||||
|     pub fn can_read(&self) -> bool { | ||||
|         self.0 & VM_AREA_FLAG_R == VM_AREA_FLAG_R | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -1,41 +0,0 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| impl VMDomain { | ||||
|     pub fn alloc_area( | ||||
|         &mut self, | ||||
|         options: &VMAllocOptions, | ||||
|         flags: VMAreaFlags, | ||||
|     ) -> Result<VMArea, Error> { | ||||
|         let new_range = self.range.alloc_subrange(options)?; | ||||
| 
 | ||||
|         // Init the memory area with all zeros
 | ||||
|         unsafe { | ||||
|             let mem_ptr = new_range.get_start() as *mut c_void; | ||||
|             let mem_size = new_range.get_size() as size_t; | ||||
|             memset(mem_ptr, 0 as c_int, mem_size); | ||||
|         } | ||||
| 
 | ||||
|         Ok(VMArea { | ||||
|             range: new_range, | ||||
|             flags: flags, | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn dealloc_area(&mut self, area: &mut VMArea) { | ||||
|         self.range.dealloc_subrange(&mut area.range) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_area( | ||||
|         &mut self, | ||||
|         area: &mut VMArea, | ||||
|         options: &VMResizeOptions, | ||||
|     ) -> Result<(), Error> { | ||||
|         // TODO: init memory with zeros when expanding!
 | ||||
|         self.range.resize_subrange(&mut area.range, options) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[link(name = "sgx_tstdc")] | ||||
| extern "C" { | ||||
|     pub fn memset(p: *mut c_void, c: c_int, n: size_t) -> *mut c_void; | ||||
| } | ||||
| @ -35,132 +35,61 @@ macro_rules! impl_vmrange_trait_for { | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| impl_vmrange_trait_for!(VMRange, inner); | ||||
| impl_vmrange_trait_for!(VMSpace, range); | ||||
| impl_vmrange_trait_for!(VMDomain, range); | ||||
| impl_vmrange_trait_for!(VMArea, range); | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct VMRange { | ||||
|     inner: VMRangeInner, | ||||
|     parent_range: *const VMRange, | ||||
|     sub_ranges: Option<Vec<VMRangeInner>>, | ||||
|     is_dealloced: bool, | ||||
|     description: String, | ||||
| } | ||||
| 
 | ||||
| impl_vmrange_trait_for!(VMRange, inner); | ||||
| 
 | ||||
| impl VMRange { | ||||
|     pub unsafe fn new(start: usize, end: usize, growth: VMGrowthType) -> Result<VMRange, Error> { | ||||
|     pub unsafe fn new(start: usize, end: usize, growth: VMGrowthType, description: &str) -> Result<VMRange, Error> { | ||||
|         if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 { | ||||
|             return errno!(EINVAL, "Invalid start and/or end"); | ||||
|         } | ||||
|         Ok(VMRange { | ||||
|             inner: VMRangeInner::new(start, end, growth), | ||||
|             parent_range: 0 as *const VMRange, | ||||
|             sub_ranges: None, | ||||
|             is_dealloced: false, | ||||
|             description: description.to_owned(), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn alloc_subrange(&mut self, options: &VMAllocOptions) -> Result<VMRange, Error> { | ||||
|         // Get valid parameters from options
 | ||||
|         let size = options.size; | ||||
|         let addr = options.addr; | ||||
|         let growth = options.growth.unwrap_or(VMGrowthType::Fixed); | ||||
|         debug_assert!(!self.is_dealloced); | ||||
| 
 | ||||
|         // Lazy initialize the subrange array upon the first allocation
 | ||||
|         if !self.has_subranges() { | ||||
|             self.init_subranges()?; | ||||
|         if self.sub_ranges.is_none() { | ||||
|             self.init_subrange_array()?; | ||||
|         } | ||||
| 
 | ||||
|         // Find a free space for allocating a VMRange
 | ||||
|         let free_space = { | ||||
|             // Look for the minimal big-enough free space
 | ||||
|             let mut min_big_enough_free_space: Option<FreeSpace> = None; | ||||
|             let sub_ranges = self.get_subranges(); | ||||
|             for (idx, range_pair) in sub_ranges.windows(2).enumerate() { | ||||
|                 let pre_range = &range_pair[0]; | ||||
|                 let next_range = &range_pair[1]; | ||||
|         // Find a free space that satisfies the options
 | ||||
|         let free_space = self.look_for_free_space(options)?; | ||||
|         // Allocate a new subrange from the free space
 | ||||
|         let (new_subrange_idx, new_subrange_inner) = { | ||||
|             let (new_subrange_start, new_subrange_end) = | ||||
|                 self.alloc_from_free_space(&free_space, options); | ||||
|             debug_assert!(free_space.contains(new_subrange_start)); | ||||
|             debug_assert!(free_space.contains(new_subrange_end)); | ||||
| 
 | ||||
|                 let mut free_range = { | ||||
|                     let free_range_start = pre_range.get_end(); | ||||
|                     let free_range_end = next_range.get_start(); | ||||
| 
 | ||||
|                     let free_range_size = free_range_end - free_range_start; | ||||
|                     if free_range_size < size { | ||||
|                         continue; | ||||
|                     } | ||||
| 
 | ||||
|                     free_range_start..free_range_end | ||||
|             (free_space.index_in_subranges, VMRangeInner::new( | ||||
|                     new_subrange_start, new_subrange_end, options.growth)) | ||||
|         }; | ||||
| 
 | ||||
|                 match addr { | ||||
|                     VMAddrOption::Hint(addr) | VMAddrOption::Fixed(addr) => { | ||||
|                         if !free_range.contains(&addr) { | ||||
|                             continue; | ||||
|                         } | ||||
|                         free_range.start = addr; | ||||
|                     } | ||||
|                     VMAddrOption::Beyond(addr) => { | ||||
|                         if free_range.start < addr { | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|                     _ => {} | ||||
|                 } | ||||
| 
 | ||||
|                 let free_space = Some(FreeSpace { | ||||
|                     index_in_subranges: idx + 1, | ||||
|                     start: free_range.start, | ||||
|                     end: free_range.end, | ||||
|                     may_neighbor_grow: ( | ||||
|                         pre_range.growth == VMGrowthType::Upward, | ||||
|                         next_range.growth == VMGrowthType::Downward, | ||||
|                     ), | ||||
|                 }); | ||||
| 
 | ||||
|                 if min_big_enough_free_space == None || free_space < min_big_enough_free_space { | ||||
|                     min_big_enough_free_space = free_space; | ||||
| 
 | ||||
|                     match addr { | ||||
|                         VMAddrOption::Hint(addr) | VMAddrOption::Fixed(addr) => break, | ||||
|                         _ => {} | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if min_big_enough_free_space.is_none() { | ||||
|                 return errno!(ENOMEM, "No enough space"); | ||||
|             } | ||||
|             min_big_enough_free_space.unwrap() | ||||
|         }; | ||||
| 
 | ||||
|         // Given the free space, determine the start and end of the sub-range
 | ||||
|         let (new_subrange_start, new_subrange_end) = match addr { | ||||
|             VMAddrOption::Any | VMAddrOption::Beyond(_) => { | ||||
|                 let should_no_gap_to_pre_domain = | ||||
|                     free_space.may_neighbor_grow.0 == false && growth != VMGrowthType::Downward; | ||||
|                 let should_no_gap_to_next_domain = | ||||
|                     free_space.may_neighbor_grow.1 == false && growth != VMGrowthType::Upward; | ||||
|                 let domain_start = if should_no_gap_to_pre_domain { | ||||
|                     free_space.start | ||||
|                 } else if should_no_gap_to_next_domain { | ||||
|                     free_space.end - size | ||||
|                 } else { | ||||
|                     // We want to leave some space at both ends in case
 | ||||
|                     // this sub-range or neighbor sub-range needs to grow later.
 | ||||
|                     // As a simple heuristic, we put this sub-range near the
 | ||||
|                     // center between the previous and next sub-ranges.
 | ||||
|                     free_space.start + (free_space.get_size() - size) / 2 | ||||
|                 }; | ||||
|                 (domain_start, domain_start + size) | ||||
|             } | ||||
|             VMAddrOption::Fixed(addr) => (addr, addr + size), | ||||
|             VMAddrOption::Hint(addr) => { | ||||
|                 return errno!(EINVAL, "Not implemented"); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         let new_subrange_inner = VMRangeInner::new(new_subrange_start, new_subrange_end, growth); | ||||
|         self.get_subranges_mut() | ||||
|             .insert(free_space.index_in_subranges, new_subrange_inner); | ||||
|             .insert(new_subrange_idx, new_subrange_inner); | ||||
| 
 | ||||
|         if options.fill_zeros { | ||||
|             // Init the memory area with all zeros
 | ||||
|             unsafe { | ||||
|                 let mem_ptr = new_subrange_inner.get_start() as *mut c_void; | ||||
|                 let mem_size = new_subrange_inner.get_size() as size_t; | ||||
|                 memset(mem_ptr, 0 as c_int, mem_size); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // Although there are two copies of the newly created VMRangeInner obj,
 | ||||
|         // we can keep them in sync as all mutation on VMRange object must
 | ||||
|         // be carried out through dealloc_subrange() and resize_subrange() that
 | ||||
| @ -169,29 +98,28 @@ impl VMRange { | ||||
|         // other in child, in dealloc_subrange and resize_subrange functions.
 | ||||
|         Ok(VMRange { | ||||
|             inner: new_subrange_inner, | ||||
|             parent_range: self as *const VMRange, | ||||
|             sub_ranges: None, | ||||
|             is_dealloced: false, | ||||
|             description: options.description.clone(), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn dealloc_subrange(&mut self, subrange: &mut VMRange) { | ||||
|         self.ensure_subrange_is_a_child(subrange); | ||||
|         if subrange.has_subranges() { | ||||
|             panic!("A range can only be dealloc'ed when it has no sub-ranges"); | ||||
|         } | ||||
|         debug_assert!(!self.is_dealloced); | ||||
|         debug_assert!(!subrange.is_dealloced); | ||||
|         debug_assert!(self.sub_ranges.is_some()); | ||||
| 
 | ||||
|         // Remove the sub-range
 | ||||
|         let domain_i = self.position_subrange(subrange); | ||||
|         self.get_subranges_mut().remove(domain_i); | ||||
| 
 | ||||
|         // When all sub-ranges are removed, remove the sub-range array
 | ||||
|         if self.get_subranges().len() == 2 { | ||||
|             // two sentinel sub-ranges excluded
 | ||||
|             self.sub_ranges = None; | ||||
|         } | ||||
| 
 | ||||
|         // Mark a range as dealloc'ed
 | ||||
|         subrange.mark_as_dealloced(); | ||||
|         subrange.inner.end = subrange.inner.start; | ||||
|         subrange.is_dealloced = true; | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_subrange( | ||||
| @ -199,7 +127,9 @@ impl VMRange { | ||||
|         subrange: &mut VMRange, | ||||
|         options: &VMResizeOptions, | ||||
|     ) -> Result<(), Error> { | ||||
|         self.ensure_subrange_is_a_child(subrange); | ||||
|         debug_assert!(!self.is_dealloced); | ||||
|         debug_assert!(!subrange.is_dealloced); | ||||
|         debug_assert!(self.sub_ranges.is_some()); | ||||
| 
 | ||||
|         // Get valid parameters from options
 | ||||
|         let new_size = options.new_size; | ||||
| @ -219,11 +149,15 @@ impl VMRange { | ||||
|         } | ||||
|         // Grow
 | ||||
|         else { | ||||
|             self.grow_subrange_to(subrange, new_size) | ||||
|             self.grow_subrange_to(subrange, new_size, options.fill_zeros) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn init_subranges(&mut self) -> Result<(), Error> { | ||||
|     pub fn get_description(&self) -> &str { | ||||
|         &self.description | ||||
|     } | ||||
| 
 | ||||
|     fn init_subrange_array(&mut self) -> Result<(), Error> { | ||||
|         // Use dummy VMRange as sentinel object at both ends to make the allocation
 | ||||
|         // and deallocation algorithm simpler
 | ||||
|         let start = self.get_start(); | ||||
| @ -234,11 +168,126 @@ impl VMRange { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn ensure_subrange_is_a_child(&self, subrange: &VMRange) { | ||||
|         // FIXME:
 | ||||
|         /*if subrange.parent_range != self as *const VMRange {
 | ||||
|             panic!("This range does not contain the given sub-range"); | ||||
|         }*/ | ||||
|     // Find a free space for allocating a sub VMRange
 | ||||
|     fn look_for_free_space(&mut self, options: &VMAllocOptions) -> Result<FreeSpace, Error> { | ||||
|         // TODO: reduce the complexity from O(N) to O(log(N)), where N is
 | ||||
|         // the number of existing subranges.
 | ||||
| 
 | ||||
|         // Get valid parameters from options
 | ||||
|         let size = options.size; | ||||
|         let addr = options.addr; | ||||
|         let growth = options.growth; | ||||
| 
 | ||||
|         // Record the minimal free space that satisfies the options
 | ||||
|         let mut min_big_enough_free_space: Option<FreeSpace> = None; | ||||
| 
 | ||||
|         let sub_ranges = self.get_subranges(); | ||||
|         for (idx, range_pair) in sub_ranges.windows(2).enumerate() { | ||||
|             let pre_range = &range_pair[0]; | ||||
|             let next_range = &range_pair[1]; | ||||
| 
 | ||||
|             let (free_range_start, free_range_end)= { | ||||
|                 let free_range_start = pre_range.get_end(); | ||||
|                 let free_range_end = next_range.get_start(); | ||||
| 
 | ||||
|                 let free_range_size = free_range_end - free_range_start; | ||||
|                 if free_range_size < size { | ||||
|                     continue; | ||||
|                 } | ||||
| 
 | ||||
|                 (free_range_start, free_range_end) | ||||
|             }; | ||||
|             let mut free_space = FreeSpace { | ||||
|                 index_in_subranges: idx + 1, | ||||
|                 start: free_range_start, | ||||
|                 end: free_range_end, | ||||
|                 may_neighbor_grow: ( | ||||
|                     pre_range.growth == VMGrowthType::Upward, | ||||
|                     next_range.growth == VMGrowthType::Downward, | ||||
|                 ), | ||||
|             }; | ||||
| 
 | ||||
|             match addr { | ||||
|                 // Want a minimal free_space
 | ||||
|                 VMAddrOption::Any => { }, | ||||
|                 // Prefer to have free_space.start == addr
 | ||||
|                 VMAddrOption::Hint(addr) => { | ||||
|                     if free_space.contains(addr) { | ||||
|                         if free_space.end - addr >= size { | ||||
|                             free_space.start = addr; | ||||
|                             return Ok(free_space); | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|                 // Must have free_space.start == addr
 | ||||
|                 VMAddrOption::Fixed(addr) => { | ||||
|                     if !free_space.contains(addr) { | ||||
|                         continue; | ||||
|                     } | ||||
|                     if free_space.end - addr < size { | ||||
|                         return errno!(ENOMEM, "not enough memory"); | ||||
|                     } | ||||
|                     free_space.start = addr; | ||||
|                     return Ok(free_space); | ||||
|                 } | ||||
|                 // Must have free_space.start >= addr
 | ||||
|                 VMAddrOption::Beyond(addr) => { | ||||
|                     if free_space.end < addr { | ||||
|                         continue; | ||||
|                     } | ||||
|                     if free_space.contains(addr) { | ||||
|                         free_space.start = addr; | ||||
|                         if free_space.get_size() < size { | ||||
|                             continue; | ||||
|                         } | ||||
|                     } | ||||
|                 }, | ||||
|             } | ||||
| 
 | ||||
|             if min_big_enough_free_space == None || | ||||
|                 free_space < *min_big_enough_free_space.as_ref().unwrap() { | ||||
|                 min_big_enough_free_space = Some(free_space); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         min_big_enough_free_space | ||||
|             .ok_or_else(|| Error::new(Errno::ENOMEM, "not enough space")) | ||||
|     } | ||||
| 
 | ||||
|     fn alloc_from_free_space(&self, free_space: &FreeSpace, options: &VMAllocOptions) -> (usize, usize) { | ||||
|         // Get valid parameters from options
 | ||||
|         let size = options.size; | ||||
|         let addr_option = options.addr; | ||||
|         let growth = options.growth; | ||||
| 
 | ||||
|         if let VMAddrOption::Fixed(addr) = addr_option { | ||||
|             return (addr, addr + size); | ||||
|         } | ||||
|         else if let VMAddrOption::Hint(addr) = addr_option { | ||||
|             if free_space.start == addr { | ||||
|                 return (addr, addr + size); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let should_no_gap_to_pre_domain = | ||||
|             free_space.may_neighbor_grow.0 == false && growth != VMGrowthType::Downward; | ||||
|         let should_no_gap_to_next_domain = | ||||
|             free_space.may_neighbor_grow.1 == false && growth != VMGrowthType::Upward; | ||||
| 
 | ||||
|         let addr = if should_no_gap_to_pre_domain { | ||||
|             free_space.start | ||||
|         } else if should_no_gap_to_next_domain { | ||||
|             free_space.end - size | ||||
|         } else { | ||||
|             // We want to leave some space at both ends in case
 | ||||
|             // this sub-range or neighbor sub-range needs to grow later.
 | ||||
|             // As a simple heuristic, we put this sub-range near the
 | ||||
|             // center between the previous and next sub-ranges.
 | ||||
|             let offset = align_down((free_space.get_size() - size) / 2, PAGE_SIZE); | ||||
|             free_space.start + offset | ||||
|         }; | ||||
| 
 | ||||
|         (addr, addr + size) | ||||
|     } | ||||
| 
 | ||||
|     fn position_subrange(&self, subrange: &VMRange) -> usize { | ||||
| @ -257,10 +306,6 @@ impl VMRange { | ||||
|         self.sub_ranges.as_mut().unwrap() | ||||
|     } | ||||
| 
 | ||||
|     fn has_subranges(&self) -> bool { | ||||
|         self.sub_ranges.is_some() | ||||
|     } | ||||
| 
 | ||||
|     fn shrink_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> { | ||||
|         let subrange_i = self.position_subrange(subrange); | ||||
|         let subranges = self.get_subranges_mut(); | ||||
| @ -304,51 +349,61 @@ impl VMRange { | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn grow_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> { | ||||
|     fn grow_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize, fill_zeros: bool) -> Result<(), Error> { | ||||
|         let subrange_i = self.position_subrange(subrange); | ||||
|         let subranges = self.get_subranges_mut(); | ||||
| 
 | ||||
|         let subrange_old_start = subrange.inner.start; | ||||
|         let subrange_old_end = subrange.inner.end; | ||||
|         let subrange_old_size = subrange.get_size(); | ||||
| 
 | ||||
|         if subrange.inner.growth == VMGrowthType::Upward { | ||||
|             // Can we grow?
 | ||||
|             // Can we grow upward?
 | ||||
|             let max_new_size = { | ||||
|                 let next_subrange = &subranges[subrange_i + 1]; | ||||
|                 next_subrange.start - subrange.inner.start | ||||
|                 next_subrange.start - subrange_old_start | ||||
|             }; | ||||
|             if new_size > max_new_size { | ||||
|                 return errno!(ENOMEM, "Cannot grow to new size"); | ||||
|             } | ||||
|             // Do grow
 | ||||
|             let subrange_new_end = subrange.inner.start + new_size; | ||||
|             let subrange_new_end = subrange_old_start + new_size; | ||||
|             subrange.inner.end = subrange_new_end; | ||||
|             // Sync state
 | ||||
|             subranges[subrange_i].end = subrange_new_end; | ||||
|         } else { | ||||
|             // self.growth == VMGrowthType::Downward
 | ||||
|             // Can we grow?
 | ||||
|             // Init memory
 | ||||
|             if fill_zeros { | ||||
|                 unsafe { | ||||
|                     let mem_ptr = subrange_old_end as *mut c_void; | ||||
|                     let mem_size = (subrange_new_end - subrange_old_end) as size_t; | ||||
|                     memset(mem_ptr, 0 as c_int, mem_size); | ||||
|                 } | ||||
|             } | ||||
|         } else { // self.growth == VMGrowthType::Downward
 | ||||
|             // Can we grow downard?
 | ||||
|             let max_new_size = { | ||||
|                 let pre_subrange = &subranges[subrange_i - 1]; | ||||
|                 subrange.inner.end - pre_subrange.end | ||||
|                 subrange_old_end - pre_subrange.end | ||||
|             }; | ||||
|             if new_size > max_new_size { | ||||
|                 return errno!(ENOMEM, "Cannot grow to new size"); | ||||
|             } | ||||
|             // Do grow
 | ||||
|             let subrange_new_start = subrange.inner.end - new_size; | ||||
|             let subrange_new_start = subrange_old_end - new_size; | ||||
|             subrange.inner.start = subrange_new_start; | ||||
|             // Sync state
 | ||||
|             subranges[subrange_i].start = subrange_new_start; | ||||
|             // Init memory
 | ||||
|             if fill_zeros { | ||||
|                 unsafe { | ||||
|                     let mem_ptr = subrange_new_start as *mut c_void; | ||||
|                     let mem_size = (subrange_old_start - subrange_new_start) as size_t; | ||||
|                     memset(mem_ptr, 0 as c_int, mem_size); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn mark_as_dealloced(&mut self) { | ||||
|         self.parent_range = 0 as *const VMRange; | ||||
|         self.inner.start = self.inner.end; | ||||
|     } | ||||
| 
 | ||||
|     fn is_dealloced(&self) -> bool { | ||||
|         self.parent_range == 0 as *const VMRange | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialOrd for VMRange { | ||||
| @ -365,29 +420,15 @@ impl PartialEq for VMRange { | ||||
| 
 | ||||
| impl Drop for VMRange { | ||||
|     fn drop(&mut self) { | ||||
|         if !self.is_dealloced() { | ||||
|             println!("VMRange::drop::panic1"); | ||||
|         if !self.is_dealloced { | ||||
|             panic!("A range must be dealloc'ed before drop"); | ||||
|         } | ||||
|         if self.has_subranges() { | ||||
|             println!("VMRange::drop::panic2"); | ||||
|             panic!("All sub-ranges must be removed explicitly before drop"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| unsafe impl Send for VMRange {} | ||||
| unsafe impl Sync for VMRange {} | ||||
| 
 | ||||
| impl Default for VMRange { | ||||
|     fn default() -> VMRange { | ||||
|         VMRange { | ||||
|             inner: VMRangeInner::new(0, 0, VMGrowthType::Fixed), | ||||
|             parent_range: 0 as *const VMRange, | ||||
|             sub_ranges: None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy)] | ||||
| pub struct VMRangeInner { | ||||
| @ -398,6 +439,8 @@ pub struct VMRangeInner { | ||||
| 
 | ||||
| impl VMRangeInner { | ||||
|     pub fn new(start: usize, end: usize, growth: VMGrowthType) -> VMRangeInner { | ||||
|         debug_assert!(start % PAGE_SIZE == 0); | ||||
|         debug_assert!(end % PAGE_SIZE == 0); | ||||
|         VMRangeInner { | ||||
|             start: start, | ||||
|             end: end, | ||||
| @ -478,9 +521,14 @@ impl FreeSpace { | ||||
|         pressure += if self.may_neighbor_grow.1 { 1 } else { 0 }; | ||||
|         pressure | ||||
|     } | ||||
| 
 | ||||
|     fn get_size(&self) -> usize { | ||||
|         self.end - self.start | ||||
|     } | ||||
| 
 | ||||
|     fn contains(&self, addr: usize) -> bool { | ||||
|         self.start <= addr && addr < self.end | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl PartialEq for FreeSpace { | ||||
| @ -512,3 +560,8 @@ impl PartialOrd for FreeSpace { | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[link(name = "sgx_tstdc")] | ||||
| extern "C" { | ||||
|     pub fn memset(p: *mut c_void, c: c_int, n: size_t) -> *mut c_void; | ||||
| } | ||||
|  | ||||
| @ -1,33 +0,0 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| impl VMSpace { | ||||
|     pub unsafe fn new( | ||||
|         addr: usize, | ||||
|         size: usize, | ||||
|         guard_type: VMGuardAreaType, | ||||
|     ) -> Result<VMSpace, Error> { | ||||
|         let range = unsafe { VMRange::new(addr, addr + size, VMGrowthType::Fixed)? }; | ||||
|         Ok(VMSpace { range, guard_type }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_guard_type(&self) -> VMGuardAreaType { | ||||
|         self.guard_type | ||||
|     } | ||||
| 
 | ||||
|     pub fn alloc_domain(&mut self, size: usize) -> Result<VMDomain, Error> { | ||||
|         let mut options = VMAllocOptions::new(size)?; | ||||
|         options.growth(VMGrowthType::Upward)?; | ||||
| 
 | ||||
|         let new_range = self.range.alloc_subrange(&options)?; | ||||
|         Ok(VMDomain { range: new_range }) | ||||
|     } | ||||
| 
 | ||||
|     pub fn dealloc_domain(&mut self, domain: &mut VMDomain) { | ||||
|         self.range.dealloc_subrange(&mut domain.range) | ||||
|     } | ||||
| 
 | ||||
|     pub fn resize_domain(&mut self, domain: &mut VMDomain, new_size: usize) -> Result<(), Error> { | ||||
|         let options = VMResizeOptions::new(new_size)?; | ||||
|         self.range.resize_subrange(&mut domain.range, &options) | ||||
|     } | ||||
| } | ||||
| @ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../) | ||||
| # Dependencies: need to be compiled but not to run by any Makefile target
 | ||||
| TEST_DEPS := dev_null | ||||
| # 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 tls pthread client server | ||||
| TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link tls pthread uname rlimit client server | ||||
| # Benchmarks: need to be compiled and run by bench-% target
 | ||||
| BENCHES := spawn_and_exit_latency pipe_throughput | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										5
									
								
								test/rlimit/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								test/rlimit/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| include ../test_common.mk | ||||
| 
 | ||||
| EXTRA_C_FLAGS := | ||||
| EXTRA_LINK_FLAGS := | ||||
| BIN_ARGS := | ||||
							
								
								
									
										15
									
								
								test/rlimit/main.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								test/rlimit/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| #include <sys/resource.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int main(int argc, const char* argv[]) { | ||||
|     struct rlimit rlim; | ||||
|     if (getrlimit(RLIMIT_AS, &rlim) < 0) { | ||||
|         printf("ERROR: getrlimit failed\n"); | ||||
|         return -1; | ||||
|     } | ||||
|     if (setrlimit(RLIMIT_AS, &rlim) < 0) { | ||||
|         printf("ERROR: getrlimit failed\n"); | ||||
|         return -1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| @ -21,6 +21,11 @@ int main(int argc, const char* argv[]) { | ||||
|         return fd; | ||||
|     } | ||||
| 
 | ||||
|     if (access(FILE_NAME, F_OK) < 0) { | ||||
|         printf("cannot access the new file\n"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     ret = ftruncate(fd, TRUNC_LEN); | ||||
|     if (ret < 0) { | ||||
|         printf("failed to ftruncate the file\n"); | ||||
|  | ||||
							
								
								
									
										5
									
								
								test/uname/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								test/uname/Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| include ../test_common.mk | ||||
| 
 | ||||
| EXTRA_C_FLAGS := | ||||
| EXTRA_LINK_FLAGS := | ||||
| BIN_ARGS := | ||||
							
								
								
									
										14
									
								
								test/uname/main.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										14
									
								
								test/uname/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| #include <sys/utsname.h> | ||||
| #include <stdio.h> | ||||
| 
 | ||||
| int main(void) { | ||||
|     struct utsname name; | ||||
|     uname(&name); | ||||
|     printf("sysname = %s\n", (const char*)&name.sysname); | ||||
|     printf("nodename = %s\n", (const char*)&name.nodename); | ||||
|     printf("release = %s\n", (const char*)&name.release); | ||||
|     printf("version = %s\n", (const char*)&name.version); | ||||
|     printf("machine = %s\n", (const char*)&name.machine); | ||||
|     printf("domainname = %s\n", (const char*)&name.__domainname); | ||||
|     return 0; | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user