use std::os::unix::io::RawFd;
use std::ptr::null_mut;
use crate::log::*;
use nix::fcntl::OFlag;
use nix::sys::mman::{mmap, munmap, shm_open, shm_unlink, MapFlags, ProtFlags};
use nix::sys::stat::{fstat, Mode};
use nix::unistd::{close, ftruncate};
use crate::ShmemError;
#[derive(Clone, Default)]
pub struct ShmemConfExt;
pub struct MapData {
owner: bool,
map_fd: RawFd,
pub unique_id: String,
pub map_size: usize,
pub map_ptr: *mut u8,
}
impl MapData {
pub fn as_mut_ptr(&self) -> *mut u8 {
self.map_ptr
}
}
impl Drop for MapData {
fn drop(&mut self) {
if !self.map_ptr.is_null() {
trace!(
"munmap(map_ptr:{:p},map_size:{})",
self.map_ptr,
self.map_size
);
if let Err(_e) = unsafe { munmap(self.map_ptr as *mut _, self.map_size) } {
debug!("Failed to munmap() shared memory mapping : {}", _e);
};
}
if self.map_fd != 0 {
if self.owner {
debug!("Deleting persistent mapping");
trace!("shm_unlink({})", self.unique_id.as_str());
if let Err(_e) = shm_unlink(self.unique_id.as_str()) {
debug!("Failed to shm_unlink() shared memory : {}", _e);
};
}
trace!("close({})", self.map_fd);
if let Err(_e) = close(self.map_fd) {
debug!(
"os_impl::Linux : Failed to close() shared memory file descriptor : {}",
_e
);
};
}
}
}
impl MapData {
pub fn set_owner(&mut self, is_owner: bool) -> bool {
let prev_val = self.owner;
self.owner = is_owner;
prev_val
}
}
pub fn create_mapping(unique_id: &str, map_size: usize) -> Result<MapData, ShmemError> {
debug!("Creating persistent mapping at {}", unique_id);
let shmem_fd = match shm_open(
unique_id, OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_RDWR, Mode::S_IRUSR | Mode::S_IWUSR, ) {
Ok(v) => {
trace!(
"shm_open({}, {:X}, {:X}) == {}",
unique_id,
OFlag::O_CREAT | OFlag::O_EXCL | OFlag::O_RDWR,
Mode::S_IRUSR | Mode::S_IWUSR,
v
);
v
}
Err(nix::Error::EEXIST) => return Err(ShmemError::MappingIdExists),
Err(e) => return Err(ShmemError::MapCreateFailed(e as u32)),
};
let mut new_map: MapData = MapData {
owner: true,
unique_id: String::from(unique_id),
map_fd: shmem_fd,
map_size,
map_ptr: null_mut(),
};
debug!("Creating memory mapping");
trace!("ftruncate({}, {})", new_map.map_fd, new_map.map_size);
match ftruncate(new_map.map_fd, new_map.map_size as _) {
Ok(_) => {}
Err(e) => return Err(ShmemError::UnknownOsError(e as u32)),
};
debug!("Loading mapping into address space");
new_map.map_ptr = match unsafe {
mmap(
null_mut(), new_map.map_size, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_SHARED, new_map.map_fd, 0, )
} {
Ok(v) => {
trace!(
"mmap(NULL, {}, {:X}, {:X}, {}, 0) == {:p}",
new_map.map_size,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_SHARED,
new_map.map_fd,
v
);
v as *mut _
}
Err(e) => return Err(ShmemError::MapCreateFailed(e as u32)),
};
Ok(new_map)
}
pub fn open_mapping(
unique_id: &str,
_map_size: usize,
_ext: &ShmemConfExt,
) -> Result<MapData, ShmemError> {
debug!("Openning persistent mapping at {}", unique_id);
let shmem_fd = match shm_open(
unique_id,
OFlag::O_RDWR, Mode::S_IRUSR,
) {
Ok(v) => {
trace!(
"shm_open({}, {:X}, {:X}) == {}",
unique_id,
OFlag::O_RDWR,
Mode::S_IRUSR,
v
);
v
}
Err(e) => return Err(ShmemError::MapOpenFailed(e as u32)),
};
let mut new_map: MapData = MapData {
owner: false,
unique_id: String::from(unique_id),
map_fd: shmem_fd,
map_size: 0,
map_ptr: null_mut(),
};
new_map.map_size = match fstat(new_map.map_fd) {
Ok(v) => v.st_size as usize,
Err(e) => return Err(ShmemError::MapOpenFailed(e as u32)),
};
debug!("Loading mapping into address space");
new_map.map_ptr = match unsafe {
mmap(
null_mut(), new_map.map_size, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_SHARED, new_map.map_fd, 0, )
} {
Ok(v) => {
trace!(
"mmap(NULL, {}, {:X}, {:X}, {}, 0) == {:p}",
new_map.map_size,
ProtFlags::PROT_READ | ProtFlags::PROT_WRITE,
MapFlags::MAP_SHARED,
new_map.map_fd,
v
);
v as *mut _
}
Err(e) => return Err(ShmemError::MapOpenFailed(e as u32)),
};
Ok(new_map)
}