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, |     num_fds: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] |  | ||||||
| struct FileTableEntry { |  | ||||||
|     file: FileRef, |  | ||||||
|     close_on_spawn: bool, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl FileTable { | impl FileTable { | ||||||
|     pub fn new() -> FileTable { |     pub fn new() -> FileTable { | ||||||
|         FileTable { |         FileTable { | ||||||
| @ -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 { |     pub fn put(&mut self, file: FileRef, close_on_spawn: bool) -> FileDesc { | ||||||
|         let mut table = &mut self.table; |         let mut table = &mut self.table; | ||||||
| 
 | 
 | ||||||
|         let min_free_fd = if self.num_fds < table.len() { |         let min_free_fd = if self.num_fds < table.len() { | ||||||
|             table |             table.iter() | ||||||
|                 .iter() |  | ||||||
|                 .enumerate() |                 .enumerate() | ||||||
|                 .find(|&(idx, opt)| opt.is_none()) |                 .find(|&(idx, opt)| opt.is_none()) | ||||||
|                 .unwrap() |                 .unwrap() | ||||||
| @ -59,13 +79,30 @@ impl FileTable { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get(&self, fd: FileDesc) -> Result<FileRef, Error> { |     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() { |         if fd as usize >= self.table.len() { | ||||||
|             return errno!(EBADF, "Invalid file descriptor"); |             return errno!(EBADF, "Invalid file descriptor"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let table = &self.table; |         let table = &self.table; | ||||||
|         match table[fd as usize].as_ref() { |         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"), |             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 { | impl FileTableEntry { | ||||||
|     fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { |     pub fn new(file: FileRef, close_on_spawn: bool) -> FileTableEntry { | ||||||
|         FileTableEntry { |         FileTableEntry { | ||||||
|             file, |             file, | ||||||
|             close_on_spawn, |             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; | use self::inode_file::OpenOptions; | ||||||
| pub use self::pipe::Pipe; | pub use self::pipe::Pipe; | ||||||
| pub use self::io_multiplexing::*; | pub use self::io_multiplexing::*; | ||||||
|  | pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; | ||||||
| 
 | 
 | ||||||
| mod file; | mod file; | ||||||
| mod file_table; | mod file_table; | ||||||
| @ -21,6 +22,7 @@ mod socket_file; | |||||||
| mod pipe; | mod pipe; | ||||||
| mod sgx_impl; | mod sgx_impl; | ||||||
| mod io_multiplexing; | mod io_multiplexing; | ||||||
|  | mod access; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> { | 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! { | bitflags! { | ||||||
|     struct OpenFlags: u32 { |     pub struct OpenFlags: u32 { | ||||||
|         /// read only
 |         /// read only
 | ||||||
|         const RDONLY = 0; |         const RDONLY = 0; | ||||||
|         /// write only
 |         /// 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.copy_from(s.as_ptr(), s.len()); | ||||||
|     ptr.add(s.len()).write(0); |     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 time; | ||||||
| mod util; | mod util; | ||||||
| mod vm; | mod vm; | ||||||
|  | mod misc; | ||||||
| 
 | 
 | ||||||
| use prelude::*; | 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::rc::Rc; | ||||||
| pub use std::string::String; | pub use std::string::String; | ||||||
| pub use std::vec::Vec; | pub use std::vec::Vec; | ||||||
|  | pub use std::cmp::{min, max}; | ||||||
| 
 | 
 | ||||||
| pub use errno::Errno; | pub use errno::Errno; | ||||||
| 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 { | pub fn align_down(addr: usize, align: usize) -> usize { | ||||||
|     addr & !(align - 1) |     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::process::{Status, IDLE_PROCESS}; | ||||||
| pub use self::task::{get_current, run_task}; | pub use self::task::{get_current, run_task}; | ||||||
| pub mod table { | pub use self::process_table::{get}; | ||||||
|     pub use super::process_table::get; |  | ||||||
| } |  | ||||||
| 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}; | ||||||
| @ -30,6 +28,7 @@ pub struct Process { | |||||||
|     waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>, |     waiting_children: Option<WaitQueue<ChildProcessFilter, pid_t>>, | ||||||
|     vm: ProcessVMRef, |     vm: ProcessVMRef, | ||||||
|     file_table: FileTableRef, |     file_table: FileTableRef, | ||||||
|  |     rlimits: ResourceLimitsRef, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub type ProcessRef = Arc<SgxMutex<Process>>; | pub type ProcessRef = Arc<SgxMutex<Process>>; | ||||||
| @ -79,3 +78,4 @@ use self::task::Task; | |||||||
| use super::*; | use super::*; | ||||||
| use fs::{File, FileRef, FileTable}; | use fs::{File, FileRef, FileTable}; | ||||||
| use vm::{ProcessVM, VMRangeTrait}; | use vm::{ProcessVM, VMRangeTrait}; | ||||||
|  | use misc::{ResourceLimitsRef}; | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ lazy_static! { | |||||||
|             task: Default::default(), |             task: Default::default(), | ||||||
|             status: Default::default(), |             status: Default::default(), | ||||||
|             pid: 0, |             pid: 0, | ||||||
|             pgid: 0, |             pgid: 1, | ||||||
|             tgid: 0, |             tgid: 0, | ||||||
|             exit_status: 0, |             exit_status: 0, | ||||||
|             cwd: "/".to_owned(), |             cwd: "/".to_owned(), | ||||||
| @ -20,6 +20,7 @@ lazy_static! { | |||||||
|             waiting_children: Default::default(), |             waiting_children: Default::default(), | ||||||
|             vm: Default::default(), |             vm: Default::default(), | ||||||
|             file_table: Default::default(), |             file_table: Default::default(), | ||||||
|  |             rlimits: Default::default(), | ||||||
|         })) |         })) | ||||||
|     }; |     }; | ||||||
| } | } | ||||||
| @ -30,13 +31,14 @@ impl Process { | |||||||
|         task: Task, |         task: Task, | ||||||
|         vm_ref: ProcessVMRef, |         vm_ref: ProcessVMRef, | ||||||
|         file_table_ref: FileTableRef, |         file_table_ref: FileTableRef, | ||||||
|  |         rlimits_ref: ResourceLimitsRef, | ||||||
|     ) -> 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 { | ||||||
|             task: task, |             task: task, | ||||||
|             status: Default::default(), |             status: Default::default(), | ||||||
|             pid: new_pid, |             pid: new_pid, | ||||||
|             pgid: new_pid, |             pgid: 1, // TODO: implement pgid
 | ||||||
|             tgid: new_pid, |             tgid: new_pid, | ||||||
|             cwd: cwd.to_owned(), |             cwd: cwd.to_owned(), | ||||||
|             clear_child_tid: None, |             clear_child_tid: None, | ||||||
| @ -46,6 +48,7 @@ impl Process { | |||||||
|             waiting_children: None, |             waiting_children: None, | ||||||
|             vm: vm_ref, |             vm: vm_ref, | ||||||
|             file_table: file_table_ref, |             file_table: file_table_ref, | ||||||
|  |             rlimits: rlimits_ref, | ||||||
|         })); |         })); | ||||||
|         Ok((new_pid, new_process_ref)) |         Ok((new_pid, new_process_ref)) | ||||||
|     } |     } | ||||||
| @ -97,6 +100,9 @@ impl Process { | |||||||
|             self.cwd += path; |             self.cwd += path; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     pub fn get_rlimits(&self) -> &ResourceLimitsRef { | ||||||
|  |         &self.rlimits | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Drop for Process { | impl Drop for Process { | ||||||
|  | |||||||
| @ -14,8 +14,10 @@ pub fn remove(pid: pid_t) { | |||||||
|     PROCESS_TABLE.lock().unwrap().remove(&pid); |     PROCESS_TABLE.lock().unwrap().remove(&pid); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn get(pid: pid_t) -> Option<ProcessRef> { | pub fn get(pid: pid_t) -> Result<ProcessRef, Error> { | ||||||
|     PROCESS_TABLE.lock().unwrap().get(&pid).map(|pr| pr.clone()) |     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); | static NEXT_PID: AtomicU32 = AtomicU32::new(1); | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ use std::ffi::{CStr, CString}; | |||||||
| use std::path::Path; | use std::path::Path; | ||||||
| use std::sgxfs::SgxFile; | use std::sgxfs::SgxFile; | ||||||
| use vm::{ProcessVM, VMRangeTrait}; | use vm::{ProcessVM, VMRangeTrait}; | ||||||
|  | use misc::{ResourceLimitsRef}; | ||||||
| 
 | 
 | ||||||
| use super::*; | use super::*; | ||||||
| use super::task::Task; | use super::task::Task; | ||||||
| @ -72,7 +73,8 @@ pub fn do_spawn<P: AsRef<Path>>( | |||||||
|             let files = init_files(parent_ref, file_actions)?; |             let files = init_files(parent_ref, file_actions)?; | ||||||
|             Arc::new(SgxMutex::new(files)) |             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); |     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()); | ||||||
|  | |||||||
| @ -51,8 +51,9 @@ pub fn do_clone( | |||||||
|         let task = new_thread_task(stack_addr, new_tls)?; |         let task = new_thread_task(stack_addr, new_tls)?; | ||||||
|         let vm_ref = current.get_vm().clone(); |         let vm_ref = current.get_vm().clone(); | ||||||
|         let files_ref = current.get_files().clone(); |         let files_ref = current.get_files().clone(); | ||||||
|  |         let rlimits_ref = current.get_rlimits().clone(); | ||||||
|         let cwd = ¤t.cwd; |         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 { |     if let Some(ctid) = ctid { | ||||||
| @ -67,6 +68,8 @@ pub fn do_clone( | |||||||
|         let mut new_thread = new_thread_ref.lock().unwrap(); |         let mut new_thread = new_thread_ref.lock().unwrap(); | ||||||
|         parent.children.push(Arc::downgrade(&new_thread_ref)); |         parent.children.push(Arc::downgrade(&new_thread_ref)); | ||||||
|         new_thread.parent = Some(parent_ref.clone()); |         new_thread.parent = Some(parent_ref.clone()); | ||||||
|  | 
 | ||||||
|  |         new_thread.tgid = current.tgid; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     process_table::put(new_thread_pid, new_thread_ref.clone()); |     process_table::put(new_thread_pid, new_thread_ref.clone()); | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
| //! 3. Dispatch the syscall to `do_*` (at this file)
 | //! 3. Dispatch the syscall to `do_*` (at this file)
 | ||||||
| //! 4. Do some memory checks then call `mod::do_*` (at each module)
 | //! 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 prelude::*; | ||||||
| use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; | ||||||
| use std::ffi::{CStr, CString}; | use std::ffi::{CStr, CString}; | ||||||
| @ -16,6 +16,7 @@ use time::timeval_t; | |||||||
| use util::mem_util::from_user::*; | use util::mem_util::from_user::*; | ||||||
| use vm::{VMAreaFlags, VMResizeOptions}; | use vm::{VMAreaFlags, VMResizeOptions}; | ||||||
| use {fs, process, std, vm}; | use {fs, process, std, vm}; | ||||||
|  | use misc::{utsname_t, resource_t, rlimit_t}; | ||||||
| 
 | 
 | ||||||
| use super::*; | 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_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_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_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_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), | ||||||
|         SYS_FSYNC => do_fsync(arg0 as FileDesc), |         SYS_FSYNC => do_fsync(arg0 as FileDesc), | ||||||
|         SYS_FDATASYNC => do_fdatasync(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_RMDIR => do_rmdir(arg0 as *const i8), | ||||||
|         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), |         SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), | ||||||
|         SYS_UNLINK => do_unlink(arg0 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
 |         // IO multiplexing
 | ||||||
|         SYS_SELECT => do_select( |         SYS_SELECT => do_select( | ||||||
| @ -119,9 +124,19 @@ pub extern "C" fn dispatch_syscall( | |||||||
|             arg4 as *const FdOp, |             arg4 as *const FdOp, | ||||||
|         ), |         ), | ||||||
|         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_GETTID => do_gettid(), |         SYS_GETTID => do_gettid(), | ||||||
|         SYS_GETPPID => do_getppid(), |         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( |         SYS_CLONE => do_clone( | ||||||
|             arg0 as u32, |             arg0 as u32, | ||||||
| @ -171,6 +186,11 @@ pub extern "C" fn dispatch_syscall( | |||||||
| 
 | 
 | ||||||
|         SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), |         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
 |         // socket
 | ||||||
|         SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), |         SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), | ||||||
|         SYS_CONNECT => do_connect( |         SYS_CONNECT => do_connect( | ||||||
| @ -658,6 +678,30 @@ fn do_getppid() -> Result<isize, Error> { | |||||||
|     Ok(ppid as isize) |     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> { | fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> { | ||||||
|     check_mut_array(fds_u, 2)?; |     check_mut_array(fds_u, 2)?; | ||||||
|     // TODO: how to deal with open flags???
 |     // TODO: how to deal with open flags???
 | ||||||
| @ -778,6 +822,21 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> { | |||||||
|     Ok(0) |     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> { | fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> { | ||||||
|     let code = process::ArchPrctlCode::from_u32(code)?; |     let code = process::ArchPrctlCode::from_u32(code)?; | ||||||
|     check_mut_ptr(addr)?; |     check_mut_ptr(addr)?; | ||||||
| @ -1087,3 +1146,62 @@ impl AsSocket for FileRef { | |||||||
|             .ok_or(Error::new(Errno::EBADF, "not a socket")) |             .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 process::{get_current, Process, ProcessRef}; | ||||||
| use std::fmt; | use std::fmt; | ||||||
| 
 | 
 | ||||||
| // TODO: Rename VMSpace to VMUniverse
 |  | ||||||
| 
 |  | ||||||
| #[macro_use] | #[macro_use] | ||||||
| mod vm_range; | mod vm_range; | ||||||
| mod process_vm; |  | ||||||
| mod vm_area; | mod vm_area; | ||||||
| mod vm_domain; | mod process_vm; | ||||||
| mod vm_space; |  | ||||||
| 
 | 
 | ||||||
| pub use self::process_vm::ProcessVM; |  | ||||||
| pub use self::vm_range::{VMRange, VMRangeTrait}; | 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: separate proc and flags
 | ||||||
| // TODO: accept fd and offset
 | // TODO: accept fd and offset
 | ||||||
| @ -56,23 +54,6 @@ pub fn do_brk(addr: usize) -> Result<usize, Error> { | |||||||
| 
 | 
 | ||||||
| pub const PAGE_SIZE: usize = 4096; | 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)] | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
| pub enum VMGuardAreaType { | pub enum VMGuardAreaType { | ||||||
|     None, |     None, | ||||||
| @ -80,32 +61,14 @@ pub enum VMGuardAreaType { | |||||||
|     Dynamic { size: usize }, |     Dynamic { size: usize }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Copy, Clone, Debug, Default, PartialEq)] |  | ||||||
| pub struct VMAreaFlags(pub u32); |  | ||||||
| 
 | 
 | ||||||
| pub const VM_AREA_FLAG_R: u32 = 0x1; | #[derive(Clone, PartialEq, Default)] | ||||||
| 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)] |  | ||||||
| pub struct VMAllocOptions { | pub struct VMAllocOptions { | ||||||
|     size: usize, |     size: usize, | ||||||
|     addr: VMAddrOption, |     addr: VMAddrOption, | ||||||
|     growth: Option<VMGrowthType>, |     growth: VMGrowthType, | ||||||
|  |     description: String, | ||||||
|  |     fill_zeros: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl VMAllocOptions { | impl VMAllocOptions { | ||||||
| @ -128,7 +91,17 @@ impl VMAllocOptions { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn growth(&mut self, growth: VMGrowthType) -> Result<&mut Self, Error> { |     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) |         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)] | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
| pub enum VMAddrOption { | pub enum VMAddrOption { | ||||||
| @ -161,6 +125,12 @@ pub enum VMAddrOption { | |||||||
|     Beyond(usize), // Must be greater or equal to the given address
 |     Beyond(usize), // Must be greater or equal to the given address
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl Default for VMAddrOption { | ||||||
|  |     fn default() -> VMAddrOption { | ||||||
|  |         VMAddrOption::Any | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl VMAddrOption { | impl VMAddrOption { | ||||||
|     pub fn is_addr_given(&self) -> bool { |     pub fn is_addr_given(&self) -> bool { | ||||||
|         match self { |         match self { | ||||||
| @ -179,18 +149,27 @@ impl VMAddrOption { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /// How VMRange may grow:
 | /// How VMRange may grow:
 | ||||||
| #[derive(Clone, Copy, Debug, PartialEq)] | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
| pub enum VMGrowthType { | pub enum VMGrowthType { | ||||||
|  |     Fixed, | ||||||
|     Upward,   // e.g., mmaped regions grow upward
 |     Upward,   // e.g., mmaped regions grow upward
 | ||||||
|     Downward, // e.g., stacks grows downward
 |     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 { | pub struct VMResizeOptions { | ||||||
|     new_size: usize, |     new_size: usize, | ||||||
|     new_addr: Option<VMAddrOption>, |     new_addr: VMAddrOption, | ||||||
|  |     fill_zeros: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl VMResizeOptions { | impl VMResizeOptions { | ||||||
| @ -205,16 +184,12 @@ impl VMResizeOptions { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn addr(&mut self, new_addr: VMAddrOption) -> &mut Self { |     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 |         self | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| impl Default for VMResizeOptions { |  | ||||||
|     fn default() -> VMResizeOptions { |  | ||||||
|         VMResizeOptions { |  | ||||||
|             new_size: 0, |  | ||||||
|             new_addr: None, |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ lazy_static! { | |||||||
|             (addr, size) |             (addr, size) | ||||||
|         }; |         }; | ||||||
|         let vm_space = unsafe { |         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, |                 Ok(vm_space) => vm_space, | ||||||
|                 Err(_) => panic!("Failed to create a VMSpace"), |                 Err(_) => panic!("Failed to create a VMSpace"), | ||||||
|             } |             } | ||||||
| @ -27,11 +27,11 @@ extern "C" { | |||||||
| #[derive(Debug, Default)] | #[derive(Debug, Default)] | ||||||
| pub struct ProcessVM { | pub struct ProcessVM { | ||||||
|     //code_domain: VMDomain,
 |     //code_domain: VMDomain,
 | ||||||
|     data_domain: VMDomain, |     data_domain: Option<Box<VMDomain>>, | ||||||
|     code_vma: VMArea, |     code_vma: Option<Box<VMArea>>, | ||||||
|     data_vma: VMArea, |     data_vma: Option<Box<VMArea>>, | ||||||
|     heap_vma: VMArea, |     heap_vma: Option<Box<VMArea>>, | ||||||
|     stack_vma: VMArea, |     stack_vma: Option<Box<VMArea>>, | ||||||
|     mmap_vmas: Vec<Box<VMArea>>, |     mmap_vmas: Vec<Box<VMArea>>, | ||||||
|     brk: usize, |     brk: usize, | ||||||
| } | } | ||||||
| @ -44,29 +44,39 @@ impl ProcessVM { | |||||||
|         stack_size: usize, |         stack_size: usize, | ||||||
|         mmap_size: usize, |         mmap_size: usize, | ||||||
|     ) -> Result<ProcessVM, Error> { |     ) -> Result<ProcessVM, Error> { | ||||||
|         let data_domain_size = code_size + data_size + heap_size + stack_size + mmap_size; |         // Allocate the data domain from the global data space
 | ||||||
|         let mut data_domain = DATA_SPACE.lock().unwrap().alloc_domain(data_domain_size)?; |         let mut data_domain = { | ||||||
| 
 |             let data_domain_size = code_size + data_size + heap_size | ||||||
|         let (code_vma, data_vma, heap_vma, stack_vma) = ProcessVM::alloc_vmas( |                                  + stack_size + mmap_size; | ||||||
|             &mut data_domain, |             let data_domain = DATA_SPACE.lock().unwrap().alloc_domain( | ||||||
|             code_size, |                                     data_domain_size, "data_domain")?; | ||||||
|             data_size, |             data_domain | ||||||
|             heap_size, |         }; | ||||||
|             stack_size, |         // 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
 |         // Initial value of the program break
 | ||||||
|         let brk = heap_vma.get_start(); |         let brk = heap_vma.get_start(); | ||||||
|         // No mmapped vmas initially
 |         // No mmapped vmas initially
 | ||||||
|         let mmap_vmas = Vec::new(); |         let mmap_vmas = Vec::new(); | ||||||
| 
 | 
 | ||||||
|         let vm = ProcessVM { |         let vm = ProcessVM { | ||||||
|             data_domain, |             data_domain: Some(Box::new(data_domain)), | ||||||
|             code_vma, |             code_vma: Some(Box::new(code_vma)), | ||||||
|             data_vma, |             data_vma: Some(Box::new(data_vma)), | ||||||
|             heap_vma, |             heap_vma: Some(Box::new(heap_vma)), | ||||||
|             stack_vma, |             stack_vma: Some(Box::new(stack_vma)), | ||||||
|             mmap_vmas, |             mmap_vmas: mmap_vmas, | ||||||
|             brk, |             brk: brk, | ||||||
|         }; |         }; | ||||||
|         Ok(vm) |         Ok(vm) | ||||||
|     } |     } | ||||||
| @ -79,11 +89,13 @@ impl ProcessVM { | |||||||
|         stack_size: usize, |         stack_size: usize, | ||||||
|     ) -> Result<(VMArea, VMArea, VMArea, VMArea), Error> { |     ) -> Result<(VMArea, VMArea, VMArea, VMArea), Error> { | ||||||
|         let mut addr = data_domain.get_start(); |         let mut addr = data_domain.get_start(); | ||||||
| 
 |  | ||||||
|         let mut alloc_vma_continuously = |         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)?; |                 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)?; |                 let new_vma = data_domain.alloc_area(&options, flags)?; | ||||||
|                 *addr += size; |                 *addr += size; | ||||||
|                 Ok(new_vma) |                 Ok(new_vma) | ||||||
| @ -92,39 +104,42 @@ impl ProcessVM { | |||||||
|         let rx_flags = VMAreaFlags(VM_AREA_FLAG_R | VM_AREA_FLAG_X); |         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 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 code_vma = alloc_vma_continuously(&mut addr, "code_vma", code_size, | ||||||
|         let data_vma = alloc_vma_continuously(&mut addr, data_size, rw_flags, VMGrowthType::Fixed)?; |                                               rx_flags, VMGrowthType::Fixed, true)?; | ||||||
|         let heap_vma = alloc_vma_continuously(&mut addr, 0, rw_flags, VMGrowthType::Upward)?; |         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
 |         // Preserve the space for heap
 | ||||||
|         addr += heap_size; |         addr += heap_size; | ||||||
|         // After the heap is the stack
 |         // After the heap is the stack
 | ||||||
|         let stack_vma = |         let stack_vma = alloc_vma_continuously(&mut addr, "stack_vma", stack_size, | ||||||
|             alloc_vma_continuously(&mut addr, stack_size, rw_flags, VMGrowthType::Downward)?; |                                                rw_flags, VMGrowthType::Downward, false)?; | ||||||
|         Ok((code_vma, data_vma, heap_vma, stack_vma)) |         Ok((code_vma, data_vma, heap_vma, stack_vma)) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_base_addr(&self) -> usize { |     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 { |     pub fn get_code_vma(&self) -> &VMArea { | ||||||
|         &self.code_vma |         &self.code_vma.as_ref().unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_data_vma(&self) -> &VMArea { |     pub fn get_data_vma(&self) -> &VMArea { | ||||||
|         &self.data_vma |         &self.data_vma.as_ref().unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_heap_vma(&self) -> &VMArea { |     pub fn get_heap_vma(&self) -> &VMArea { | ||||||
|         &self.heap_vma |         &self.heap_vma.as_ref().unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_stack_vma(&self) -> &VMArea { |     pub fn get_stack_vma(&self) -> &VMArea { | ||||||
|         &self.stack_vma |         &self.stack_vma.as_ref().unwrap() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn get_stack_top(&self) -> usize { |     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>] { |     pub fn get_mmap_vmas(&self) -> &[Box<VMArea>] { | ||||||
| @ -156,36 +171,37 @@ impl ProcessVM { | |||||||
|                     if addr < mmap_start_addr { |                     if addr < mmap_start_addr { | ||||||
|                         return Err(Error::new(Errno::EINVAL, "Beyond valid memory range")); |                         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)?; |                 .growth(VMGrowthType::Upward)?; | ||||||
|             alloc_options |             alloc_options | ||||||
|         }; |         }; | ||||||
|         // TODO: when failed, try to resize data_domain
 |         // 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(); |         let addr = new_mmap_vma.get_start(); | ||||||
|         self.mmap_vmas.push(Box::new(new_mmap_vma)); |         self.mmap_vmas.push(Box::new(new_mmap_vma)); | ||||||
|         Ok(addr) |         Ok(addr) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // 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> { |     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.
 |  | ||||||
| 
 |  | ||||||
|         let mmap_vma_i = { |         let mmap_vma_i = { | ||||||
|             let mmap_vma_i = self |             let mmap_vma_i = self | ||||||
|                 .get_mmap_vmas() |                 .get_mmap_vmas() | ||||||
|                 .iter() |                 .iter() | ||||||
|                 .position(|vma| vma.get_start() == addr && vma.get_end() == addr + size); |                 .position(|vma| vma.get_start() == addr && vma.get_end() == addr + size); | ||||||
|             if mmap_vma_i.is_none() { |             if mmap_vma_i.is_none() { | ||||||
|                 return Ok(()); |                 return errno!(EINVAL, "memory area not found"); | ||||||
|             } |             } | ||||||
|             mmap_vma_i.unwrap() |             mmap_vma_i.unwrap() | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let mut removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); |         let removed_mmap_vma = self.mmap_vmas.swap_remove(mmap_vma_i); | ||||||
|         self.data_domain.dealloc_area(&mut removed_mmap_vma); |         self.get_data_domain_mut().dealloc_area(unbox(removed_mmap_vma)); | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -200,43 +216,52 @@ impl ProcessVM { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn brk(&mut self, new_brk: usize) -> Result<usize, Error> { |     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 { |         if new_brk == 0 { | ||||||
|             return Ok(self.get_brk()); |             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"); |             return errno!(EINVAL, "New brk address is too low"); | ||||||
|         } else if new_brk <= self.heap_vma.get_end() { |         } else if new_brk > heap_end { | ||||||
|             self.brk = new_brk; |             let resize_options = { | ||||||
|             return Ok(new_brk); |                 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
 |     fn get_data_domain_mut(&mut self) -> &mut Box<VMDomain> { | ||||||
|         let resize_options = { |         self.data_domain.as_mut().unwrap() | ||||||
|             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) |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Drop for ProcessVM { | impl Drop for ProcessVM { | ||||||
|     fn drop(&mut self) { |     fn drop(&mut self) { | ||||||
|         let data_domain = &mut self.data_domain; |  | ||||||
| 
 |  | ||||||
|         // Remove all vma from the domain
 |         // Remove all vma from the domain
 | ||||||
|         data_domain.dealloc_area(&mut self.code_vma); |         { | ||||||
|         data_domain.dealloc_area(&mut self.data_vma); |             let data_domain = self.data_domain.as_mut().unwrap(); | ||||||
|         data_domain.dealloc_area(&mut self.heap_vma); |             data_domain.dealloc_area(unbox(self.code_vma.take().unwrap())); | ||||||
|         data_domain.dealloc_area(&mut self.stack_vma); |             data_domain.dealloc_area(unbox(self.data_vma.take().unwrap())); | ||||||
|         for mmap_vma in &mut self.mmap_vmas { |             data_domain.dealloc_area(unbox(self.heap_vma.take().unwrap())); | ||||||
|             data_domain.dealloc_area(mmap_vma); |             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
 |         // 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::*; | 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 { |     pub fn get_flags(&self) -> &VMAreaFlags { | ||||||
|         &self.flags |         &self.flags | ||||||
|     } |     } | ||||||
| @ -9,3 +96,25 @@ impl super::VMArea { | |||||||
|         &mut self.flags |         &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)] | #[derive(Debug)] | ||||||
| pub struct VMRange { | pub struct VMRange { | ||||||
|     inner: VMRangeInner, |     inner: VMRangeInner, | ||||||
|     parent_range: *const VMRange, |  | ||||||
|     sub_ranges: Option<Vec<VMRangeInner>>, |     sub_ranges: Option<Vec<VMRangeInner>>, | ||||||
|  |     is_dealloced: bool, | ||||||
|  |     description: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl_vmrange_trait_for!(VMRange, inner); | ||||||
|  | 
 | ||||||
| impl VMRange { | 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 { |         if start % PAGE_SIZE != 0 || end % PAGE_SIZE != 0 { | ||||||
|             return errno!(EINVAL, "Invalid start and/or end"); |             return errno!(EINVAL, "Invalid start and/or end"); | ||||||
|         } |         } | ||||||
|         Ok(VMRange { |         Ok(VMRange { | ||||||
|             inner: VMRangeInner::new(start, end, growth), |             inner: VMRangeInner::new(start, end, growth), | ||||||
|             parent_range: 0 as *const VMRange, |  | ||||||
|             sub_ranges: None, |             sub_ranges: None, | ||||||
|  |             is_dealloced: false, | ||||||
|  |             description: description.to_owned(), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn alloc_subrange(&mut self, options: &VMAllocOptions) -> Result<VMRange, Error> { |     pub fn alloc_subrange(&mut self, options: &VMAllocOptions) -> Result<VMRange, Error> { | ||||||
|         // Get valid parameters from options
 |         debug_assert!(!self.is_dealloced); | ||||||
|         let size = options.size; |  | ||||||
|         let addr = options.addr; |  | ||||||
|         let growth = options.growth.unwrap_or(VMGrowthType::Fixed); |  | ||||||
| 
 | 
 | ||||||
|         // Lazy initialize the subrange array upon the first allocation
 |         // Lazy initialize the subrange array upon the first allocation
 | ||||||
|         if !self.has_subranges() { |         if self.sub_ranges.is_none() { | ||||||
|             self.init_subranges()?; |             self.init_subrange_array()?; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Find a free space for allocating a VMRange
 |         // Find a free space that satisfies the options
 | ||||||
|         let free_space = { |         let free_space = self.look_for_free_space(options)?; | ||||||
|             // Look for the minimal big-enough free space
 |         // Allocate a new subrange from the free space
 | ||||||
|             let mut min_big_enough_free_space: Option<FreeSpace> = None; |         let (new_subrange_idx, new_subrange_inner) = { | ||||||
|             let sub_ranges = self.get_subranges(); |             let (new_subrange_start, new_subrange_end) = | ||||||
|             for (idx, range_pair) in sub_ranges.windows(2).enumerate() { |                 self.alloc_from_free_space(&free_space, options); | ||||||
|                 let pre_range = &range_pair[0]; |             debug_assert!(free_space.contains(new_subrange_start)); | ||||||
|                 let next_range = &range_pair[1]; |             debug_assert!(free_space.contains(new_subrange_end)); | ||||||
| 
 | 
 | ||||||
|                 let mut free_range = { |             (free_space.index_in_subranges, VMRangeInner::new( | ||||||
|                     let free_range_start = pre_range.get_end(); |                     new_subrange_start, new_subrange_end, options.growth)) | ||||||
|                     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 |  | ||||||
|                 }; |  | ||||||
| 
 |  | ||||||
|                 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() |         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,
 |         // Although there are two copies of the newly created VMRangeInner obj,
 | ||||||
|         // we can keep them in sync as all mutation on VMRange object must
 |         // we can keep them in sync as all mutation on VMRange object must
 | ||||||
|         // be carried out through dealloc_subrange() and resize_subrange() that
 |         // 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.
 |         // other in child, in dealloc_subrange and resize_subrange functions.
 | ||||||
|         Ok(VMRange { |         Ok(VMRange { | ||||||
|             inner: new_subrange_inner, |             inner: new_subrange_inner, | ||||||
|             parent_range: self as *const VMRange, |  | ||||||
|             sub_ranges: None, |             sub_ranges: None, | ||||||
|  |             is_dealloced: false, | ||||||
|  |             description: options.description.clone(), | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn dealloc_subrange(&mut self, subrange: &mut VMRange) { |     pub fn dealloc_subrange(&mut self, subrange: &mut VMRange) { | ||||||
|         self.ensure_subrange_is_a_child(subrange); |         debug_assert!(!self.is_dealloced); | ||||||
|         if subrange.has_subranges() { |         debug_assert!(!subrange.is_dealloced); | ||||||
|             panic!("A range can only be dealloc'ed when it has no sub-ranges"); |         debug_assert!(self.sub_ranges.is_some()); | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // Remove the sub-range
 |         // Remove the sub-range
 | ||||||
|         let domain_i = self.position_subrange(subrange); |         let domain_i = self.position_subrange(subrange); | ||||||
|         self.get_subranges_mut().remove(domain_i); |         self.get_subranges_mut().remove(domain_i); | ||||||
| 
 |  | ||||||
|         // When all sub-ranges are removed, remove the sub-range array
 |         // When all sub-ranges are removed, remove the sub-range array
 | ||||||
|         if self.get_subranges().len() == 2 { |         if self.get_subranges().len() == 2 { | ||||||
|             // two sentinel sub-ranges excluded
 |             // two sentinel sub-ranges excluded
 | ||||||
|             self.sub_ranges = None; |             self.sub_ranges = None; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Mark a range as dealloc'ed
 |         subrange.inner.end = subrange.inner.start; | ||||||
|         subrange.mark_as_dealloced(); |         subrange.is_dealloced = true; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn resize_subrange( |     pub fn resize_subrange( | ||||||
| @ -199,7 +127,9 @@ impl VMRange { | |||||||
|         subrange: &mut VMRange, |         subrange: &mut VMRange, | ||||||
|         options: &VMResizeOptions, |         options: &VMResizeOptions, | ||||||
|     ) -> Result<(), Error> { |     ) -> 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
 |         // Get valid parameters from options
 | ||||||
|         let new_size = options.new_size; |         let new_size = options.new_size; | ||||||
| @ -219,11 +149,15 @@ impl VMRange { | |||||||
|         } |         } | ||||||
|         // Grow
 |         // Grow
 | ||||||
|         else { |         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
 |         // Use dummy VMRange as sentinel object at both ends to make the allocation
 | ||||||
|         // and deallocation algorithm simpler
 |         // and deallocation algorithm simpler
 | ||||||
|         let start = self.get_start(); |         let start = self.get_start(); | ||||||
| @ -234,11 +168,126 @@ impl VMRange { | |||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn ensure_subrange_is_a_child(&self, subrange: &VMRange) { |     // Find a free space for allocating a sub VMRange
 | ||||||
|         // FIXME:
 |     fn look_for_free_space(&mut self, options: &VMAllocOptions) -> Result<FreeSpace, Error> { | ||||||
|         /*if subrange.parent_range != self as *const VMRange {
 |         // TODO: reduce the complexity from O(N) to O(log(N)), where N is
 | ||||||
|             panic!("This range does not contain the given sub-range"); |         // 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 { |     fn position_subrange(&self, subrange: &VMRange) -> usize { | ||||||
| @ -257,10 +306,6 @@ impl VMRange { | |||||||
|         self.sub_ranges.as_mut().unwrap() |         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> { |     fn shrink_subrange_to(&mut self, subrange: &mut VMRange, new_size: usize) -> Result<(), Error> { | ||||||
|         let subrange_i = self.position_subrange(subrange); |         let subrange_i = self.position_subrange(subrange); | ||||||
|         let subranges = self.get_subranges_mut(); |         let subranges = self.get_subranges_mut(); | ||||||
| @ -304,51 +349,61 @@ impl VMRange { | |||||||
|         Ok(()) |         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 subrange_i = self.position_subrange(subrange); | ||||||
|         let subranges = self.get_subranges_mut(); |         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 { |         if subrange.inner.growth == VMGrowthType::Upward { | ||||||
|             // Can we grow?
 |             // Can we grow upward?
 | ||||||
|             let max_new_size = { |             let max_new_size = { | ||||||
|                 let next_subrange = &subranges[subrange_i + 1]; |                 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 { |             if new_size > max_new_size { | ||||||
|                 return errno!(ENOMEM, "Cannot grow to new size"); |                 return errno!(ENOMEM, "Cannot grow to new size"); | ||||||
|             } |             } | ||||||
|             // Do grow
 |             // 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; |             subrange.inner.end = subrange_new_end; | ||||||
|             // Sync state
 |             // Sync state
 | ||||||
|             subranges[subrange_i].end = subrange_new_end; |             subranges[subrange_i].end = subrange_new_end; | ||||||
|         } else { |             // Init memory
 | ||||||
|             // self.growth == VMGrowthType::Downward
 |             if fill_zeros { | ||||||
|             // Can we grow?
 |                 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 max_new_size = { | ||||||
|                 let pre_subrange = &subranges[subrange_i - 1]; |                 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 { |             if new_size > max_new_size { | ||||||
|                 return errno!(ENOMEM, "Cannot grow to new size"); |                 return errno!(ENOMEM, "Cannot grow to new size"); | ||||||
|             } |             } | ||||||
|             // Do grow
 |             // 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; |             subrange.inner.start = subrange_new_start; | ||||||
|             // Sync state
 |             // Sync state
 | ||||||
|             subranges[subrange_i].start = subrange_new_start; |             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(()) |         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 { | impl PartialOrd for VMRange { | ||||||
| @ -365,29 +420,15 @@ impl PartialEq for VMRange { | |||||||
| 
 | 
 | ||||||
| impl Drop for VMRange { | impl Drop for VMRange { | ||||||
|     fn drop(&mut self) { |     fn drop(&mut self) { | ||||||
|         if !self.is_dealloced() { |         if !self.is_dealloced { | ||||||
|             println!("VMRange::drop::panic1"); |  | ||||||
|             panic!("A range must be dealloc'ed before drop"); |             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 Send for VMRange {} | ||||||
| unsafe impl Sync 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)] | #[derive(Clone, Copy)] | ||||||
| pub struct VMRangeInner { | pub struct VMRangeInner { | ||||||
| @ -398,6 +439,8 @@ pub struct VMRangeInner { | |||||||
| 
 | 
 | ||||||
| impl VMRangeInner { | impl VMRangeInner { | ||||||
|     pub fn new(start: usize, end: usize, growth: VMGrowthType) -> VMRangeInner { |     pub fn new(start: usize, end: usize, growth: VMGrowthType) -> VMRangeInner { | ||||||
|  |         debug_assert!(start % PAGE_SIZE == 0); | ||||||
|  |         debug_assert!(end % PAGE_SIZE == 0); | ||||||
|         VMRangeInner { |         VMRangeInner { | ||||||
|             start: start, |             start: start, | ||||||
|             end: end, |             end: end, | ||||||
| @ -478,9 +521,14 @@ impl FreeSpace { | |||||||
|         pressure += if self.may_neighbor_grow.1 { 1 } else { 0 }; |         pressure += if self.may_neighbor_grow.1 { 1 } else { 0 }; | ||||||
|         pressure |         pressure | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     fn get_size(&self) -> usize { |     fn get_size(&self) -> usize { | ||||||
|         self.end - self.start |         self.end - self.start | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     fn contains(&self, addr: usize) -> bool { | ||||||
|  |         self.start <= addr && addr < self.end | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl PartialEq for FreeSpace { | 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
 | # 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 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
 | # 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/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; |         return fd; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (access(FILE_NAME, F_OK) < 0) { | ||||||
|  |         printf("cannot access the new file\n"); | ||||||
|  |         return -1; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     ret = ftruncate(fd, TRUNC_LEN); |     ret = ftruncate(fd, TRUNC_LEN); | ||||||
|     if (ret < 0) { |     if (ret < 0) { | ||||||
|         printf("failed to ftruncate the file\n"); |         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