[libos] Add support for SHM
This commit is contained in:
		
							parent
							
								
									c84c3b7b88
								
							
						
					
					
						commit
						ed96ce55dd
					
				
							
								
								
									
										7
									
								
								src/libos/src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								src/libos/src/ipc/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| mod shm; | ||||
| mod syscalls; | ||||
| 
 | ||||
| pub use self::shm::{key_t, shmids_t, SHM_MANAGER}; | ||||
| pub use self::syscalls::{do_shmat, do_shmctl, do_shmdt, do_shmget}; | ||||
							
								
								
									
										509
									
								
								src/libos/src/ipc/shm.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										509
									
								
								src/libos/src/ipc/shm.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,509 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| use crate::fs::FileMode; | ||||
| use crate::process::{do_getegid, do_geteuid, gid_t, uid_t, ThreadRef}; | ||||
| use crate::time::{do_gettimeofday, time_t}; | ||||
| use crate::vm::{ | ||||
|     ChunkRef, VMInitializer, VMMapOptionsBuilder, VMPerms, VMRange, USER_SPACE_VM_MANAGER, | ||||
| }; | ||||
| use std::collections::{HashMap, HashSet}; | ||||
| 
 | ||||
| #[allow(non_camel_case_types)] | ||||
| pub type key_t = u32; | ||||
| pub type ShmId = u32; | ||||
| pub type CmdId = u32; | ||||
| 
 | ||||
| // min shared seg size (bytes)
 | ||||
| const SHMMIN: usize = 1; | ||||
| // max shared seg size (bytes)
 | ||||
| const SHMMAX: usize = (usize::MAX - (1_usize << 24)); | ||||
| // max num of segs system wide,
 | ||||
| // also indicates the max shmid - 1 in Occlum
 | ||||
| const SHMMNI: ShmId = 4096; | ||||
| 
 | ||||
| const IPC_PRIVATE: key_t = 0; | ||||
| 
 | ||||
| // For cmd in shmctl()
 | ||||
| const IPC_RMID: CmdId = 0; | ||||
| const IPC_SET: CmdId = 1; | ||||
| const IPC_STAT: CmdId = 2; | ||||
| const IPC_INFO: CmdId = 3; | ||||
| const SHM_LOCK: CmdId = 11; | ||||
| const SHM_UNLOCK: CmdId = 12; | ||||
| const SHM_STAT: CmdId = 13; | ||||
| const SHM_INFO: CmdId = 14; | ||||
| const SHM_STAT_ANY: CmdId = 15; | ||||
| 
 | ||||
| #[allow(non_camel_case_types)] | ||||
| #[derive(Debug)] | ||||
| #[repr(C)] | ||||
| struct ipc_perm_t { | ||||
|     key: key_t, | ||||
|     uid: uid_t, | ||||
|     gid: gid_t, | ||||
|     cuid: uid_t, | ||||
|     cgid: gid_t, | ||||
|     mode: u16, | ||||
|     pad1: u16, | ||||
|     seq: u16, | ||||
|     pad2: u16, | ||||
|     unused1: u64, | ||||
|     unused2: u64, | ||||
| } | ||||
| 
 | ||||
| #[allow(non_camel_case_types)] | ||||
| #[derive(Debug)] | ||||
| #[repr(C)] | ||||
| pub struct shmids_t { | ||||
|     shm_perm: ipc_perm_t, | ||||
|     shm_segsz: size_t, | ||||
|     shm_atime: time_t, | ||||
|     shm_dtime: time_t, | ||||
|     shm_ctime: time_t, | ||||
|     shm_cpid: pid_t, | ||||
|     shm_lpid: pid_t, | ||||
|     shm_nattach: u64, | ||||
|     unused1: u64, | ||||
|     unused2: u64, | ||||
| } | ||||
| 
 | ||||
| // shared memory segment status
 | ||||
| bitflags! { | ||||
|     struct ShmStatus : u16 { | ||||
|         // segment will be destroyed on last detach
 | ||||
|         const SHM_DEST = 0o1000; | ||||
|         // segment will not be swapped, unused now
 | ||||
|         const SHM_LOCKED = 0o2000; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bitflags! { | ||||
|     pub struct ShmFlags: u32 { | ||||
|         const IPC_CREAT = 0o1000; | ||||
|         const IPC_EXCL = 0o2000; | ||||
| 
 | ||||
|         /// read by owner
 | ||||
|         const S_IRUSR = FileMode::S_IRUSR.bits() as u32; | ||||
|         /// write by owner
 | ||||
|         const S_IWUSR = FileMode::S_IWUSR.bits() as u32; | ||||
|         /// execute/search by owner
 | ||||
|         const S_IXUSR = FileMode::S_IXUSR.bits() as u32; | ||||
|         /// read by group
 | ||||
|         const S_IRGRP = FileMode::S_IRGRP.bits() as u32; | ||||
|         /// write by group
 | ||||
|         const S_IWGRP = FileMode::S_IWGRP.bits() as u32; | ||||
|         /// execute/search by group
 | ||||
|         const S_IXGRP = FileMode::S_IXGRP.bits() as u32; | ||||
|         /// read by others
 | ||||
|         const S_IROTH = FileMode::S_IROTH.bits() as u32; | ||||
|         /// write by others
 | ||||
|         const S_IWOTH = FileMode::S_IWOTH.bits() as u32; | ||||
|         /// execute/search by others
 | ||||
|         const S_IXOTH = FileMode::S_IXOTH.bits() as u32; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl ShmFlags { | ||||
|     fn to_file_mode(&self) -> FileMode { | ||||
|         let mut shmflgs = *self; | ||||
|         shmflgs.remove(ShmFlags::IPC_CREAT); | ||||
|         shmflgs.remove(ShmFlags::IPC_EXCL); | ||||
|         let file_mode = FileMode::from_bits(shmflgs.bits as u16 & FileMode::all().bits()).unwrap(); | ||||
|         file_mode | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| struct ShmSegment { | ||||
|     shmid: ShmId, | ||||
|     key: key_t, | ||||
| 
 | ||||
|     uid: uid_t, | ||||
|     gid: gid_t, | ||||
|     cuid: uid_t, | ||||
|     cgid: gid_t, | ||||
|     mode: FileMode, | ||||
|     status: ShmStatus, | ||||
| 
 | ||||
|     shm_atime: time_t, | ||||
|     shm_dtime: time_t, | ||||
|     shm_ctime: time_t, | ||||
| 
 | ||||
|     shm_cpid: pid_t, | ||||
|     shm_lpid: pid_t, | ||||
| 
 | ||||
|     shm_nattach: u64, | ||||
|     chunk: ChunkRef, | ||||
|     process_set: HashSet<pid_t>, | ||||
| } | ||||
| 
 | ||||
| impl ShmSegment { | ||||
|     fn new(shmid: ShmId, key: key_t, size: size_t, mode: FileMode) -> Result<Self> { | ||||
|         let vm_option = VMMapOptionsBuilder::default() | ||||
|             .size(size) | ||||
|             // Currently, Occlum only support shared memory segment with rw permission
 | ||||
|             .perms(VMPerms::READ | VMPerms::WRITE) | ||||
|             .initializer(VMInitializer::FillZeros()) | ||||
|             .build()?; | ||||
|         let chunk = USER_SPACE_VM_MANAGER.internal().mmap_chunk(&vm_option)?; | ||||
| 
 | ||||
|         Ok(ShmSegment { | ||||
|             shmid: shmid, | ||||
|             key: key, | ||||
|             uid: do_geteuid().unwrap() as u32, | ||||
|             cuid: do_geteuid().unwrap() as u32, | ||||
|             gid: do_getegid().unwrap() as u32, | ||||
|             cgid: do_getegid().unwrap() as u32, | ||||
|             mode: mode, | ||||
|             status: ShmStatus::empty(), | ||||
|             shm_atime: 0, | ||||
|             shm_dtime: 0, | ||||
|             shm_ctime: ShmManager::current_time(), | ||||
|             shm_cpid: current!().process().pid(), | ||||
|             shm_lpid: 0, | ||||
|             shm_nattach: 0, | ||||
|             chunk: chunk, | ||||
|             process_set: HashSet::new(), | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     fn check_perm(&self) -> Result<()> { | ||||
|         // TODO: Add permission control
 | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn set_destruction(&mut self) { | ||||
|         self.status.insert(ShmStatus::SHM_DEST) | ||||
|     } | ||||
| 
 | ||||
|     fn is_destruction(&self) -> bool { | ||||
|         self.status.contains(ShmStatus::SHM_DEST) | ||||
|     } | ||||
| 
 | ||||
|     fn shm_start(&self) -> usize { | ||||
|         self.chunk.range().start() | ||||
|     } | ||||
| 
 | ||||
|     fn shm_size(&self) -> usize { | ||||
|         self.chunk.range().size() | ||||
|     } | ||||
| 
 | ||||
|     fn shm_add_pid(&mut self, pid: &pid_t) -> Result<()> { | ||||
|         if self.process_set.contains(pid) { | ||||
|             return_errno!(EINVAL, "this pid has been attached to the shm"); | ||||
|         } | ||||
|         self.process_set.insert(*pid); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn shm_remove_pid(&mut self, pid: &pid_t) -> Result<()> { | ||||
|         if !self.process_set.contains(pid) { | ||||
|             return_errno!(EINVAL, " this pid has not been attached to the shm"); | ||||
|         } | ||||
|         self.process_set.remove(&pid); | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for ShmSegment { | ||||
|     fn drop(&mut self) { | ||||
|         debug!("drop shm: {:?}", self); | ||||
|         assert!(self.shm_nattach == 0); | ||||
|         assert!(self.process_set.len() == 0); | ||||
|         USER_SPACE_VM_MANAGER | ||||
|             .internal() | ||||
|             .munmap_chunk(&self.chunk, None); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| struct ShmIdManager { | ||||
|     used_id: HashSet<ShmId>, | ||||
|     free_num: u32, | ||||
|     last_alloc_id: ShmId, | ||||
| } | ||||
| 
 | ||||
| impl ShmIdManager { | ||||
|     fn new() -> Self { | ||||
|         let used_id = HashSet::new(); | ||||
|         let free_num = SHMMNI as u32; | ||||
|         let last_alloc_id = SHMMNI - 1; | ||||
|         ShmIdManager { | ||||
|             used_id, | ||||
|             free_num, | ||||
|             last_alloc_id, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Always return next free id for shmid
 | ||||
|     fn get_new_shmid(&mut self) -> Result<ShmId> { | ||||
|         if self.free_num == 0 { | ||||
|             return_errno!(ENOSPC, "all possible shared memory IDs have been taken"); | ||||
|         } else { | ||||
|             self.free_num -= 1; | ||||
|         } | ||||
|         let mut id = self.last_alloc_id + 1; | ||||
|         loop { | ||||
|             if id == SHMMNI { | ||||
|                 id = 0; | ||||
|             } | ||||
|             if !self.used_id.contains(&id) { | ||||
|                 break; | ||||
|             } | ||||
|             id += 1; | ||||
|         } | ||||
|         self.last_alloc_id = id; | ||||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     fn free_shmid(&mut self, shmid: &ShmId) -> Result<()> { | ||||
|         self.free_num += 1; | ||||
|         self.used_id.remove(shmid); | ||||
|         Ok(()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| lazy_static! { | ||||
|     pub static ref SHM_MANAGER: ShmManager = ShmManager::new(); | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| pub struct ShmManager { | ||||
|     shm_segments: RwLock<HashMap<ShmId, ShmSegment>>, | ||||
|     shmid_manager: RwLock<ShmIdManager>, | ||||
| } | ||||
| 
 | ||||
| impl ShmManager { | ||||
|     fn new() -> Self { | ||||
|         ShmManager { | ||||
|             shm_segments: RwLock::new(HashMap::new()), | ||||
|             shmid_manager: RwLock::new(ShmIdManager::new()), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn current_time() -> time_t { | ||||
|         do_gettimeofday().sec() | ||||
|     } | ||||
| 
 | ||||
|     fn get_new_shmid(&self) -> Result<ShmId> { | ||||
|         let mut shmid_manager = self.shmid_manager.write().unwrap(); | ||||
|         shmid_manager.get_new_shmid() | ||||
|     } | ||||
| 
 | ||||
|     fn free_shmid(&self, shmid: &ShmId) -> Result<()> { | ||||
|         let mut shmid_manager = self.shmid_manager.write().unwrap(); | ||||
|         shmid_manager.free_shmid(&shmid) | ||||
|     } | ||||
| 
 | ||||
|     fn shmctl_rmshm(&self, shmid: ShmId) -> Result<()> { | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         let shm = shm_segments.get_mut(&shmid); | ||||
| 
 | ||||
|         if let Some(shm) = shm { | ||||
|             shm.shm_ctime = ShmManager::current_time(); | ||||
|             shm.set_destruction(); | ||||
|             if shm.shm_nattach == 0 { | ||||
|                 let shmid = shm.shmid; | ||||
|                 self.free_shmid(&shmid)?; | ||||
|                 shm_segments.remove(&shmid); | ||||
|             } | ||||
|         } else { | ||||
|             return_errno!(EINVAL, "cannot find shm by shmid"); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     fn shmctl_ipcstat(&self, shmid: ShmId, buf: Option<&mut shmids_t>) -> Result<()> { | ||||
|         let shm_segments = self.shm_segments.read().unwrap(); | ||||
|         let shm = shm_segments.get(&shmid); | ||||
|         if let Some(shm) = shm { | ||||
|             shm.check_perm()?; | ||||
|             let mut buf = match buf { | ||||
|                 Some(buf) => buf, | ||||
|                 None => return_errno!(EFAULT, "buf is empty"), | ||||
|             }; | ||||
|             let shm_perm = ipc_perm_t { | ||||
|                 key: shm.key, | ||||
|                 uid: shm.uid, | ||||
|                 gid: shm.uid, | ||||
|                 cuid: shm.cuid, | ||||
|                 cgid: shm.cgid, | ||||
|                 mode: shm.mode.bits() | shm.status.bits(), | ||||
|                 pad1: 0, | ||||
|                 seq: 0, | ||||
|                 pad2: 0, | ||||
|                 unused1: 0, | ||||
|                 unused2: 0, | ||||
|             }; | ||||
|             let shmids = shmids_t { | ||||
|                 shm_perm: shm_perm, | ||||
|                 shm_segsz: shm.shm_size(), | ||||
|                 shm_atime: shm.shm_atime, | ||||
|                 shm_dtime: shm.shm_dtime, | ||||
|                 shm_ctime: shm.shm_ctime, | ||||
|                 shm_cpid: shm.shm_cpid, | ||||
|                 shm_lpid: shm.shm_lpid, | ||||
|                 shm_nattach: shm.shm_nattach, | ||||
|                 unused1: 0, | ||||
|                 unused2: 0, | ||||
|             }; | ||||
|             *buf = shmids; | ||||
|         } else { | ||||
|             return_errno!(EINVAL, "cannot find shm by shmid"); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn do_shmget(&self, key: key_t, size: usize, shmflg: ShmFlags) -> Result<ShmId> { | ||||
|         debug!( | ||||
|             "do_shmget: key: {:?}, size: {:?}, shmflg: {:?}", | ||||
|             key, size, shmflg | ||||
|         ); | ||||
| 
 | ||||
|         // Check the size from user
 | ||||
|         if size < SHMMIN || size > SHMMAX { | ||||
|             return_errno!(EINVAL, "invalid size"); | ||||
|         } | ||||
| 
 | ||||
|         let mut mode = shmflg.to_file_mode(); | ||||
|         // The creator and user must have the read and write permission to the segment
 | ||||
|         let read_per = mode.contains(FileMode::S_IRUSR) | ||||
|             || mode.contains(FileMode::S_IRGRP) | ||||
|             || mode.contains(FileMode::S_IROTH); | ||||
|         let write_per = mode.contains(FileMode::S_IWUSR) | ||||
|             || mode.contains(FileMode::S_IWGRP) | ||||
|             || mode.contains(FileMode::S_IWOTH); | ||||
|         if !(read_per && write_per) { | ||||
|             return_errno!( | ||||
|                 EINVAL, | ||||
|                 "shared memory segement in occlum should have rw permission now" | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         let shmid = if key == IPC_PRIVATE { | ||||
|             let shmid = self.get_new_shmid()?; | ||||
|             let shm = ShmSegment::new(shmid, key, size, mode)?; | ||||
|             shm_segments.insert(shm.shmid, shm); | ||||
|             shmid | ||||
|         } else { | ||||
|             // Get the shm from key if the segment is not marked to be destroyed
 | ||||
|             let shm = shm_segments | ||||
|                 .values() | ||||
|                 .find(|&shm| !shm.is_destruction() && shm.key == key); | ||||
|             let shmid = if let Some(shm) = shm { | ||||
|                 if shmflg.contains(ShmFlags::IPC_CREAT) && shmflg.contains(ShmFlags::IPC_EXCL) { | ||||
|                     return_errno!( | ||||
|                         EEXIST, | ||||
|                         "the shared memory segment already exists for given key" | ||||
|                     ); | ||||
|                 } | ||||
|                 // The size from user must be less than the actual size
 | ||||
|                 if size > shm.shm_size() { | ||||
|                     return_errno!(EINVAL, "the size from user is too large"); | ||||
|                 } | ||||
|                 // Check the permission
 | ||||
|                 shm.check_perm()?; | ||||
|                 shm.shmid | ||||
|             } else { | ||||
|                 if !shmflg.contains(ShmFlags::IPC_CREAT) { | ||||
|                     return_errno!(ENOENT, "no segment exists for given key"); | ||||
|                 } | ||||
|                 let shmid = self.get_new_shmid()?; | ||||
|                 let shm = ShmSegment::new(shmid, key, size, mode)?; | ||||
|                 shm_segments.insert(shm.shmid, shm); | ||||
|                 shmid | ||||
|             }; | ||||
|             shmid | ||||
|         }; | ||||
|         Ok(shmid) | ||||
|     } | ||||
| 
 | ||||
|     pub fn do_shmat(&self, shmid: ShmId, addr: usize, shmflg: ShmFlags) -> Result<usize> { | ||||
|         debug!( | ||||
|             "do_shmat: shmid: {:?}, addr: {:?}, shmflg: {:?}", | ||||
|             shmid, addr, shmflg | ||||
|         ); | ||||
|         let pid = current!().process().pid(); | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         let shm = shm_segments.get_mut(&shmid); | ||||
|         let addr = if let Some(shm) = shm { | ||||
|             if addr != 0 && addr != shm.shm_start() { | ||||
|                 return_errno!(EINVAL, "invalid addr"); | ||||
|             } | ||||
|             // Check the permission
 | ||||
|             shm.check_perm()?; | ||||
| 
 | ||||
|             shm.shm_nattach += 1; | ||||
|             shm.shm_atime = ShmManager::current_time(); | ||||
|             shm.shm_add_pid(&pid)?; | ||||
|             shm.shm_lpid = pid; | ||||
|             shm.shm_start() | ||||
|         } else { | ||||
|             return_errno!(EINVAL, "cannot find shm by shmid"); | ||||
|         }; | ||||
|         Ok(addr) | ||||
|     } | ||||
| 
 | ||||
|     pub fn do_shmdt(&self, addr: usize) -> Result<()> { | ||||
|         debug!("do_shmdt: addr: {:?}", addr); | ||||
|         let pid = current!().process().pid(); | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         let shm = shm_segments | ||||
|             .values_mut() | ||||
|             .find(|shm| shm.shm_start() == addr); | ||||
| 
 | ||||
|         if let Some(shm) = shm { | ||||
|             shm.shm_dtime = ShmManager::current_time(); | ||||
|             shm.shm_lpid = pid; | ||||
|             shm.shm_remove_pid(&pid)?; | ||||
|             shm.shm_nattach -= 1; | ||||
|             if shm.is_destruction() && shm.shm_nattach == 0 { | ||||
|                 let shmid = shm.shmid; | ||||
|                 self.free_shmid(&shmid); | ||||
|                 shm_segments.remove(&shmid); | ||||
|             } | ||||
|         } else { | ||||
|             return_errno!(EINVAL, "cannot find shm by addr"); | ||||
|         } | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     pub fn do_shmctl(&self, shmid: ShmId, cmd: CmdId, buf: Option<&mut shmids_t>) -> Result<()> { | ||||
|         debug!( | ||||
|             "do_shmctl: shmid: {:?}, cmd: {:?}, buf: {:?}", | ||||
|             shmid, cmd, buf | ||||
|         ); | ||||
|         match cmd { | ||||
|             IPC_RMID => self.shmctl_rmshm(shmid), | ||||
|             IPC_STAT => self.shmctl_ipcstat(shmid, buf), | ||||
|             _ => return_errno!(EINVAL, "unimplemented cmd"), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn detach_shm_when_process_exit(&self, thread: &ThreadRef) { | ||||
|         let pid = &thread.process().pid(); | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         shm_segments.drain_filter(|shmid, shm| match shm.shm_remove_pid(&pid) { | ||||
|             // There exists a shm that has been attached to the current process
 | ||||
|             Ok(_) => { | ||||
|                 shm.shm_nattach -= 1; | ||||
|                 if shm.is_destruction() && shm.shm_nattach == 0 { | ||||
|                     self.free_shmid(&shmid); | ||||
|                     true | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             } | ||||
|             Err(_) => false, | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     pub fn clean_when_libos_exit(&self) { | ||||
|         let mut shm_segments = self.shm_segments.write().unwrap(); | ||||
|         for (_, shm) in shm_segments.drain() { | ||||
|             debug!("clean shm: {:?}", shm); | ||||
|             self.free_shmid(&shm.shmid); | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										36
									
								
								src/libos/src/ipc/syscalls.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										36
									
								
								src/libos/src/ipc/syscalls.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| use super::*; | ||||
| 
 | ||||
| use util::mem_util::from_user; | ||||
| 
 | ||||
| use super::shm::{shmids_t, CmdId, ShmFlags, ShmId, SHM_MANAGER}; | ||||
| 
 | ||||
| pub fn do_shmget(key: key_t, size: size_t, shmflg: i32) -> Result<isize> { | ||||
|     let shmflg = | ||||
|         ShmFlags::from_bits(shmflg as u32).ok_or_else(|| errno!(EINVAL, "invalid flags"))?; | ||||
|     let shmid = SHM_MANAGER.do_shmget(key, size, shmflg)?; | ||||
|     Ok(shmid as isize) | ||||
| } | ||||
| 
 | ||||
| pub fn do_shmat(shmid: i32, shmaddr: usize, shmflg: i32) -> Result<isize> { | ||||
|     let shmflg = | ||||
|         ShmFlags::from_bits(shmflg as u32).ok_or_else(|| errno!(EINVAL, "invalid flags"))?; | ||||
|     let addr = SHM_MANAGER.do_shmat(shmid as ShmId, shmaddr, shmflg)?; | ||||
|     Ok(addr as isize) | ||||
| } | ||||
| 
 | ||||
| pub fn do_shmdt(shmaddr: usize) -> Result<isize> { | ||||
|     SHM_MANAGER.do_shmdt(shmaddr)?; | ||||
|     Ok(0) | ||||
| } | ||||
| 
 | ||||
| pub fn do_shmctl(shmid: i32, cmd: i32, buf_u: *mut shmids_t) -> Result<isize> { | ||||
|     let buf = if !buf_u.is_null() { | ||||
|         from_user::check_mut_ptr(buf_u)?; | ||||
|         let mut buf = unsafe { &mut *buf_u }; | ||||
|         Some(buf) | ||||
|     } else { | ||||
|         None | ||||
|     }; | ||||
|     SHM_MANAGER.do_shmctl(shmid as ShmId, cmd as CmdId, buf)?; | ||||
|     Ok(0) | ||||
| } | ||||
| @ -81,6 +81,7 @@ mod events; | ||||
| mod exception; | ||||
| mod fs; | ||||
| mod interrupt; | ||||
| mod ipc; | ||||
| mod misc; | ||||
| mod net; | ||||
| mod process; | ||||
|  | ||||
| @ -6,6 +6,7 @@ use super::do_vfork::{is_vforked_child_process, vfork_return_to_parent}; | ||||
| use super::pgrp::clean_pgrp_when_exit; | ||||
| use super::process::{Process, ProcessFilter}; | ||||
| use super::{table, ProcessRef, TermStatus, ThreadRef, ThreadStatus}; | ||||
| use crate::ipc::SHM_MANAGER; | ||||
| use crate::prelude::*; | ||||
| use crate::signal::{KernelSignal, SigNum}; | ||||
| use crate::syscall::CpuContext; | ||||
| @ -107,6 +108,7 @@ fn exit_process(thread: &ThreadRef, term_status: TermStatus) { | ||||
|     let mut process_inner = process.inner(); | ||||
|     // Clean used VM
 | ||||
|     USER_SPACE_VM_MANAGER.free_chunks_when_exit(thread); | ||||
|     SHM_MANAGER.detach_shm_when_process_exit(thread); | ||||
| 
 | ||||
|     // The parent is the idle process
 | ||||
|     if parent_inner.is_none() { | ||||
|  | ||||
| @ -68,6 +68,8 @@ pub mod task; | ||||
| pub type pid_t = u32; | ||||
| #[allow(non_camel_case_types)] | ||||
| pub type uid_t = u32; | ||||
| #[allow(non_camel_case_types)] | ||||
| pub type gid_t = u32; | ||||
| 
 | ||||
| pub type ProcessRef = Arc<Process>; | ||||
| pub type ThreadRef = Arc<Thread>; | ||||
|  | ||||
| @ -35,6 +35,7 @@ use crate::fs::{ | ||||
|     FileRef, HostStdioFds, Stat, Statfs, | ||||
| }; | ||||
| use crate::interrupt::{do_handle_interrupt, sgx_interrupt_info_t}; | ||||
| use crate::ipc::{do_shmat, do_shmctl, do_shmdt, do_shmget, key_t, shmids_t}; | ||||
| use crate::misc::{resource_t, rlimit_t, sysinfo_t, utsname_t, RandFlags}; | ||||
| use crate::net::{ | ||||
|     do_accept, do_accept4, do_bind, do_connect, do_epoll_create, do_epoll_create1, do_epoll_ctl, | ||||
| @ -118,9 +119,9 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (Msync = 26) => do_msync(addr: usize, size: usize, flags: u32), | ||||
|             (Mincore = 27) => handle_unsupported(), | ||||
|             (Madvise = 28) => handle_unsupported(), | ||||
|             (Shmget = 29) => handle_unsupported(), | ||||
|             (Shmat = 30) => handle_unsupported(), | ||||
|             (Shmctl = 31) => handle_unsupported(), | ||||
|             (Shmget = 29) => do_shmget(key: key_t, size: size_t, shmflg: i32), | ||||
|             (Shmat = 30) => do_shmat(shmid: i32, shmaddr: usize, shmflg: i32), | ||||
|             (Shmctl = 31) => do_shmctl(shmid: i32, cmd: i32, buf: *mut shmids_t), | ||||
|             (Dup = 32) => do_dup(old_fd: FileDesc), | ||||
|             (Dup2 = 33) => do_dup2(old_fd: FileDesc, new_fd: FileDesc), | ||||
|             (Pause = 34) => handle_unsupported(), | ||||
| @ -156,7 +157,7 @@ macro_rules! process_syscall_table_with_callback { | ||||
|             (Semget = 64) => handle_unsupported(), | ||||
|             (Semop = 65) => handle_unsupported(), | ||||
|             (Semctl = 66) => handle_unsupported(), | ||||
|             (Shmdt = 67) => handle_unsupported(), | ||||
|             (Shmdt = 67) => do_shmdt(shmaddr: usize), | ||||
|             (Msgget = 68) => handle_unsupported(), | ||||
|             (Msgsnd = 69) => handle_unsupported(), | ||||
|             (Msgrcv = 70) => handle_unsupported(), | ||||
|  | ||||
| @ -75,10 +75,12 @@ mod vm_util; | ||||
| 
 | ||||
| use self::vm_layout::VMLayout; | ||||
| 
 | ||||
| pub use self::chunk::ChunkRef; | ||||
| pub use self::process_vm::{MMapFlags, MRemapFlags, MSyncFlags, ProcessVM, ProcessVMBuilder}; | ||||
| pub use self::user_space_vm::USER_SPACE_VM_MANAGER; | ||||
| pub use self::vm_perms::VMPerms; | ||||
| pub use self::vm_range::VMRange; | ||||
| pub use self::vm_util::{VMInitializer, VMMapOptionsBuilder}; | ||||
| 
 | ||||
| pub fn do_mmap( | ||||
|     addr: usize, | ||||
|  | ||||
| @ -2,6 +2,7 @@ use super::*; | ||||
| 
 | ||||
| use super::chunk::*; | ||||
| use super::config; | ||||
| use super::ipc::SHM_MANAGER; | ||||
| use super::process::elf_file::{ElfFile, ProgramHeaderExt}; | ||||
| use super::user_space_vm::USER_SPACE_VM_MANAGER; | ||||
| use super::vm_area::VMArea; | ||||
|  | ||||
| @ -1,3 +1,4 @@ | ||||
| use super::ipc::SHM_MANAGER; | ||||
| use super::*; | ||||
| use crate::ctor::dtor; | ||||
| use config::LIBOS_CONFIG; | ||||
| @ -46,6 +47,7 @@ impl UserSpaceVMManager { | ||||
| // be called after the main function. Static variables are still safe to visit at this time.
 | ||||
| #[dtor] | ||||
| fn free_user_space() { | ||||
|     SHM_MANAGER.clean_when_libos_exit(); | ||||
|     let range = USER_SPACE_VM_MANAGER.range(); | ||||
|     assert!(USER_SPACE_VM_MANAGER.verified_clean_when_exit()); | ||||
|     let addr = range.start() as *const c_void; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user