4 use std
::os
::unix
::io
::{AsRawFd, RawFd}
;
8 all(target_os
= "linux", not(target_arch
= "mips")),
12 const MAP_STACK
: libc
::c_int
= libc
::MAP_STACK
;
15 all(target_os
= "linux", not(target_arch
= "mips")),
16 target_os
= "freebsd",
19 const MAP_STACK
: libc
::c_int
= 0;
21 pub struct MmapInner
{
22 ptr
: *mut libc
::c_void
,
27 /// Creates a new `MmapInner`.
29 /// This is a thin wrapper around the `mmap` sytem call.
36 ) -> io
::Result
<MmapInner
> {
37 let alignment
= offset
% page_size() as u64;
38 let aligned_offset
= offset
- alignment
;
39 let aligned_len
= len
+ alignment
as usize;
41 // Normally the OS would catch this, but it segfaults under QEMU.
42 return Err(io
::Error
::new(
43 io
::ErrorKind
::InvalidInput
,
44 "memory map must have a non-zero length",
51 aligned_len
as libc
::size_t
,
55 aligned_offset
as libc
::off_t
,
58 if ptr
== libc
::MAP_FAILED
{
59 Err(io
::Error
::last_os_error())
62 ptr
: ptr
.offset(alignment
as isize),
69 pub fn map(len
: usize, file
: &File
, offset
: u64) -> io
::Result
<MmapInner
> {
79 pub fn map_exec(len
: usize, file
: &File
, offset
: u64) -> io
::Result
<MmapInner
> {
82 libc
::PROT_READ
| libc
::PROT_EXEC
,
89 pub fn map_mut(len
: usize, file
: &File
, offset
: u64) -> io
::Result
<MmapInner
> {
92 libc
::PROT_READ
| libc
::PROT_WRITE
,
99 pub fn map_copy(len
: usize, file
: &File
, offset
: u64) -> io
::Result
<MmapInner
> {
102 libc
::PROT_READ
| libc
::PROT_WRITE
,
109 /// Open an anonymous memory map.
110 pub fn map_anon(len
: usize, stack
: bool
) -> io
::Result
<MmapInner
> {
111 let stack
= if stack { MAP_STACK }
else { 0 }
;
114 libc
::PROT_READ
| libc
::PROT_WRITE
,
115 libc
::MAP_SHARED
| libc
::MAP_ANON
| stack
,
121 pub fn flush(&self, offset
: usize, len
: usize) -> io
::Result
<()> {
122 let alignment
= (self.ptr
as usize + offset
) % page_size();
123 let offset
= offset
as isize - alignment
as isize;
124 let len
= len
+ alignment
;
126 unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_SYNC) }
;
130 Err(io
::Error
::last_os_error())
134 pub fn flush_async(&self, offset
: usize, len
: usize) -> io
::Result
<()> {
135 let alignment
= offset
% page_size();
136 let aligned_offset
= offset
- alignment
;
137 let aligned_len
= len
+ alignment
;
138 let result
= unsafe {
140 self.ptr
.offset(aligned_offset
as isize),
141 aligned_len
as libc
::size_t
,
148 Err(io
::Error
::last_os_error())
152 fn mprotect(&mut self, prot
: libc
::c_int
) -> io
::Result
<()> {
154 let alignment
= self.ptr
as usize % page_size();
155 let ptr
= self.ptr
.offset(-(alignment
as isize));
156 let len
= self.len
+ alignment
;
157 if libc
::mprotect(ptr
, len
, prot
) == 0 {
160 Err(io
::Error
::last_os_error())
165 pub fn make_read_only(&mut self) -> io
::Result
<()> {
166 self.mprotect(libc
::PROT_READ
)
169 pub fn make_exec(&mut self) -> io
::Result
<()> {
170 self.mprotect(libc
::PROT_READ
| libc
::PROT_EXEC
)
173 pub fn make_mut(&mut self) -> io
::Result
<()> {
174 self.mprotect(libc
::PROT_READ
| libc
::PROT_WRITE
)
178 pub fn ptr(&self) -> *const u8 {
179 self.ptr
as *const u8
183 pub fn mut_ptr(&mut self) -> *mut u8 {
188 pub fn len(&self) -> usize {
193 impl Drop
for MmapInner
{
195 let alignment
= self.ptr
as usize % page_size();
199 self.ptr
.offset(-(alignment
as isize)),
200 (self.len
+ alignment
) as libc
::size_t
202 "unable to unmap mmap: {}",
203 io
::Error
::last_os_error()
209 unsafe impl Sync
for MmapInner {}
210 unsafe impl Send
for MmapInner {}
212 fn page_size() -> usize {
213 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }