]> git.proxmox.com Git - rustc.git/blob - vendor/memmap/src/unix.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / vendor / memmap / src / unix.rs
1 extern crate libc;
2
3 use std::fs::File;
4 use std::os::unix::io::{AsRawFd, RawFd};
5 use std::{io, ptr};
6
7 #[cfg(any(
8 all(target_os = "linux", not(target_arch = "mips")),
9 target_os = "freebsd",
10 target_os = "android"
11 ))]
12 const MAP_STACK: libc::c_int = libc::MAP_STACK;
13
14 #[cfg(not(any(
15 all(target_os = "linux", not(target_arch = "mips")),
16 target_os = "freebsd",
17 target_os = "android"
18 )))]
19 const MAP_STACK: libc::c_int = 0;
20
21 pub struct MmapInner {
22 ptr: *mut libc::c_void,
23 len: usize,
24 }
25
26 impl MmapInner {
27 /// Creates a new `MmapInner`.
28 ///
29 /// This is a thin wrapper around the `mmap` sytem call.
30 fn new(
31 len: usize,
32 prot: libc::c_int,
33 flags: libc::c_int,
34 file: RawFd,
35 offset: u64,
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;
40 if aligned_len == 0 {
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",
45 ));
46 }
47
48 unsafe {
49 let ptr = libc::mmap(
50 ptr::null_mut(),
51 aligned_len as libc::size_t,
52 prot,
53 flags,
54 file,
55 aligned_offset as libc::off_t,
56 );
57
58 if ptr == libc::MAP_FAILED {
59 Err(io::Error::last_os_error())
60 } else {
61 Ok(MmapInner {
62 ptr: ptr.offset(alignment as isize),
63 len: len,
64 })
65 }
66 }
67 }
68
69 pub fn map(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
70 MmapInner::new(
71 len,
72 libc::PROT_READ,
73 libc::MAP_SHARED,
74 file.as_raw_fd(),
75 offset,
76 )
77 }
78
79 pub fn map_exec(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
80 MmapInner::new(
81 len,
82 libc::PROT_READ | libc::PROT_EXEC,
83 libc::MAP_SHARED,
84 file.as_raw_fd(),
85 offset,
86 )
87 }
88
89 pub fn map_mut(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
90 MmapInner::new(
91 len,
92 libc::PROT_READ | libc::PROT_WRITE,
93 libc::MAP_SHARED,
94 file.as_raw_fd(),
95 offset,
96 )
97 }
98
99 pub fn map_copy(len: usize, file: &File, offset: u64) -> io::Result<MmapInner> {
100 MmapInner::new(
101 len,
102 libc::PROT_READ | libc::PROT_WRITE,
103 libc::MAP_PRIVATE,
104 file.as_raw_fd(),
105 offset,
106 )
107 }
108
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 };
112 MmapInner::new(
113 len,
114 libc::PROT_READ | libc::PROT_WRITE,
115 libc::MAP_SHARED | libc::MAP_ANON | stack,
116 -1,
117 0,
118 )
119 }
120
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;
125 let result =
126 unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_SYNC) };
127 if result == 0 {
128 Ok(())
129 } else {
130 Err(io::Error::last_os_error())
131 }
132 }
133
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 {
139 libc::msync(
140 self.ptr.offset(aligned_offset as isize),
141 aligned_len as libc::size_t,
142 libc::MS_ASYNC,
143 )
144 };
145 if result == 0 {
146 Ok(())
147 } else {
148 Err(io::Error::last_os_error())
149 }
150 }
151
152 fn mprotect(&mut self, prot: libc::c_int) -> io::Result<()> {
153 unsafe {
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 {
158 Ok(())
159 } else {
160 Err(io::Error::last_os_error())
161 }
162 }
163 }
164
165 pub fn make_read_only(&mut self) -> io::Result<()> {
166 self.mprotect(libc::PROT_READ)
167 }
168
169 pub fn make_exec(&mut self) -> io::Result<()> {
170 self.mprotect(libc::PROT_READ | libc::PROT_EXEC)
171 }
172
173 pub fn make_mut(&mut self) -> io::Result<()> {
174 self.mprotect(libc::PROT_READ | libc::PROT_WRITE)
175 }
176
177 #[inline]
178 pub fn ptr(&self) -> *const u8 {
179 self.ptr as *const u8
180 }
181
182 #[inline]
183 pub fn mut_ptr(&mut self) -> *mut u8 {
184 self.ptr as *mut u8
185 }
186
187 #[inline]
188 pub fn len(&self) -> usize {
189 self.len
190 }
191 }
192
193 impl Drop for MmapInner {
194 fn drop(&mut self) {
195 let alignment = self.ptr as usize % page_size();
196 unsafe {
197 assert!(
198 libc::munmap(
199 self.ptr.offset(-(alignment as isize)),
200 (self.len + alignment) as libc::size_t
201 ) == 0,
202 "unable to unmap mmap: {}",
203 io::Error::last_os_error()
204 );
205 }
206 }
207 }
208
209 unsafe impl Sync for MmapInner {}
210 unsafe impl Send for MmapInner {}
211
212 fn page_size() -> usize {
213 unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
214 }