]>
Commit | Line | Data |
---|---|---|
353b0b11 FG |
1 | //! libc syscalls supporting `rustix::mm`. |
2 | ||
3 | use super::super::c; | |
4 | #[cfg(any(target_os = "android", target_os = "linux"))] | |
5 | use super::super::conv::syscall_ret_owned_fd; | |
6 | use super::super::conv::{borrowed_fd, no_fd, ret}; | |
7 | use super::super::offset::libc_mmap; | |
8 | #[cfg(not(target_os = "redox"))] | |
9 | use super::types::Advice; | |
10 | #[cfg(target_os = "linux")] | |
11 | use super::types::MremapFlags; | |
12 | use super::types::{MapFlags, MprotectFlags, MsyncFlags, ProtFlags}; | |
13 | #[cfg(any(target_os = "android", target_os = "linux"))] | |
14 | use super::types::{MlockFlags, UserfaultfdFlags}; | |
15 | use crate::fd::BorrowedFd; | |
16 | #[cfg(any(target_os = "android", target_os = "linux"))] | |
17 | use crate::fd::OwnedFd; | |
18 | use crate::io; | |
19 | ||
20 | #[cfg(not(target_os = "redox"))] | |
21 | pub(crate) fn madvise(addr: *mut c::c_void, len: usize, advice: Advice) -> io::Result<()> { | |
22 | // On Linux platforms, `MADV_DONTNEED` has the same value as | |
23 | // `POSIX_MADV_DONTNEED` but different behavior. We remap it to a different | |
24 | // value, and check for it here. | |
25 | #[cfg(target_os = "linux")] | |
26 | if let Advice::LinuxDontNeed = advice { | |
27 | return unsafe { ret(c::madvise(addr, len, c::MADV_DONTNEED)) }; | |
28 | } | |
29 | ||
30 | #[cfg(not(target_os = "android"))] | |
31 | { | |
32 | let err = unsafe { c::posix_madvise(addr, len, advice as c::c_int) }; | |
33 | ||
34 | // `posix_madvise` returns its error status rather than using `errno`. | |
35 | if err == 0 { | |
36 | Ok(()) | |
37 | } else { | |
38 | Err(io::Errno(err)) | |
39 | } | |
40 | } | |
41 | ||
42 | #[cfg(target_os = "android")] | |
43 | { | |
44 | if let Advice::DontNeed = advice { | |
45 | // Do nothing. Linux's `MADV_DONTNEED` isn't the same as | |
46 | // `POSIX_MADV_DONTNEED`, so just discard `MADV_DONTNEED`. | |
47 | Ok(()) | |
48 | } else { | |
49 | unsafe { ret(c::madvise(addr, len, advice as c::c_int)) } | |
50 | } | |
51 | } | |
52 | } | |
53 | ||
54 | pub(crate) unsafe fn msync(addr: *mut c::c_void, len: usize, flags: MsyncFlags) -> io::Result<()> { | |
55 | let err = c::msync(addr, len, flags.bits()); | |
56 | ||
57 | // `msync` returns its error status rather than using `errno`. | |
58 | if err == 0 { | |
59 | Ok(()) | |
60 | } else { | |
61 | Err(io::Errno(err)) | |
62 | } | |
63 | } | |
64 | ||
65 | /// # Safety | |
66 | /// | |
67 | /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working | |
68 | /// with memory pointed to by raw pointers is unsafe. | |
69 | pub(crate) unsafe fn mmap( | |
70 | ptr: *mut c::c_void, | |
71 | len: usize, | |
72 | prot: ProtFlags, | |
73 | flags: MapFlags, | |
74 | fd: BorrowedFd<'_>, | |
75 | offset: u64, | |
76 | ) -> io::Result<*mut c::c_void> { | |
77 | let res = libc_mmap( | |
78 | ptr, | |
79 | len, | |
80 | prot.bits(), | |
81 | flags.bits(), | |
82 | borrowed_fd(fd), | |
83 | offset as i64, | |
84 | ); | |
85 | if res == c::MAP_FAILED { | |
86 | Err(io::Errno::last_os_error()) | |
87 | } else { | |
88 | Ok(res) | |
89 | } | |
90 | } | |
91 | ||
92 | /// # Safety | |
93 | /// | |
94 | /// `mmap` is primarily unsafe due to the `addr` parameter, as anything working | |
95 | /// with memory pointed to by raw pointers is unsafe. | |
96 | pub(crate) unsafe fn mmap_anonymous( | |
97 | ptr: *mut c::c_void, | |
98 | len: usize, | |
99 | prot: ProtFlags, | |
100 | flags: MapFlags, | |
101 | ) -> io::Result<*mut c::c_void> { | |
102 | let res = libc_mmap( | |
103 | ptr, | |
104 | len, | |
105 | prot.bits(), | |
106 | flags.bits() | c::MAP_ANONYMOUS, | |
107 | no_fd(), | |
108 | 0, | |
109 | ); | |
110 | if res == c::MAP_FAILED { | |
111 | Err(io::Errno::last_os_error()) | |
112 | } else { | |
113 | Ok(res) | |
114 | } | |
115 | } | |
116 | ||
117 | pub(crate) unsafe fn mprotect( | |
118 | ptr: *mut c::c_void, | |
119 | len: usize, | |
120 | flags: MprotectFlags, | |
121 | ) -> io::Result<()> { | |
122 | ret(c::mprotect(ptr, len, flags.bits())) | |
123 | } | |
124 | ||
125 | pub(crate) unsafe fn munmap(ptr: *mut c::c_void, len: usize) -> io::Result<()> { | |
126 | ret(c::munmap(ptr, len)) | |
127 | } | |
128 | ||
129 | /// # Safety | |
130 | /// | |
131 | /// `mremap` is primarily unsafe due to the `old_address` parameter, as | |
132 | /// anything working with memory pointed to by raw pointers is unsafe. | |
133 | #[cfg(target_os = "linux")] | |
134 | pub(crate) unsafe fn mremap( | |
135 | old_address: *mut c::c_void, | |
136 | old_size: usize, | |
137 | new_size: usize, | |
138 | flags: MremapFlags, | |
139 | ) -> io::Result<*mut c::c_void> { | |
140 | let res = c::mremap(old_address, old_size, new_size, flags.bits()); | |
141 | if res == c::MAP_FAILED { | |
142 | Err(io::Errno::last_os_error()) | |
143 | } else { | |
144 | Ok(res) | |
145 | } | |
146 | } | |
147 | ||
148 | /// # Safety | |
149 | /// | |
150 | /// `mremap_fixed` is primarily unsafe due to the `old_address` and | |
151 | /// `new_address` parameters, as anything working with memory pointed to by raw | |
152 | /// pointers is unsafe. | |
153 | #[cfg(target_os = "linux")] | |
154 | pub(crate) unsafe fn mremap_fixed( | |
155 | old_address: *mut c::c_void, | |
156 | old_size: usize, | |
157 | new_size: usize, | |
158 | flags: MremapFlags, | |
159 | new_address: *mut c::c_void, | |
160 | ) -> io::Result<*mut c::c_void> { | |
161 | let res = c::mremap( | |
162 | old_address, | |
163 | old_size, | |
164 | new_size, | |
165 | flags.bits() | c::MAP_FIXED, | |
166 | new_address, | |
167 | ); | |
168 | if res == c::MAP_FAILED { | |
169 | Err(io::Errno::last_os_error()) | |
170 | } else { | |
171 | Ok(res) | |
172 | } | |
173 | } | |
174 | ||
175 | /// # Safety | |
176 | /// | |
177 | /// `mlock` operates on raw pointers and may round out to the nearest page | |
178 | /// boundaries. | |
179 | #[inline] | |
180 | pub(crate) unsafe fn mlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { | |
181 | ret(c::mlock(addr, length)) | |
182 | } | |
183 | ||
184 | /// # Safety | |
185 | /// | |
186 | /// `mlock_with` operates on raw pointers and may round out to the nearest page | |
187 | /// boundaries. | |
188 | #[cfg(any(target_os = "android", target_os = "linux"))] | |
189 | #[inline] | |
190 | pub(crate) unsafe fn mlock_with( | |
191 | addr: *mut c::c_void, | |
192 | length: usize, | |
193 | flags: MlockFlags, | |
194 | ) -> io::Result<()> { | |
195 | weak_or_syscall! { | |
196 | fn mlock2( | |
197 | addr: *const c::c_void, | |
198 | len: c::size_t, | |
199 | flags: c::c_int | |
200 | ) via SYS_mlock2 -> c::c_int | |
201 | } | |
202 | ||
203 | ret(mlock2(addr, length, flags.bits())) | |
204 | } | |
205 | ||
206 | /// # Safety | |
207 | /// | |
208 | /// `munlock` operates on raw pointers and may round out to the nearest page | |
209 | /// boundaries. | |
210 | #[inline] | |
211 | pub(crate) unsafe fn munlock(addr: *mut c::c_void, length: usize) -> io::Result<()> { | |
212 | ret(c::munlock(addr, length)) | |
213 | } | |
214 | ||
215 | #[cfg(any(target_os = "android", target_os = "linux"))] | |
216 | pub(crate) unsafe fn userfaultfd(flags: UserfaultfdFlags) -> io::Result<OwnedFd> { | |
217 | syscall_ret_owned_fd(c::syscall(c::SYS_userfaultfd, flags.bits())) | |
218 | } |