/rust/registry/src/index.crates.io-1949cf8c6b5b557f/memmap2-0.9.11/src/unix.rs
Line | Count | Source |
1 | | use std::fs::File; |
2 | | use std::io; |
3 | | use std::mem::ManuallyDrop; |
4 | | use std::os::unix::io::{FromRawFd, RawFd}; |
5 | | use std::sync::atomic::{AtomicUsize, Ordering}; |
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 | | #[cfg(any(target_os = "linux", target_os = "android"))] |
22 | | const MAP_POPULATE: libc::c_int = libc::MAP_POPULATE; |
23 | | |
24 | | #[cfg(not(any(target_os = "linux", target_os = "android")))] |
25 | | const MAP_POPULATE: libc::c_int = 0; |
26 | | |
27 | | #[cfg(any(target_os = "linux", target_os = "android"))] |
28 | | const MAP_HUGETLB: libc::c_int = libc::MAP_HUGETLB; |
29 | | |
30 | | #[cfg(target_os = "linux")] |
31 | | const MAP_HUGE_MASK: libc::c_int = libc::MAP_HUGE_MASK; |
32 | | |
33 | | #[cfg(any(target_os = "linux", target_os = "android"))] |
34 | | const MAP_HUGE_SHIFT: libc::c_int = libc::MAP_HUGE_SHIFT; |
35 | | |
36 | | #[cfg(not(any(target_os = "linux", target_os = "android")))] |
37 | | const MAP_HUGETLB: libc::c_int = 0; |
38 | | |
39 | | #[cfg(not(target_os = "linux"))] |
40 | | const MAP_HUGE_MASK: libc::c_int = 0; |
41 | | |
42 | | #[cfg(not(any(target_os = "linux", target_os = "android")))] |
43 | | const MAP_HUGE_SHIFT: libc::c_int = 0; |
44 | | |
45 | | #[cfg(any( |
46 | | target_os = "linux", |
47 | | target_os = "android", |
48 | | target_vendor = "apple", |
49 | | target_os = "netbsd", |
50 | | target_os = "solaris", |
51 | | target_os = "illumos", |
52 | | ))] |
53 | | const MAP_NORESERVE: libc::c_int = libc::MAP_NORESERVE; |
54 | | |
55 | | #[cfg(not(any( |
56 | | target_os = "linux", |
57 | | target_os = "android", |
58 | | target_vendor = "apple", |
59 | | target_os = "netbsd", |
60 | | target_os = "solaris", |
61 | | target_os = "illumos", |
62 | | )))] |
63 | | const MAP_NORESERVE: libc::c_int = 0; |
64 | | |
65 | | #[cfg(any( |
66 | | target_os = "android", |
67 | | all(target_os = "linux", not(target_env = "musl")) |
68 | | ))] |
69 | | use libc::{mmap64 as mmap, off64_t as off_t}; |
70 | | |
71 | | #[cfg(not(any( |
72 | | target_os = "android", |
73 | | all(target_os = "linux", not(target_env = "musl")) |
74 | | )))] |
75 | | use libc::{mmap, off_t}; |
76 | | |
77 | | pub struct MmapInner { |
78 | | ptr: *mut libc::c_void, |
79 | | len: usize, |
80 | | } |
81 | | |
82 | | impl MmapInner { |
83 | | /// Creates a new `MmapInner`. |
84 | | /// |
85 | | /// This is a thin wrapper around the `mmap` system call. |
86 | 1.57k | fn new( |
87 | 1.57k | len: usize, |
88 | 1.57k | prot: libc::c_int, |
89 | 1.57k | flags: libc::c_int, |
90 | 1.57k | file: RawFd, |
91 | 1.57k | offset: u64, |
92 | 1.57k | ) -> io::Result<MmapInner> { |
93 | 1.57k | let alignment = offset % page_size() as u64; |
94 | 1.57k | let aligned_offset = offset - alignment; |
95 | | |
96 | 1.57k | let (map_len, map_offset) = Self::adjust_mmap_params(len, alignment as usize)?; |
97 | | |
98 | | // SAFETY: creating a new memory map with a nullptr as address hint is always sound: |
99 | | // it does not modify any existing mapping or memory contents. |
100 | 1.57k | let ptr = unsafe { |
101 | 1.57k | mmap( |
102 | 1.57k | std::ptr::null_mut(), |
103 | 1.57k | map_len as libc::size_t, |
104 | 1.57k | prot, |
105 | 1.57k | flags, |
106 | 1.57k | file, |
107 | 1.57k | aligned_offset as off_t, |
108 | | ) |
109 | | }; |
110 | | |
111 | 1.57k | if ptr == libc::MAP_FAILED { |
112 | 0 | Err(io::Error::last_os_error()) |
113 | | } else { |
114 | | // SAFETY: The ptr and len have been checked, |
115 | | // and the offset has been calculated as required. |
116 | 1.57k | Ok(unsafe { Self::from_raw_parts(ptr, len, map_offset) }) |
117 | | } |
118 | 1.57k | } |
119 | | |
120 | 1.57k | fn adjust_mmap_params(len: usize, alignment: usize) -> io::Result<(usize, usize)> { |
121 | | // Rust's slice cannot be larger than isize::MAX. |
122 | | // See https://doc.rust-lang.org/std/slice/fn.from_raw_parts.html |
123 | | // |
124 | | // This is not a problem on 64-bit targets, but on 32-bit one |
125 | | // having a file or an anonymous mapping larger than 2GB is quite normal |
126 | | // and we have to prevent it. |
127 | | // |
128 | | // The code below is essentially the same as in Rust's std: |
129 | | // https://github.com/rust-lang/rust/blob/db78ab70a88a0a5e89031d7ee4eccec835dcdbde/library/alloc/src/raw_vec.rs#L495 |
130 | 1.57k | if std::mem::size_of::<usize>() < 8 && len > isize::MAX as usize { |
131 | 0 | return Err(io::Error::new( |
132 | 0 | io::ErrorKind::InvalidData, |
133 | 0 | "memory map length overflows isize", |
134 | 0 | )); |
135 | 1.57k | } |
136 | | |
137 | 1.57k | let map_len = len + alignment; |
138 | 1.57k | let map_offset = alignment; |
139 | | |
140 | | // `libc::mmap` does not support zero-size mappings. POSIX defines: |
141 | | // |
142 | | // https://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html |
143 | | // > If `len` is zero, `mmap()` shall fail and no mapping shall be established. |
144 | | // |
145 | | // So if we would create such a mapping, crate a one-byte mapping instead: |
146 | 1.57k | let map_len = map_len.max(1); |
147 | | |
148 | | // Note that in that case `MmapInner::len` is still set to zero, |
149 | | // and `Mmap` will still dereferences to an empty slice. |
150 | | // |
151 | | // If this mapping is backed by an empty file, we create a mapping larger than the file. |
152 | | // This is unusual but well-defined. On the same man page, POSIX further defines: |
153 | | // |
154 | | // > The `mmap()` function can be used to map a region of memory that is larger |
155 | | // > than the current size of the object. |
156 | | // |
157 | | // (The object here is the file.) |
158 | | // |
159 | | // > Memory access within the mapping but beyond the current end of the underlying |
160 | | // > objects may result in SIGBUS signals being sent to the process. The reason for this |
161 | | // > is that the size of the object can be manipulated by other processes and can change |
162 | | // > at any moment. The implementation should tell the application that a memory reference |
163 | | // > is outside the object where this can be detected; otherwise, written data may be lost |
164 | | // > and read data may not reflect actual data in the object. |
165 | | // |
166 | | // Because `MmapInner::len` is not incremented, this increment of `aligned_len` |
167 | | // will not allow accesses past the end of the file and will not cause SIGBUS. |
168 | | // |
169 | | // (SIGBUS is still possible by mapping a non-empty file and then truncating it |
170 | | // to a shorter size, but that is unrelated to this handling of empty files.) |
171 | 1.57k | Ok((map_len, map_offset)) |
172 | 1.57k | } |
173 | | |
174 | | /// Get the current memory mapping as a `(ptr, map_len, offset)` tuple. |
175 | | /// |
176 | | /// Note that `map_len` is the length of the memory mapping itself and |
177 | | /// _not_ the one that would be passed to `from_raw_parts`. |
178 | 1.57k | fn as_mmap_params(&self) -> (*mut libc::c_void, usize, usize) { |
179 | 1.57k | let offset = self.ptr as usize % page_size(); |
180 | 1.57k | let len = self.len + offset; |
181 | | |
182 | | // There are two possible memory layouts we could have, depending on |
183 | | // the length and offset passed when constructing this instance: |
184 | | // |
185 | | // 1. The "normal" memory layout looks like this: |
186 | | // |
187 | | // |<------------------>|<---------------------->| |
188 | | // mmap ptr offset ptr public slice |
189 | | // |
190 | | // That is, we have |
191 | | // - The start of the page-aligned memory mapping returned by mmap, |
192 | | // followed by, |
193 | | // - Some number of bytes that are memory mapped but ignored since |
194 | | // they are before the byte offset requested by the user, followed |
195 | | // by, |
196 | | // - The actual memory mapped slice requested by the user. |
197 | | // |
198 | | // This maps cleanly to a (ptr, len, offset) tuple. |
199 | | // |
200 | | // 2. Then, we have the case where the user requested a zero-length |
201 | | // memory mapping. mmap(2) does not support zero-length mappings so |
202 | | // this crate works around that by actually making a mapping of |
203 | | // length one. This means that we have |
204 | | // - A length zero slice, followed by, |
205 | | // - A single memory mapped byte |
206 | | // |
207 | | // Note that this only happens if the offset within the page is also |
208 | | // zero. Otherwise, we have a memory map of offset bytes and not a |
209 | | // zero-length memory map. |
210 | | // |
211 | | // This doesn't fit cleanly into a (ptr, len, offset) tuple. Instead, |
212 | | // we fudge it slightly: a zero-length memory map turns into a |
213 | | // mapping of length one and can't be told apart outside of this |
214 | | // method without knowing the original length. |
215 | 1.57k | if len == 0 { |
216 | 0 | (self.ptr, 1, 0) |
217 | | } else { |
218 | 1.57k | let offset = self.ptr as usize % page_size(); |
219 | | // SAFETY: MmapInner guarantees that rounding `self.ptr` down to a page boundary gives the real address of the memory map. |
220 | | // This means that it points into the same allocation as `self.ptr`. |
221 | 1.57k | let ptr = unsafe { self.ptr.sub(offset) }; |
222 | 1.57k | (ptr, len, offset) |
223 | | } |
224 | 1.57k | } |
225 | | |
226 | | /// Construct this `MmapInner` from its raw components |
227 | | /// |
228 | | /// # Safety |
229 | | /// |
230 | | /// - `ptr` must point to the start of memory mapping that can be freed |
231 | | /// using `munmap(2)` (i.e. returned by `mmap(2)` or `mremap(2)`) |
232 | | /// - The memory mapping at `ptr` must have a length of `len + offset`. |
233 | | /// - If `len + offset == 0` then the memory mapping must be of length 1. |
234 | | /// - `offset` must be less than the current page size. |
235 | 1.57k | unsafe fn from_raw_parts(ptr: *mut libc::c_void, len: usize, offset: usize) -> Self { |
236 | 1.57k | debug_assert_eq!(ptr as usize % page_size(), 0, "ptr not page-aligned"); |
237 | 1.57k | debug_assert!(offset < page_size(), "offset larger than page size"); |
238 | | |
239 | 1.57k | Self { |
240 | 1.57k | ptr: unsafe { ptr.add(offset) }, |
241 | 1.57k | len, |
242 | 1.57k | } |
243 | 1.57k | } |
244 | | |
245 | 0 | pub fn map( |
246 | 0 | len: usize, |
247 | 0 | file: RawFd, |
248 | 0 | offset: u64, |
249 | 0 | populate: bool, |
250 | 0 | no_reserve: bool, |
251 | 0 | ) -> io::Result<MmapInner> { |
252 | 0 | let populate = if populate { MAP_POPULATE } else { 0 }; |
253 | 0 | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
254 | 0 | MmapInner::new( |
255 | 0 | len, |
256 | | libc::PROT_READ, |
257 | 0 | libc::MAP_SHARED | populate | no_reserve, |
258 | 0 | file, |
259 | 0 | offset, |
260 | | ) |
261 | 0 | } |
262 | | |
263 | 0 | pub fn map_exec( |
264 | 0 | len: usize, |
265 | 0 | file: RawFd, |
266 | 0 | offset: u64, |
267 | 0 | populate: bool, |
268 | 0 | no_reserve: bool, |
269 | 0 | ) -> io::Result<MmapInner> { |
270 | 0 | let populate = if populate { MAP_POPULATE } else { 0 }; |
271 | 0 | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
272 | 0 | MmapInner::new( |
273 | 0 | len, |
274 | 0 | libc::PROT_READ | libc::PROT_EXEC, |
275 | 0 | libc::MAP_SHARED | populate | no_reserve, |
276 | 0 | file, |
277 | 0 | offset, |
278 | | ) |
279 | 0 | } |
280 | | |
281 | 0 | pub fn map_mut( |
282 | 0 | len: usize, |
283 | 0 | file: RawFd, |
284 | 0 | offset: u64, |
285 | 0 | populate: bool, |
286 | 0 | no_reserve: bool, |
287 | 0 | ) -> io::Result<MmapInner> { |
288 | 0 | let populate = if populate { MAP_POPULATE } else { 0 }; |
289 | 0 | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
290 | 0 | MmapInner::new( |
291 | 0 | len, |
292 | 0 | libc::PROT_READ | libc::PROT_WRITE, |
293 | 0 | libc::MAP_SHARED | populate | no_reserve, |
294 | 0 | file, |
295 | 0 | offset, |
296 | | ) |
297 | 0 | } |
298 | | |
299 | 0 | pub fn map_copy( |
300 | 0 | len: usize, |
301 | 0 | file: RawFd, |
302 | 0 | offset: u64, |
303 | 0 | populate: bool, |
304 | 0 | no_reserve: bool, |
305 | 0 | ) -> io::Result<MmapInner> { |
306 | 0 | let populate = if populate { MAP_POPULATE } else { 0 }; |
307 | 0 | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
308 | 0 | MmapInner::new( |
309 | 0 | len, |
310 | 0 | libc::PROT_READ | libc::PROT_WRITE, |
311 | 0 | libc::MAP_PRIVATE | populate | no_reserve, |
312 | 0 | file, |
313 | 0 | offset, |
314 | | ) |
315 | 0 | } |
316 | | |
317 | 0 | pub fn map_copy_read_only( |
318 | 0 | len: usize, |
319 | 0 | file: RawFd, |
320 | 0 | offset: u64, |
321 | 0 | populate: bool, |
322 | 0 | no_reserve: bool, |
323 | 0 | ) -> io::Result<MmapInner> { |
324 | 0 | let populate = if populate { MAP_POPULATE } else { 0 }; |
325 | 0 | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
326 | 0 | MmapInner::new( |
327 | 0 | len, |
328 | | libc::PROT_READ, |
329 | 0 | libc::MAP_PRIVATE | populate | no_reserve, |
330 | 0 | file, |
331 | 0 | offset, |
332 | | ) |
333 | 0 | } |
334 | | |
335 | | /// Open an anonymous memory map. |
336 | 1.57k | pub fn map_anon( |
337 | 1.57k | len: usize, |
338 | 1.57k | stack: bool, |
339 | 1.57k | populate: bool, |
340 | 1.57k | huge: Option<u8>, |
341 | 1.57k | no_reserve: bool, |
342 | 1.57k | ) -> io::Result<MmapInner> { |
343 | 1.57k | let stack = if stack { MAP_STACK } else { 0 }; |
344 | 1.57k | let populate = if populate { MAP_POPULATE } else { 0 }; |
345 | 1.57k | let hugetlb = if huge.is_some() { MAP_HUGETLB } else { 0 }; |
346 | 1.57k | let hugetlb_size = huge.map_or(0, |mask| { |
347 | 0 | (u64::from(mask) & (MAP_HUGE_MASK as u64)) << MAP_HUGE_SHIFT |
348 | 0 | }) as i32; |
349 | 1.57k | let no_reserve = if no_reserve { MAP_NORESERVE } else { 0 }; |
350 | 1.57k | MmapInner::new( |
351 | 1.57k | len, |
352 | 1.57k | libc::PROT_READ | libc::PROT_WRITE, |
353 | 1.57k | libc::MAP_PRIVATE |
354 | 1.57k | | libc::MAP_ANON |
355 | 1.57k | | stack |
356 | 1.57k | | populate |
357 | 1.57k | | hugetlb |
358 | 1.57k | | hugetlb_size |
359 | 1.57k | | no_reserve, |
360 | | -1, |
361 | | 0, |
362 | | ) |
363 | 1.57k | } |
364 | | |
365 | 0 | pub fn flush(&self, offset: usize, len: usize) -> io::Result<()> { |
366 | 0 | if offset > self.len || len > self.len - offset { |
367 | 0 | return Err(io::ErrorKind::InvalidInput.into()); |
368 | 0 | } |
369 | 0 | let alignment = (self.ptr as usize + offset) % page_size(); |
370 | 0 | let offset = offset as isize - alignment as isize; |
371 | 0 | let len = len + alignment; |
372 | 0 | let result = |
373 | | // SAFETY: We've checked that offset and len fall within the mapped region. |
374 | 0 | unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_SYNC) }; |
375 | 0 | if result == 0 { |
376 | 0 | Ok(()) |
377 | | } else { |
378 | 0 | Err(io::Error::last_os_error()) |
379 | | } |
380 | 0 | } |
381 | | |
382 | 0 | pub fn flush_async(&self, offset: usize, len: usize) -> io::Result<()> { |
383 | 0 | if offset > self.len || len > self.len - offset { |
384 | 0 | return Err(io::ErrorKind::InvalidInput.into()); |
385 | 0 | } |
386 | 0 | let alignment = (self.ptr as usize + offset) % page_size(); |
387 | 0 | let offset = offset as isize - alignment as isize; |
388 | 0 | let len = len + alignment; |
389 | 0 | let result = |
390 | | // SAFETY: We've checked that offset and len fall within the mapped region. |
391 | 0 | unsafe { libc::msync(self.ptr.offset(offset), len as libc::size_t, libc::MS_ASYNC) }; |
392 | 0 | if result == 0 { |
393 | 0 | Ok(()) |
394 | | } else { |
395 | 0 | Err(io::Error::last_os_error()) |
396 | | } |
397 | 0 | } |
398 | | |
399 | 1.57k | fn mprotect(&mut self, prot: libc::c_int) -> io::Result<()> { |
400 | 1.57k | let alignment = self.ptr as usize % page_size(); |
401 | | // SAFETY: rounding self.ptr down to the previous page boundary gives the pointer of the actual memory map. |
402 | 1.57k | let ptr = unsafe { self.ptr.sub(alignment) }; |
403 | 1.57k | let len = self.len + alignment; |
404 | 1.57k | let len = len.max(1); |
405 | | |
406 | | // SAFETY: the contract of MmapInner guarantees ptr and len are valid. |
407 | 1.57k | if unsafe { libc::mprotect(ptr, len, prot) } == 0 { |
408 | 1.57k | Ok(()) |
409 | | } else { |
410 | 0 | Err(io::Error::last_os_error()) |
411 | | } |
412 | 1.57k | } |
413 | | |
414 | 1.57k | pub fn make_read_only(&mut self) -> io::Result<()> { |
415 | 1.57k | self.mprotect(libc::PROT_READ) |
416 | 1.57k | } |
417 | | |
418 | 0 | pub fn make_exec(&mut self) -> io::Result<()> { |
419 | 0 | self.mprotect(libc::PROT_READ | libc::PROT_EXEC) |
420 | 0 | } |
421 | | |
422 | 0 | pub fn make_mut(&mut self) -> io::Result<()> { |
423 | 0 | self.mprotect(libc::PROT_READ | libc::PROT_WRITE) |
424 | 0 | } |
425 | | |
426 | | #[inline] |
427 | 20.7k | pub fn ptr(&self) -> *const u8 { |
428 | 20.7k | self.ptr as *const u8 |
429 | 20.7k | } |
430 | | |
431 | | #[inline] |
432 | 1.57k | pub fn mut_ptr(&mut self) -> *mut u8 { |
433 | 1.57k | self.ptr.cast() |
434 | 1.57k | } |
435 | | |
436 | | #[inline] |
437 | 22.2k | pub fn len(&self) -> usize { |
438 | 22.2k | self.len |
439 | 22.2k | } |
440 | | |
441 | | /// Perform an `madvise()`. |
442 | | /// |
443 | | /// # Safety |
444 | | /// |
445 | | /// Some `advise` values can be unsound depending on the situation. |
446 | | /// It is up to the caller to only perform sound madvise() calls on the memory range. |
447 | 0 | pub unsafe fn advise(&self, advice: libc::c_int, offset: usize, len: usize) -> io::Result<()> { |
448 | 0 | if offset > self.len || len > self.len { |
449 | 0 | return Err(std::io::ErrorKind::InvalidInput.into()); |
450 | 0 | } |
451 | 0 | let alignment = (self.ptr as usize + offset) % page_size(); |
452 | 0 | let offset = offset as isize - alignment as isize; |
453 | 0 | let len = len + alignment; |
454 | | |
455 | | // SAFETY: We've checked that offset is within the mapped region. |
456 | 0 | let ptr = unsafe { self.ptr.offset(offset) }; |
457 | | |
458 | | // The AIX signature of 'madvise()' differs from the POSIX |
459 | | // specification, which expects 'void *' as the type of the |
460 | | // 'addr' argument, whereas AIX uses 'caddr_t' (i.e., 'char *'). |
461 | | #[cfg(target_os = "aix")] |
462 | | let ptr = self.ptr.offset(offset).cast(); |
463 | | |
464 | | // SAFETY: ptr and len are valid. The burden of giving a safe `advice` value is on the caller. |
465 | 0 | if unsafe { libc::madvise(ptr, len, advice) } != 0 { |
466 | 0 | Err(io::Error::last_os_error()) |
467 | | } else { |
468 | 0 | Ok(()) |
469 | | } |
470 | 0 | } |
471 | | |
472 | | #[cfg(target_os = "linux")] |
473 | 0 | pub fn remap(&mut self, new_len: usize, options: crate::RemapOptions) -> io::Result<()> { |
474 | 0 | let (old_ptr, old_len, offset) = self.as_mmap_params(); |
475 | 0 | let (map_len, offset) = Self::adjust_mmap_params(new_len, offset)?; |
476 | | |
477 | | // SAFETY: we hold a mutable reference to self, so we can adjust the location and size of the mapping. |
478 | 0 | let new_ptr = unsafe { libc::mremap(old_ptr, old_len, map_len, options.into_flags()) }; |
479 | | |
480 | 0 | if new_ptr == libc::MAP_FAILED { |
481 | 0 | Err(io::Error::last_os_error()) |
482 | | } else { |
483 | | // SAFETY: The pointer and length passed to `from_raw_parts` have just been obtained from a real map, so they must be valid. |
484 | 0 | let new_map = unsafe { Self::from_raw_parts(new_ptr, new_len, offset) }; |
485 | | // We explicitly don't drop self since the pointer within is no longer valid. |
486 | | // Instead, swap the new map into `self` and forget the old one. |
487 | 0 | let old_map = std::mem::replace(self, new_map); |
488 | 0 | std::mem::forget(old_map); |
489 | 0 | Ok(()) |
490 | | } |
491 | 0 | } |
492 | | |
493 | 0 | pub fn lock(&self) -> io::Result<()> { |
494 | | unsafe { |
495 | 0 | if libc::mlock(self.ptr, self.len) != 0 { |
496 | 0 | Err(io::Error::last_os_error()) |
497 | | } else { |
498 | 0 | Ok(()) |
499 | | } |
500 | | } |
501 | 0 | } |
502 | | |
503 | 0 | pub fn unlock(&self) -> io::Result<()> { |
504 | | unsafe { |
505 | 0 | if libc::munlock(self.ptr, self.len) != 0 { |
506 | 0 | Err(io::Error::last_os_error()) |
507 | | } else { |
508 | 0 | Ok(()) |
509 | | } |
510 | | } |
511 | 0 | } |
512 | | } |
513 | | |
514 | | impl Drop for MmapInner { |
515 | 1.57k | fn drop(&mut self) { |
516 | 1.57k | let (ptr, len, _) = self.as_mmap_params(); |
517 | | |
518 | | // Any errors during unmapping/closing are ignored as the only way |
519 | | // to report them would be through panicking which is highly discouraged |
520 | | // in Drop impls, c.f. https://github.com/rust-lang/lang-team/issues/97 |
521 | 1.57k | unsafe { libc::munmap(ptr, len as libc::size_t) }; |
522 | 1.57k | } |
523 | | } |
524 | | |
525 | | unsafe impl Sync for MmapInner {} |
526 | | unsafe impl Send for MmapInner {} |
527 | | |
528 | 9.45k | fn page_size() -> usize { |
529 | | static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); |
530 | | |
531 | 9.45k | match PAGE_SIZE.load(Ordering::Relaxed) { |
532 | | 0 => { |
533 | 1 | let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }; |
534 | | |
535 | 1 | PAGE_SIZE.store(page_size, Ordering::Relaxed); |
536 | | |
537 | 1 | page_size |
538 | | } |
539 | 9.44k | page_size => page_size, |
540 | | } |
541 | 9.45k | } |
542 | | |
543 | 0 | pub fn file_len(file: RawFd) -> io::Result<u64> { |
544 | | // SAFETY: We must not close the passed-in fd by dropping the File we create, |
545 | | // we ensure this by immediately wrapping it in a ManuallyDrop. |
546 | | unsafe { |
547 | 0 | let file = ManuallyDrop::new(File::from_raw_fd(file)); |
548 | 0 | Ok(file.metadata()?.len()) |
549 | | } |
550 | 0 | } |