]> git.proxmox.com Git - proxmox.git/blob - proxmox-sys/src/mmap.rs
move io error helpers to proxmox-lang
[proxmox.git] / proxmox-sys / src / mmap.rs
1 //! Memory mapping helpers.
2
3 use std::convert::TryFrom;
4 use std::mem::MaybeUninit;
5 use std::os::unix::io::RawFd;
6 use std::{io, mem, ptr};
7
8 use nix::sys::mman;
9
10 use proxmox_lang::error::io_err_other;
11
12 use crate::error::{SysError};
13
14 pub struct Mmap<T> {
15 data: *mut T,
16 len: usize,
17 }
18
19 unsafe impl<T> Send for Mmap<T> where T: Send {}
20 unsafe impl<T> Sync for Mmap<T> where T: Sync {}
21
22 impl<T> Mmap<T> {
23 /// Map a file into memory.
24 ///
25 /// # Safety
26 ///
27 /// `fd` must refer to a valid file descriptor.
28 pub unsafe fn map_fd(
29 fd: RawFd,
30 ofs: u64,
31 count: usize,
32 prot: mman::ProtFlags,
33 flags: mman::MapFlags,
34 ) -> io::Result<Self> {
35 let byte_len = count * mem::size_of::<T>();
36 // libc::size_t vs usize
37 #[allow(clippy::useless_conversion)]
38 let data = mman::mmap(
39 ptr::null_mut(),
40 libc::size_t::try_from(byte_len).map_err(io_err_other)?,
41 prot,
42 flags,
43 fd,
44 libc::off_t::try_from(ofs).map_err(io_err_other)?,
45 )
46 .map_err(SysError::into_io_error)?;
47
48 Ok(Self {
49 data: data as *mut T,
50 len: count,
51 })
52 }
53 }
54
55 impl<T> std::ops::Deref for Mmap<T> {
56 type Target = [T];
57
58 #[inline]
59 fn deref(&self) -> &[T] {
60 unsafe { std::slice::from_raw_parts(self.data, self.len) }
61 }
62 }
63
64 impl<T> std::ops::DerefMut for Mmap<T> {
65 #[inline]
66 fn deref_mut(&mut self) -> &mut [T] {
67 unsafe { std::slice::from_raw_parts_mut(self.data, self.len) }
68 }
69 }
70
71 impl<T> Drop for Mmap<T> {
72 fn drop(&mut self) {
73 unsafe {
74 // In theory this can fail if too many memory mappings are already present and
75 // unmapping a smaller region inside a bigger one, causing it to become split into 2
76 // regions. But then we have bigger problems already anyway, so we'll just ignore this.
77 let _ = mman::munmap(
78 self.data as *mut libc::c_void,
79 self.len * mem::size_of::<T>(),
80 );
81 }
82 }
83 }
84
85 impl<'a, T> IntoIterator for &'a Mmap<T> {
86 type Item = &'a T;
87 type IntoIter = <&'a [T] as IntoIterator>::IntoIter;
88
89 fn into_iter(self) -> Self::IntoIter {
90 <&'a [T] as IntoIterator>::into_iter(self)
91 }
92 }
93
94 impl<T> Mmap<MaybeUninit<T>> {
95 /// Converts to `Mmap<T>`.
96 ///
97 /// # Safety
98 ///
99 /// It is up to the caller to ensure this is safe, see
100 /// [`MaybeUninit::assume_init`](std::mem::MaybeUninit::assume_init).
101 pub unsafe fn assume_init(self) -> Mmap<T> {
102 let out = Mmap {
103 data: self.data as *mut T,
104 len: self.len,
105 };
106 std::mem::forget(self);
107 out
108 }
109 }