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