use libc::{
c_char, c_int, c_long, c_uint, c_void, close, ftruncate, mkstemp, mmap,
munmap, off_t, size_t, syscall, sysconf, SYS_memfd_create, ENOSYS,
MAP_FAILED, MAP_FIXED, MAP_SHARED, PROT_READ, PROT_WRITE, _SC_PAGESIZE,
};
#[cfg(target_os = "android")]
use libc::__errno;
#[cfg(not(target_os = "android"))]
use libc::__errno_location;
use super::{ptr, AllocError};
fn memfd_create(name: *const c_char, flags: c_uint) -> c_long {
unsafe { syscall(SYS_memfd_create, name, flags) }
}
pub fn allocation_granularity() -> usize {
unsafe { sysconf(_SC_PAGESIZE) as usize }
}
fn errno() -> c_int {
#[cfg(not(target_os = "android"))]
unsafe {
*__errno_location()
}
#[cfg(target_os = "android")]
unsafe {
*__errno()
}
}
pub fn allocate_mirrored(size: usize) -> Result<*mut u8, AllocError> {
unsafe {
let half_size = size / 2;
assert!(size != 0);
assert!(half_size % allocation_granularity() == 0);
let mut fname = *b"/tmp/slice_deque_fileXXXXXX\0";
let mut fd: c_long =
memfd_create(fname.as_mut_ptr() as *mut c_char, 0);
if fd == -1 && errno() == ENOSYS {
fd = c_long::from(mkstemp(fname.as_mut_ptr() as *mut c_char));
}
if fd == -1 {
print_error("memfd_create failed");
return Err(AllocError::Other);
}
let fd = fd as c_int;
if ftruncate(fd, half_size as off_t) == -1 {
print_error("ftruncate failed");
if close(fd) == -1 {
print_error("@ftruncate: close failed");
}
return Err(AllocError::Oom);
};
let ptr = mmap(
ptr::null_mut(),
size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0,
);
if ptr == MAP_FAILED {
print_error("@first: mmap failed");
if close(fd) == -1 {
print_error("@first: close failed");
}
return Err(AllocError::Oom);
}
let ptr2 = mmap(
(ptr as *mut u8).offset(half_size as isize) as *mut c_void,
half_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_FIXED,
fd,
0,
);
if ptr2 == MAP_FAILED {
print_error("@second: mmap failed");
if munmap(ptr, size as size_t) == -1 {
print_error("@second: munmap failed");
}
if close(fd) == -1 {
print_error("@second: close failed");
}
return Err(AllocError::Other);
}
if close(fd) == -1 {
print_error("@success: close failed");
}
Ok(ptr as *mut u8)
}
}
pub unsafe fn deallocate_mirrored(ptr: *mut u8, size: usize) {
assert!(!ptr.is_null());
assert!(size != 0);
assert!(size % allocation_granularity() == 0);
if munmap(ptr as *mut c_void, size as size_t) == -1 {
print_error("deallocate munmap failed");
}
}
#[cfg(all(debug_assertions, feature = "use_std"))]
fn print_error(location: &str) {
eprintln!(
"Error at {}: {}",
location,
::std::io::Error::last_os_error()
);
}
#[cfg(not(all(debug_assertions, feature = "use_std")))]
fn print_error(_location: &str) {}