1 | //! Memory management declarations. |
2 | |
3 | use crate::errno::Errno; |
4 | #[cfg (not(target_os = "android" ))] |
5 | use crate::NixPath; |
6 | use crate::Result; |
7 | #[cfg (not(target_os = "android" ))] |
8 | #[cfg (feature = "fs" )] |
9 | use crate::{fcntl::OFlag, sys::stat::Mode}; |
10 | use libc::{self, c_int, c_void, off_t, size_t}; |
11 | use std::{os::unix::io::RawFd, num::NonZeroUsize}; |
12 | |
13 | libc_bitflags! { |
14 | /// Desired memory protection of a memory mapping. |
15 | pub struct ProtFlags: c_int { |
16 | /// Pages cannot be accessed. |
17 | PROT_NONE; |
18 | /// Pages can be read. |
19 | PROT_READ; |
20 | /// Pages can be written. |
21 | PROT_WRITE; |
22 | /// Pages can be executed |
23 | PROT_EXEC; |
24 | /// Apply protection up to the end of a mapping that grows upwards. |
25 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
26 | #[cfg_attr(docsrs, doc(cfg(all())))] |
27 | PROT_GROWSDOWN; |
28 | /// Apply protection down to the beginning of a mapping that grows downwards. |
29 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
30 | #[cfg_attr(docsrs, doc(cfg(all())))] |
31 | PROT_GROWSUP; |
32 | } |
33 | } |
34 | |
35 | libc_bitflags! { |
36 | /// Additional parameters for [`mmap`]. |
37 | pub struct MapFlags: c_int { |
38 | /// Compatibility flag. Ignored. |
39 | MAP_FILE; |
40 | /// Share this mapping. Mutually exclusive with `MAP_PRIVATE`. |
41 | MAP_SHARED; |
42 | /// Create a private copy-on-write mapping. Mutually exclusive with `MAP_SHARED`. |
43 | MAP_PRIVATE; |
44 | /// Place the mapping at exactly the address specified in `addr`. |
45 | MAP_FIXED; |
46 | /// Place the mapping at exactly the address specified in `addr`, but never clobber an existing range. |
47 | #[cfg(target_os = "linux" )] |
48 | #[cfg_attr(docsrs, doc(cfg(all())))] |
49 | MAP_FIXED_NOREPLACE; |
50 | /// To be used with `MAP_FIXED`, to forbid the system |
51 | /// to select a different address than the one specified. |
52 | #[cfg(target_os = "freebsd" )] |
53 | #[cfg_attr(docsrs, doc(cfg(all())))] |
54 | MAP_EXCL; |
55 | /// Synonym for `MAP_ANONYMOUS`. |
56 | MAP_ANON; |
57 | /// The mapping is not backed by any file. |
58 | MAP_ANONYMOUS; |
59 | /// Put the mapping into the first 2GB of the process address space. |
60 | #[cfg(any(all(any(target_os = "android" , target_os = "linux" ), |
61 | any(target_arch = "x86" , target_arch = "x86_64" )), |
62 | all(target_os = "linux" , target_env = "musl" , any(target_arch = "x86" , target_arch = "x86_64" )), |
63 | all(target_os = "freebsd" , target_pointer_width = "64" )))] |
64 | #[cfg_attr(docsrs, doc(cfg(all())))] |
65 | MAP_32BIT; |
66 | /// Used for stacks; indicates to the kernel that the mapping should extend downward in memory. |
67 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
68 | #[cfg_attr(docsrs, doc(cfg(all())))] |
69 | MAP_GROWSDOWN; |
70 | /// Compatibility flag. Ignored. |
71 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
72 | #[cfg_attr(docsrs, doc(cfg(all())))] |
73 | MAP_DENYWRITE; |
74 | /// Compatibility flag. Ignored. |
75 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
76 | #[cfg_attr(docsrs, doc(cfg(all())))] |
77 | MAP_EXECUTABLE; |
78 | /// Mark the mmaped region to be locked in the same way as `mlock(2)`. |
79 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
80 | #[cfg_attr(docsrs, doc(cfg(all())))] |
81 | MAP_LOCKED; |
82 | /// Do not reserve swap space for this mapping. |
83 | /// |
84 | /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. |
85 | #[cfg(not(any(target_os = "dragonfly" , target_os = "freebsd" )))] |
86 | #[cfg_attr(docsrs, doc(cfg(all())))] |
87 | MAP_NORESERVE; |
88 | /// Populate page tables for a mapping. |
89 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
90 | #[cfg_attr(docsrs, doc(cfg(all())))] |
91 | MAP_POPULATE; |
92 | /// Only meaningful when used with `MAP_POPULATE`. Don't perform read-ahead. |
93 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
94 | #[cfg_attr(docsrs, doc(cfg(all())))] |
95 | MAP_NONBLOCK; |
96 | /// Allocate the mapping using "huge pages." |
97 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
98 | #[cfg_attr(docsrs, doc(cfg(all())))] |
99 | MAP_HUGETLB; |
100 | /// Make use of 64KB huge page (must be supported by the system) |
101 | #[cfg(target_os = "linux" )] |
102 | #[cfg_attr(docsrs, doc(cfg(all())))] |
103 | MAP_HUGE_64KB; |
104 | /// Make use of 512KB huge page (must be supported by the system) |
105 | #[cfg(target_os = "linux" )] |
106 | #[cfg_attr(docsrs, doc(cfg(all())))] |
107 | MAP_HUGE_512KB; |
108 | /// Make use of 1MB huge page (must be supported by the system) |
109 | #[cfg(target_os = "linux" )] |
110 | #[cfg_attr(docsrs, doc(cfg(all())))] |
111 | MAP_HUGE_1MB; |
112 | /// Make use of 2MB huge page (must be supported by the system) |
113 | #[cfg(target_os = "linux" )] |
114 | #[cfg_attr(docsrs, doc(cfg(all())))] |
115 | MAP_HUGE_2MB; |
116 | /// Make use of 8MB huge page (must be supported by the system) |
117 | #[cfg(target_os = "linux" )] |
118 | #[cfg_attr(docsrs, doc(cfg(all())))] |
119 | MAP_HUGE_8MB; |
120 | /// Make use of 16MB huge page (must be supported by the system) |
121 | #[cfg(target_os = "linux" )] |
122 | #[cfg_attr(docsrs, doc(cfg(all())))] |
123 | MAP_HUGE_16MB; |
124 | /// Make use of 32MB huge page (must be supported by the system) |
125 | #[cfg(target_os = "linux" )] |
126 | #[cfg_attr(docsrs, doc(cfg(all())))] |
127 | MAP_HUGE_32MB; |
128 | /// Make use of 256MB huge page (must be supported by the system) |
129 | #[cfg(target_os = "linux" )] |
130 | #[cfg_attr(docsrs, doc(cfg(all())))] |
131 | MAP_HUGE_256MB; |
132 | /// Make use of 512MB huge page (must be supported by the system) |
133 | #[cfg(target_os = "linux" )] |
134 | #[cfg_attr(docsrs, doc(cfg(all())))] |
135 | MAP_HUGE_512MB; |
136 | /// Make use of 1GB huge page (must be supported by the system) |
137 | #[cfg(target_os = "linux" )] |
138 | #[cfg_attr(docsrs, doc(cfg(all())))] |
139 | MAP_HUGE_1GB; |
140 | /// Make use of 2GB huge page (must be supported by the system) |
141 | #[cfg(target_os = "linux" )] |
142 | #[cfg_attr(docsrs, doc(cfg(all())))] |
143 | MAP_HUGE_2GB; |
144 | /// Make use of 16GB huge page (must be supported by the system) |
145 | #[cfg(target_os = "linux" )] |
146 | #[cfg_attr(docsrs, doc(cfg(all())))] |
147 | MAP_HUGE_16GB; |
148 | |
149 | /// Lock the mapped region into memory as with `mlock(2)`. |
150 | #[cfg(target_os = "netbsd" )] |
151 | #[cfg_attr(docsrs, doc(cfg(all())))] |
152 | MAP_WIRED; |
153 | /// Causes dirtied data in the specified range to be flushed to disk only when necessary. |
154 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" ))] |
155 | #[cfg_attr(docsrs, doc(cfg(all())))] |
156 | MAP_NOSYNC; |
157 | /// Rename private pages to a file. |
158 | /// |
159 | /// This was removed in FreeBSD 11 and is unused in DragonFlyBSD. |
160 | #[cfg(any(target_os = "netbsd" , target_os = "openbsd" ))] |
161 | #[cfg_attr(docsrs, doc(cfg(all())))] |
162 | MAP_RENAME; |
163 | /// Region may contain semaphores. |
164 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" , target_os = "netbsd" , target_os = "openbsd" ))] |
165 | #[cfg_attr(docsrs, doc(cfg(all())))] |
166 | MAP_HASSEMAPHORE; |
167 | /// Region grows down, like a stack. |
168 | #[cfg(any(target_os = "android" , target_os = "dragonfly" , target_os = "freebsd" , target_os = "linux" , target_os = "openbsd" ))] |
169 | #[cfg_attr(docsrs, doc(cfg(all())))] |
170 | MAP_STACK; |
171 | /// Pages in this mapping are not retained in the kernel's memory cache. |
172 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
173 | #[cfg_attr(docsrs, doc(cfg(all())))] |
174 | MAP_NOCACHE; |
175 | /// Allows the W/X bit on the page, it's necessary on aarch64 architecture. |
176 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
177 | #[cfg_attr(docsrs, doc(cfg(all())))] |
178 | MAP_JIT; |
179 | /// Allows to use large pages, underlying alignment based on size. |
180 | #[cfg(target_os = "freebsd" )] |
181 | #[cfg_attr(docsrs, doc(cfg(all())))] |
182 | MAP_ALIGNED_SUPER; |
183 | /// Pages will be discarded in the core dumps. |
184 | #[cfg(target_os = "openbsd" )] |
185 | #[cfg_attr(docsrs, doc(cfg(all())))] |
186 | MAP_CONCEAL; |
187 | } |
188 | } |
189 | |
190 | #[cfg (any(target_os = "linux" , target_os = "netbsd" ))] |
191 | libc_bitflags! { |
192 | /// Options for [`mremap`]. |
193 | pub struct MRemapFlags: c_int { |
194 | /// Permit the kernel to relocate the mapping to a new virtual address, if necessary. |
195 | #[cfg(target_os = "linux" )] |
196 | #[cfg_attr(docsrs, doc(cfg(all())))] |
197 | MREMAP_MAYMOVE; |
198 | /// Place the mapping at exactly the address specified in `new_address`. |
199 | #[cfg(target_os = "linux" )] |
200 | #[cfg_attr(docsrs, doc(cfg(all())))] |
201 | MREMAP_FIXED; |
202 | /// Place the mapping at exactly the address specified in `new_address`. |
203 | #[cfg(target_os = "netbsd" )] |
204 | #[cfg_attr(docsrs, doc(cfg(all())))] |
205 | MAP_FIXED; |
206 | /// Allows to duplicate the mapping to be able to apply different flags on the copy. |
207 | #[cfg(target_os = "netbsd" )] |
208 | #[cfg_attr(docsrs, doc(cfg(all())))] |
209 | MAP_REMAPDUP; |
210 | } |
211 | } |
212 | |
213 | libc_enum! { |
214 | /// Usage information for a range of memory to allow for performance optimizations by the kernel. |
215 | /// |
216 | /// Used by [`madvise`]. |
217 | #[repr(i32)] |
218 | #[non_exhaustive] |
219 | pub enum MmapAdvise { |
220 | /// No further special treatment. This is the default. |
221 | MADV_NORMAL, |
222 | /// Expect random page references. |
223 | MADV_RANDOM, |
224 | /// Expect sequential page references. |
225 | MADV_SEQUENTIAL, |
226 | /// Expect access in the near future. |
227 | MADV_WILLNEED, |
228 | /// Do not expect access in the near future. |
229 | MADV_DONTNEED, |
230 | /// Free up a given range of pages and its associated backing store. |
231 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
232 | #[cfg_attr(docsrs, doc(cfg(all())))] |
233 | MADV_REMOVE, |
234 | /// Do not make pages in this range available to the child after a `fork(2)`. |
235 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
236 | #[cfg_attr(docsrs, doc(cfg(all())))] |
237 | MADV_DONTFORK, |
238 | /// Undo the effect of `MADV_DONTFORK`. |
239 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
240 | #[cfg_attr(docsrs, doc(cfg(all())))] |
241 | MADV_DOFORK, |
242 | /// Poison the given pages. |
243 | /// |
244 | /// Subsequent references to those pages are treated like hardware memory corruption. |
245 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
246 | #[cfg_attr(docsrs, doc(cfg(all())))] |
247 | MADV_HWPOISON, |
248 | /// Enable Kernel Samepage Merging (KSM) for the given pages. |
249 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
250 | #[cfg_attr(docsrs, doc(cfg(all())))] |
251 | MADV_MERGEABLE, |
252 | /// Undo the effect of `MADV_MERGEABLE` |
253 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
254 | #[cfg_attr(docsrs, doc(cfg(all())))] |
255 | MADV_UNMERGEABLE, |
256 | /// Preserve the memory of each page but offline the original page. |
257 | #[cfg(any(target_os = "android" , |
258 | all(target_os = "linux" , any( |
259 | target_arch = "aarch64" , |
260 | target_arch = "arm" , |
261 | target_arch = "powerpc" , |
262 | target_arch = "powerpc64" , |
263 | target_arch = "s390x" , |
264 | target_arch = "x86" , |
265 | target_arch = "x86_64" , |
266 | target_arch = "sparc64" ))))] |
267 | MADV_SOFT_OFFLINE, |
268 | /// Enable Transparent Huge Pages (THP) for pages in the given range. |
269 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
270 | #[cfg_attr(docsrs, doc(cfg(all())))] |
271 | MADV_HUGEPAGE, |
272 | /// Undo the effect of `MADV_HUGEPAGE`. |
273 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
274 | #[cfg_attr(docsrs, doc(cfg(all())))] |
275 | MADV_NOHUGEPAGE, |
276 | /// Exclude the given range from a core dump. |
277 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
278 | #[cfg_attr(docsrs, doc(cfg(all())))] |
279 | MADV_DONTDUMP, |
280 | /// Undo the effect of an earlier `MADV_DONTDUMP`. |
281 | #[cfg(any(target_os = "android" , target_os = "linux" ))] |
282 | #[cfg_attr(docsrs, doc(cfg(all())))] |
283 | MADV_DODUMP, |
284 | /// Specify that the application no longer needs the pages in the given range. |
285 | MADV_FREE, |
286 | /// Request that the system not flush the current range to disk unless it needs to. |
287 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" ))] |
288 | #[cfg_attr(docsrs, doc(cfg(all())))] |
289 | MADV_NOSYNC, |
290 | /// Undoes the effects of `MADV_NOSYNC` for any future pages dirtied within the given range. |
291 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" ))] |
292 | #[cfg_attr(docsrs, doc(cfg(all())))] |
293 | MADV_AUTOSYNC, |
294 | /// Region is not included in a core file. |
295 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" ))] |
296 | #[cfg_attr(docsrs, doc(cfg(all())))] |
297 | MADV_NOCORE, |
298 | /// Include region in a core file |
299 | #[cfg(any(target_os = "dragonfly" , target_os = "freebsd" ))] |
300 | #[cfg_attr(docsrs, doc(cfg(all())))] |
301 | MADV_CORE, |
302 | /// This process should not be killed when swap space is exhausted. |
303 | #[cfg(any(target_os = "freebsd" ))] |
304 | #[cfg_attr(docsrs, doc(cfg(all())))] |
305 | MADV_PROTECT, |
306 | /// Invalidate the hardware page table for the given region. |
307 | #[cfg(target_os = "dragonfly" )] |
308 | #[cfg_attr(docsrs, doc(cfg(all())))] |
309 | MADV_INVAL, |
310 | /// Set the offset of the page directory page to `value` for the virtual page table. |
311 | #[cfg(target_os = "dragonfly" )] |
312 | #[cfg_attr(docsrs, doc(cfg(all())))] |
313 | MADV_SETMAP, |
314 | /// Indicates that the application will not need the data in the given range. |
315 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
316 | #[cfg_attr(docsrs, doc(cfg(all())))] |
317 | MADV_ZERO_WIRED_PAGES, |
318 | /// Pages can be reused (by anyone). |
319 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
320 | #[cfg_attr(docsrs, doc(cfg(all())))] |
321 | MADV_FREE_REUSABLE, |
322 | /// Caller wants to reuse those pages. |
323 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
324 | #[cfg_attr(docsrs, doc(cfg(all())))] |
325 | MADV_FREE_REUSE, |
326 | // Darwin doesn't document this flag's behavior. |
327 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
328 | #[cfg_attr(docsrs, doc(cfg(all())))] |
329 | #[allow(missing_docs)] |
330 | MADV_CAN_REUSE, |
331 | } |
332 | } |
333 | |
334 | libc_bitflags! { |
335 | /// Configuration flags for [`msync`]. |
336 | pub struct MsFlags: c_int { |
337 | /// Schedule an update but return immediately. |
338 | MS_ASYNC; |
339 | /// Invalidate all cached data. |
340 | MS_INVALIDATE; |
341 | /// Invalidate pages, but leave them mapped. |
342 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
343 | #[cfg_attr(docsrs, doc(cfg(all())))] |
344 | MS_KILLPAGES; |
345 | /// Deactivate pages, but leave them mapped. |
346 | #[cfg(any(target_os = "ios" , target_os = "macos" ))] |
347 | #[cfg_attr(docsrs, doc(cfg(all())))] |
348 | MS_DEACTIVATE; |
349 | /// Perform an update and wait for it to complete. |
350 | MS_SYNC; |
351 | } |
352 | } |
353 | |
354 | #[cfg (not(target_os = "haiku" ))] |
355 | libc_bitflags! { |
356 | /// Flags for [`mlockall`]. |
357 | pub struct MlockAllFlags: c_int { |
358 | /// Lock pages that are currently mapped into the address space of the process. |
359 | MCL_CURRENT; |
360 | /// Lock pages which will become mapped into the address space of the process in the future. |
361 | MCL_FUTURE; |
362 | } |
363 | } |
364 | |
365 | /// Locks all memory pages that contain part of the address range with `length` |
366 | /// bytes starting at `addr`. |
367 | /// |
368 | /// Locked pages never move to the swap area. |
369 | /// |
370 | /// # Safety |
371 | /// |
372 | /// `addr` must meet all the requirements described in the [`mlock(2)`] man page. |
373 | /// |
374 | /// [`mlock(2)`]: https://man7.org/linux/man-pages/man2/mlock.2.html |
375 | pub unsafe fn mlock(addr: *const c_void, length: size_t) -> Result<()> { |
376 | Errno::result(libc::mlock(addr, length)).map(op:drop) |
377 | } |
378 | |
379 | /// Unlocks all memory pages that contain part of the address range with |
380 | /// `length` bytes starting at `addr`. |
381 | /// |
382 | /// # Safety |
383 | /// |
384 | /// `addr` must meet all the requirements described in the [`munlock(2)`] man |
385 | /// page. |
386 | /// |
387 | /// [`munlock(2)`]: https://man7.org/linux/man-pages/man2/munlock.2.html |
388 | pub unsafe fn munlock(addr: *const c_void, length: size_t) -> Result<()> { |
389 | Errno::result(libc::munlock(addr, length)).map(op:drop) |
390 | } |
391 | |
392 | /// Locks all memory pages mapped into this process' address space. |
393 | /// |
394 | /// Locked pages never move to the swap area. For more information, see [`mlockall(2)`]. |
395 | /// |
396 | /// [`mlockall(2)`]: https://man7.org/linux/man-pages/man2/mlockall.2.html |
397 | #[cfg (not(target_os = "haiku" ))] |
398 | pub fn mlockall(flags: MlockAllFlags) -> Result<()> { |
399 | unsafe { Errno::result(libc::mlockall(flags.bits())) }.map(op:drop) |
400 | } |
401 | |
402 | /// Unlocks all memory pages mapped into this process' address space. |
403 | /// |
404 | /// For more information, see [`munlockall(2)`]. |
405 | /// |
406 | /// [`munlockall(2)`]: https://man7.org/linux/man-pages/man2/munlockall.2.html |
407 | #[cfg (not(target_os = "haiku" ))] |
408 | pub fn munlockall() -> Result<()> { |
409 | unsafe { Errno::result(libc::munlockall()) }.map(op:drop) |
410 | } |
411 | |
412 | /// allocate memory, or map files or devices into memory |
413 | /// |
414 | /// # Safety |
415 | /// |
416 | /// See the [`mmap(2)`] man page for detailed requirements. |
417 | /// |
418 | /// [`mmap(2)`]: https://man7.org/linux/man-pages/man2/mmap.2.html |
419 | pub unsafe fn mmap( |
420 | addr: Option<NonZeroUsize>, |
421 | length: NonZeroUsize, |
422 | prot: ProtFlags, |
423 | flags: MapFlags, |
424 | fd: RawFd, |
425 | offset: off_t, |
426 | ) -> Result<*mut c_void> { |
427 | let ptr: *mut c_void = addr.map_or( |
428 | default:std::ptr::null_mut(), |
429 | |a: NonZero| usize::from(a) as *mut c_void |
430 | ); |
431 | |
432 | let ret: *mut c_void = libc::mmap(addr:ptr, len:length.into(), prot:prot.bits(), flags:flags.bits(), fd, offset); |
433 | |
434 | if ret == libc::MAP_FAILED { |
435 | Err(Errno::last()) |
436 | } else { |
437 | Ok(ret) |
438 | } |
439 | } |
440 | |
441 | /// Expands (or shrinks) an existing memory mapping, potentially moving it at |
442 | /// the same time. |
443 | /// |
444 | /// # Safety |
445 | /// |
446 | /// See the `mremap(2)` [man page](https://man7.org/linux/man-pages/man2/mremap.2.html) for |
447 | /// detailed requirements. |
448 | #[cfg (any(target_os = "linux" , target_os = "netbsd" ))] |
449 | pub unsafe fn mremap( |
450 | addr: *mut c_void, |
451 | old_size: size_t, |
452 | new_size: size_t, |
453 | flags: MRemapFlags, |
454 | new_address: Option<*mut c_void>, |
455 | ) -> Result<*mut c_void> { |
456 | #[cfg (target_os = "linux" )] |
457 | let ret: *mut c_void = libc::mremap( |
458 | addr, |
459 | len:old_size, |
460 | new_len:new_size, |
461 | flags:flags.bits(), |
462 | new_address.unwrap_or(default:std::ptr::null_mut()), |
463 | ); |
464 | #[cfg (target_os = "netbsd" )] |
465 | let ret = libc::mremap( |
466 | addr, |
467 | old_size, |
468 | new_address.unwrap_or(std::ptr::null_mut()), |
469 | new_size, |
470 | flags.bits(), |
471 | ); |
472 | |
473 | if ret == libc::MAP_FAILED { |
474 | Err(Errno::last()) |
475 | } else { |
476 | Ok(ret) |
477 | } |
478 | } |
479 | |
480 | /// remove a mapping |
481 | /// |
482 | /// # Safety |
483 | /// |
484 | /// `addr` must meet all the requirements described in the [`munmap(2)`] man |
485 | /// page. |
486 | /// |
487 | /// [`munmap(2)`]: https://man7.org/linux/man-pages/man2/munmap.2.html |
488 | pub unsafe fn munmap(addr: *mut c_void, len: size_t) -> Result<()> { |
489 | Errno::result(libc::munmap(addr, len)).map(op:drop) |
490 | } |
491 | |
492 | /// give advice about use of memory |
493 | /// |
494 | /// # Safety |
495 | /// |
496 | /// See the [`madvise(2)`] man page. Take special care when using |
497 | /// [`MmapAdvise::MADV_FREE`]. |
498 | /// |
499 | /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html |
500 | pub unsafe fn madvise( |
501 | addr: *mut c_void, |
502 | length: size_t, |
503 | advise: MmapAdvise, |
504 | ) -> Result<()> { |
505 | Errno::result(libc::madvise(addr, length, advise as i32)).map(op:drop) |
506 | } |
507 | |
508 | /// Set protection of memory mapping. |
509 | /// |
510 | /// See [`mprotect(3)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html) for |
511 | /// details. |
512 | /// |
513 | /// # Safety |
514 | /// |
515 | /// Calls to `mprotect` are inherently unsafe, as changes to memory protections can lead to |
516 | /// SIGSEGVs. |
517 | /// |
518 | /// ``` |
519 | /// # use nix::libc::size_t; |
520 | /// # use nix::sys::mman::{mmap, mprotect, MapFlags, ProtFlags}; |
521 | /// # use std::ptr; |
522 | /// const ONE_K: size_t = 1024; |
523 | /// let one_k_non_zero = std::num::NonZeroUsize::new(ONE_K).unwrap(); |
524 | /// let mut slice: &mut [u8] = unsafe { |
525 | /// let mem = mmap(None, one_k_non_zero, ProtFlags::PROT_NONE, |
526 | /// MapFlags::MAP_ANON | MapFlags::MAP_PRIVATE, -1, 0).unwrap(); |
527 | /// mprotect(mem, ONE_K, ProtFlags::PROT_READ | ProtFlags::PROT_WRITE).unwrap(); |
528 | /// std::slice::from_raw_parts_mut(mem as *mut u8, ONE_K) |
529 | /// }; |
530 | /// assert_eq!(slice[0], 0x00); |
531 | /// slice[0] = 0xFF; |
532 | /// assert_eq!(slice[0], 0xFF); |
533 | /// ``` |
534 | pub unsafe fn mprotect( |
535 | addr: *mut c_void, |
536 | length: size_t, |
537 | prot: ProtFlags, |
538 | ) -> Result<()> { |
539 | Errno::result(libc::mprotect(addr, length, prot.bits())).map(op:drop) |
540 | } |
541 | |
542 | /// synchronize a mapped region |
543 | /// |
544 | /// # Safety |
545 | /// |
546 | /// `addr` must meet all the requirements described in the [`msync(2)`] man |
547 | /// page. |
548 | /// |
549 | /// [`msync(2)`]: https://man7.org/linux/man-pages/man2/msync.2.html |
550 | pub unsafe fn msync( |
551 | addr: *mut c_void, |
552 | length: size_t, |
553 | flags: MsFlags, |
554 | ) -> Result<()> { |
555 | Errno::result(libc::msync(addr, length, flags.bits())).map(op:drop) |
556 | } |
557 | |
558 | #[cfg (not(target_os = "android" ))] |
559 | feature! { |
560 | #![feature = "fs" ] |
561 | /// Creates and opens a new, or opens an existing, POSIX shared memory object. |
562 | /// |
563 | /// For more information, see [`shm_open(3)`]. |
564 | /// |
565 | /// [`shm_open(3)`]: https://man7.org/linux/man-pages/man3/shm_open.3.html |
566 | pub fn shm_open<P>( |
567 | name: &P, |
568 | flag: OFlag, |
569 | mode: Mode |
570 | ) -> Result<RawFd> |
571 | where P: ?Sized + NixPath |
572 | { |
573 | let ret = name.with_nix_path(|cstr| { |
574 | #[cfg (any(target_os = "macos" , target_os = "ios" ))] |
575 | unsafe { |
576 | libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::c_uint) |
577 | } |
578 | #[cfg (not(any(target_os = "macos" , target_os = "ios" )))] |
579 | unsafe { |
580 | libc::shm_open(cstr.as_ptr(), flag.bits(), mode.bits() as libc::mode_t) |
581 | } |
582 | })?; |
583 | |
584 | Errno::result(ret) |
585 | } |
586 | } |
587 | |
588 | /// Performs the converse of [`shm_open`], removing an object previously created. |
589 | /// |
590 | /// For more information, see [`shm_unlink(3)`]. |
591 | /// |
592 | /// [`shm_unlink(3)`]: https://man7.org/linux/man-pages/man3/shm_unlink.3.html |
593 | #[cfg (not(target_os = "android" ))] |
594 | pub fn shm_unlink<P: ?Sized + NixPath>(name: &P) -> Result<()> { |
595 | let ret: i32 = |
596 | name.with_nix_path(|cstr: &CStr| unsafe { libc::shm_unlink(name:cstr.as_ptr()) })?; |
597 | |
598 | Errno::result(ret).map(op:drop) |
599 | } |
600 | |