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