diff --git a/src/advice.rs b/src/advice.rs index 9b25e4ff..4316058f 100644 --- a/src/advice.rs +++ b/src/advice.rs @@ -1,145 +1,32 @@ /// Values supported by [`Mmap::advise`][crate::Mmap::advise] and [`MmapMut::advise`][crate::MmapMut::advise] functions. +/// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. -#[derive(Debug, Eq, PartialEq, Hash)] -pub struct Advice(pub(crate) libc::c_int); - -impl Advice { +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum Advice { /// **MADV_NORMAL** /// /// No special treatment. This is the default. - pub fn normal() -> Self { - Self(libc::MADV_NORMAL) - } + Normal = libc::MADV_NORMAL, /// **MADV_RANDOM** /// /// Expect page references in random order. (Hence, read /// ahead may be less useful than normally.) - pub fn random() -> Self { - Self(libc::MADV_RANDOM) - } + Random = libc::MADV_RANDOM, /// **MADV_SEQUENTIAL** /// /// Expect page references in sequential order. (Hence, pages /// in the given range can be aggressively read ahead, and may /// be freed soon after they are accessed.) - pub fn sequential() -> Self { - Self(libc::MADV_SEQUENTIAL) - } + Sequential = libc::MADV_SEQUENTIAL, /// **MADV_WILLNEED** /// /// Expect access in the near future. (Hence, it might be a /// good idea to read some pages ahead.) - pub fn will_need() -> Self { - Self(libc::MADV_WILLNEED) - } - - /// **MADV_DONTNEED** - /// - /// Do not expect access in the near future. (For the time - /// being, the application is finished with the given range, - /// so the kernel can free resources associated with it.) - /// - /// After a successful MADV_DONTNEED operation, the semantics - /// of memory access in the specified region are changed: - /// subsequent accesses of pages in the range will succeed, - /// but will result in either repopulating the memory contents - /// from the up-to-date contents of the underlying mapped file - /// (for shared file mappings, shared anonymous mappings, and - /// shmem-based techniques such as System V shared memory - /// segments) or zero-fill-on-demand pages for anonymous - /// private mappings. - /// - /// Note that, when applied to shared mappings, MADV_DONTNEED - /// might not lead to immediate freeing of the pages in the - /// range. The kernel is free to delay freeing the pages - /// until an appropriate moment. The resident set size (RSS) - /// of the calling process will be immediately reduced - /// however. - /// - /// **MADV_DONTNEED** cannot be applied to locked pages, Huge TLB - /// pages, or VM_PFNMAP pages. (Pages marked with the kernel- - /// internal VM_PFNMAP flag are special memory areas that are - /// not managed by the virtual memory subsystem. Such pages - /// are typically created by device drivers that map the pages - /// into user space.) - /// - /// # Safety - /// - /// Using the returned value with conceptually write to the - /// mapped pages, i.e. borrowing the mapping when the pages - /// are freed results in undefined behaviour. - pub unsafe fn dont_need() -> Self { - Self(libc::MADV_DONTNEED) - } - - // - // The rest are Linux-specific - // - /// **MADV_FREE** - Linux (since Linux 4.5) and Darwin - /// - /// The application no longer requires the pages in the range - /// specified by addr and len. The kernel can thus free these - /// pages, but the freeing could be delayed until memory - /// pressure occurs. For each of the pages that has been - /// marked to be freed but has not yet been freed, the free - /// operation will be canceled if the caller writes into the - /// page. After a successful MADV_FREE operation, any stale - /// data (i.e., dirty, unwritten pages) will be lost when the - /// kernel frees the pages. However, subsequent writes to - /// pages in the range will succeed and then kernel cannot - /// free those dirtied pages, so that the caller can always - /// see just written data. If there is no subsequent write, - /// the kernel can free the pages at any time. Once pages in - /// the range have been freed, the caller will see zero-fill- - /// on-demand pages upon subsequent page references. - /// - /// The MADV_FREE operation can be applied only to private - /// anonymous pages (see mmap(2)). In Linux before version - /// 4.12, when freeing pages on a swapless system, the pages - /// in the given range are freed instantly, regardless of - /// memory pressure. - /// - /// # Safety - /// - /// Using the returned value with conceptually write to the - /// mapped pages, i.e. borrowing the mapping while the pages - /// are still being freed results in undefined behaviour. - #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))] - pub unsafe fn free() -> Self { - Self(libc::MADV_FREE) - } - - /// **MADV_REMOVE** - Linux only (since Linux 2.6.16) - /// - /// Free up a given range of pages and its associated backing - /// store. This is equivalent to punching a hole in the - /// corresponding byte range of the backing store (see - /// fallocate(2)). Subsequent accesses in the specified - /// address range will see bytes containing zero. - /// - /// The specified address range must be mapped shared and - /// writable. This flag cannot be applied to locked pages, - /// Huge TLB pages, or VM_PFNMAP pages. - /// - /// In the initial implementation, only tmpfs(5) was supported - /// **MADV_REMOVE**; but since Linux 3.5, any filesystem which - /// supports the fallocate(2) FALLOC_FL_PUNCH_HOLE mode also - /// supports MADV_REMOVE. Hugetlbfs fails with the error - /// EINVAL and other filesystems fail with the error - /// EOPNOTSUPP. - /// - /// # Safety - /// - /// Using the returned value with conceptually write to the - /// mapped pages, i.e. borrowing the mapping when the pages - /// are freed results in undefined behaviour. - #[cfg(target_os = "linux")] - pub unsafe fn remove() -> Self { - Self(libc::MADV_REMOVE) - } + WillNeed = libc::MADV_WILLNEED, /// **MADV_DONTFORK** - Linux only (since Linux 2.6.16) /// @@ -150,18 +37,14 @@ impl Advice { /// relocations cause problems for hardware that DMAs into the /// page.) #[cfg(target_os = "linux")] - pub fn dont_fork() -> Self { - Self(libc::MADV_DONTFORK) - } + DontFork = libc::MADV_DONTFORK, /// **MADV_DOFORK** - Linux only (since Linux 2.6.16) /// /// Undo the effect of MADV_DONTFORK, restoring the default /// behavior, whereby a mapping is inherited across fork(2). #[cfg(target_os = "linux")] - pub fn do_fork() -> Self { - Self(libc::MADV_DOFORK) - } + DoFork = libc::MADV_DOFORK, /// **MADV_MERGEABLE** - Linux only (since Linux 2.6.32) /// @@ -184,9 +67,7 @@ impl Advice { /// available only if the kernel was configured with /// CONFIG_KSM. #[cfg(target_os = "linux")] - pub fn mergeable() -> Self { - Self(libc::MADV_MERGEABLE) - } + Mergeable = libc::MADV_MERGEABLE, /// **MADV_UNMERGEABLE** - Linux only (since Linux 2.6.32) /// @@ -195,9 +76,7 @@ impl Advice { /// it had merged in the address range specified by addr and /// length. #[cfg(target_os = "linux")] - pub fn unmergeable() -> Self { - Self(libc::MADV_UNMERGEABLE) - } + Unmergeable = libc::MADV_UNMERGEABLE, /// **MADV_HUGEPAGE** - Linux only (since Linux 2.6.38) /// @@ -236,18 +115,14 @@ impl Advice { /// available only if the kernel was configured with /// CONFIG_TRANSPARENT_HUGEPAGE. #[cfg(target_os = "linux")] - pub fn huge_page() -> Self { - Self(libc::MADV_HUGEPAGE) - } + HugePage = libc::MADV_HUGEPAGE, /// **MADV_NOHUGEPAGE** - Linux only (since Linux 2.6.38) /// /// Ensures that memory in the address range specified by addr /// and length will not be backed by transparent hugepages. #[cfg(target_os = "linux")] - pub fn no_huge_page() -> Self { - Self(libc::MADV_NOHUGEPAGE) - } + NoHugePage = libc::MADV_NOHUGEPAGE, /// **MADV_DONTDUMP** - Linux only (since Linux 3.4) /// @@ -259,17 +134,13 @@ impl Advice { /// set via the `/proc/[pid]/coredump_filter` file (see /// core(5)). #[cfg(target_os = "linux")] - pub fn dont_dump() -> Self { - Self(libc::MADV_DONTDUMP) - } + DontDump = libc::MADV_DONTDUMP, /// **MADV_DODUMP** - Linux only (since Linux 3.4) /// /// Undo the effect of an earlier MADV_DONTDUMP. #[cfg(target_os = "linux")] - pub fn do_dump() -> Self { - Self(libc::MADV_DODUMP) - } + DoDump = libc::MADV_DODUMP, /// **MADV_HWPOISON** - Linux only (since Linux 2.6.32) /// @@ -284,9 +155,7 @@ impl Advice { /// handling code; it is available only if the kernel was /// configured with CONFIG_MEMORY_FAILURE. #[cfg(target_os = "linux")] - pub fn hw_poison() -> Self { - Self(libc::MADV_HWPOISON) - } + HwPoison = libc::MADV_HWPOISON, /// **MADV_POPULATE_READ** - Linux only (since Linux 5.14) /// @@ -321,9 +190,7 @@ impl Advice { /// Note that with MADV_POPULATE_READ, the process can be killed /// at any moment when the system runs out of memory. #[cfg(target_os = "linux")] - pub fn populate_read() -> Self { - Self(libc::MADV_POPULATE_READ) - } + PopulateRead = libc::MADV_POPULATE_READ, /// **MADV_POPULATE_WRITE** - Linux only (since Linux 5.14) /// @@ -355,9 +222,7 @@ impl Advice { /// Note that with MADV_POPULATE_WRITE, the process can be killed /// at any moment when the system runs out of memory. #[cfg(target_os = "linux")] - pub fn populate_write() -> Self { - Self(libc::MADV_POPULATE_WRITE) - } + PopulateWrite = libc::MADV_POPULATE_WRITE, /// **MADV_ZERO_WIRED_PAGES** - Darwin only /// @@ -366,9 +231,123 @@ impl Advice { /// a munmap(2) without a preceding munlock(2) or the application quits). This is used /// with madvise() system call. #[cfg(any(target_os = "macos", target_os = "ios"))] - pub fn zero_wired_pages() -> Self { - Self(libc::MADV_ZERO_WIRED_PAGES) - } + ZeroWiredPages = libc::MADV_ZERO_WIRED_PAGES, +} + +/// Values supported by [`Mmap::unsafe_advise`][crate::Mmap::unsafe_advise] and [`MmapMut::unsafe_advise`][crate::MmapMut::unsafe_advise] functions. +/// +/// These flags can be passed to the [madvise (2)][man_page] system call +/// and effects on the mapped pages which are conceptually writes, +/// i.e. the change the observable contents of these pages which +/// implies undefined behaviour if the mapping is still borrowed. +/// +/// Hence, these potentially unsafe flags must be used with the unsafe +/// methods and the programmer has to justify that the code +/// does not keep any borrows of the mapping active while the mapped pages +/// are updated by the kernel's memory management subsystem. +/// +/// [man_page]: https://man7.org/linux/man-pages/man2/madvise.2.html +#[repr(i32)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum UncheckedAdvice { + /// **MADV_DONTNEED** + /// + /// Do not expect access in the near future. (For the time + /// being, the application is finished with the given range, + /// so the kernel can free resources associated with it.) + /// + /// After a successful MADV_DONTNEED operation, the semantics + /// of memory access in the specified region are changed: + /// subsequent accesses of pages in the range will succeed, + /// but will result in either repopulating the memory contents + /// from the up-to-date contents of the underlying mapped file + /// (for shared file mappings, shared anonymous mappings, and + /// shmem-based techniques such as System V shared memory + /// segments) or zero-fill-on-demand pages for anonymous + /// private mappings. + /// + /// Note that, when applied to shared mappings, MADV_DONTNEED + /// might not lead to immediate freeing of the pages in the + /// range. The kernel is free to delay freeing the pages + /// until an appropriate moment. The resident set size (RSS) + /// of the calling process will be immediately reduced + /// however. + /// + /// **MADV_DONTNEED** cannot be applied to locked pages, Huge TLB + /// pages, or VM_PFNMAP pages. (Pages marked with the kernel- + /// internal VM_PFNMAP flag are special memory areas that are + /// not managed by the virtual memory subsystem. Such pages + /// are typically created by device drivers that map the pages + /// into user space.) + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping when the pages + /// are freed results in undefined behaviour. + DontNeed = libc::MADV_DONTNEED, + + // + // The rest are Linux-specific + // + /// **MADV_FREE** - Linux (since Linux 4.5) and Darwin + /// + /// The application no longer requires the pages in the range + /// specified by addr and len. The kernel can thus free these + /// pages, but the freeing could be delayed until memory + /// pressure occurs. For each of the pages that has been + /// marked to be freed but has not yet been freed, the free + /// operation will be canceled if the caller writes into the + /// page. After a successful MADV_FREE operation, any stale + /// data (i.e., dirty, unwritten pages) will be lost when the + /// kernel frees the pages. However, subsequent writes to + /// pages in the range will succeed and then kernel cannot + /// free those dirtied pages, so that the caller can always + /// see just written data. If there is no subsequent write, + /// the kernel can free the pages at any time. Once pages in + /// the range have been freed, the caller will see zero-fill- + /// on-demand pages upon subsequent page references. + /// + /// The MADV_FREE operation can be applied only to private + /// anonymous pages (see mmap(2)). In Linux before version + /// 4.12, when freeing pages on a swapless system, the pages + /// in the given range are freed instantly, regardless of + /// memory pressure. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping while the pages + /// are still being freed results in undefined behaviour. + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))] + Free = libc::MADV_FREE, + + /// **MADV_REMOVE** - Linux only (since Linux 2.6.16) + /// + /// Free up a given range of pages and its associated backing + /// store. This is equivalent to punching a hole in the + /// corresponding byte range of the backing store (see + /// fallocate(2)). Subsequent accesses in the specified + /// address range will see bytes containing zero. + /// + /// The specified address range must be mapped shared and + /// writable. This flag cannot be applied to locked pages, + /// Huge TLB pages, or VM_PFNMAP pages. + /// + /// In the initial implementation, only tmpfs(5) was supported + /// **MADV_REMOVE**; but since Linux 3.5, any filesystem which + /// supports the fallocate(2) FALLOC_FL_PUNCH_HOLE mode also + /// supports MADV_REMOVE. Hugetlbfs fails with the error + /// EINVAL and other filesystems fail with the error + /// EOPNOTSUPP. + /// + /// # Safety + /// + /// Using the returned value with conceptually write to the + /// mapped pages, i.e. borrowing the mapping when the pages + /// are freed results in undefined behaviour. + #[cfg(target_os = "linux")] + Remove = libc::MADV_REMOVE, /// **MADV_FREE_REUSABLE** - Darwin only /// @@ -380,9 +359,7 @@ impl Advice { /// mapped pages, i.e. borrowing the mapping while the pages /// are still being freed results in undefined behaviour. #[cfg(any(target_os = "macos", target_os = "ios"))] - pub unsafe fn free_reusable() -> Self { - Self(libc::MADV_FREE_REUSABLE) - } + FreeReusable = libc::MADV_FREE_REUSABLE, /// **MADV_FREE_REUSE** - Darwin only /// @@ -396,9 +373,7 @@ impl Advice { /// mapped pages, i.e. borrowing the mapping while the pages /// are still being freed results in undefined behaviour. #[cfg(any(target_os = "macos", target_os = "ios"))] - pub unsafe fn free_reuse() -> Self { - Self(libc::MADV_FREE_REUSE) - } + FreeReuse = libc::MADV_FREE_REUSE, } // Future expansion: diff --git a/src/lib.rs b/src/lib.rs index 61239be4..d6a185d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ use crate::os::{file_len, MmapInner}; #[cfg(unix)] mod advice; #[cfg(unix)] -pub use crate::advice::Advice; +pub use crate::advice::{Advice, UncheckedAdvice}; use std::fmt; #[cfg(not(any(unix, windows)))] @@ -639,24 +639,55 @@ impl Mmap { Ok(MmapMut { inner: self.inner }) } - /// Advise OS how this memory map will be accessed. Only supported on Unix. + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. /// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise(&self, advice: Advice) -> Result<()> { - self.inner.advise(advice, 0, self.inner.len()) + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) } - /// Advise OS how this range of memory map will be accessed. + /// Advise OS how this memory map will be accessed. /// - /// The offset and length must be in the bounds of the memory map. + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this range of memory map will be accessed. /// /// Only supported on Unix. /// + /// The offset and length must be in the bounds of the memory map. + /// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { - self.inner.advise(advice, offset, len) + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) } /// Lock the whole memory map into RAM. Only supported on Unix. @@ -852,12 +883,26 @@ impl MmapRaw { self.inner.flush_async(offset, len) } - /// Advise OS how this memory map will be accessed. Only supported on Unix. + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. /// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise(&self, advice: Advice) -> Result<()> { - self.inner.advise(advice, 0, self.inner.len()) + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) } /// Advise OS how this range of memory map will be accessed. @@ -869,7 +914,24 @@ impl MmapRaw { /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { - self.inner.advise(advice, offset, len) + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) } /// Lock the whole memory map into RAM. Only supported on Unix. @@ -1142,24 +1204,55 @@ impl MmapMut { Ok(Mmap { inner: self.inner }) } - /// Advise OS how this memory map will be accessed. Only supported on Unix. + /// Advise OS how this memory map will be accessed. + /// + /// Only supported on Unix. /// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise(&self, advice: Advice) -> Result<()> { - self.inner.advise(advice, 0, self.inner.len()) + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) } - /// Advise OS how this range of memory map will be accessed. + /// Advise OS how this memory map will be accessed. /// - /// The offset and length must be in the bounds of the memory map. + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub unsafe fn unchecked_advise(&self, advice: UncheckedAdvice) -> Result<()> { + self.inner + .advise(advice as libc::c_int, 0, self.inner.len()) + } + + /// Advise OS how this range of memory map will be accessed. /// /// Only supported on Unix. /// + /// The offset and length must be in the bounds of the memory map. + /// /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. #[cfg(unix)] pub fn advise_range(&self, advice: Advice, offset: usize, len: usize) -> Result<()> { - self.inner.advise(advice, offset, len) + self.inner.advise(advice as libc::c_int, offset, len) + } + + /// Advise OS how this range of memory map will be accessed. + /// + /// Used with the [unchecked flags][UncheckedAdvice]. Only supported on Unix. + /// + /// The offset and length must be in the bounds of the memory map. + /// + /// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page. + #[cfg(unix)] + pub fn unchecked_advise_range( + &self, + advice: UncheckedAdvice, + offset: usize, + len: usize, + ) -> Result<()> { + self.inner.advise(advice as libc::c_int, offset, len) } /// Lock the whole memory map into RAM. Only supported on Unix. @@ -1293,7 +1386,7 @@ mod test { extern crate tempfile; #[cfg(unix)] - use crate::advice::Advice; + use crate::advice::{Advice, UncheckedAdvice}; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; use std::mem; @@ -1816,7 +1909,7 @@ mod test { // Test MmapMut::advise let mut mmap = unsafe { MmapMut::map_mut(&file).unwrap() }; - mmap.advise(Advice::random()) + mmap.advise(Advice::Random) .expect("mmap advising should be supported on unix"); let len = mmap.len(); @@ -1828,7 +1921,7 @@ mod test { // check that the mmap is empty assert_eq!(&zeros[..], &mmap[..]); - mmap.advise_range(Advice::sequential(), 0, mmap.len()) + mmap.advise_range(Advice::Sequential, 0, mmap.len()) .expect("mmap advising should be supported on unix"); // write values into the mmap @@ -1840,7 +1933,7 @@ mod test { // Set advice and Read from the read-only map let mmap = unsafe { Mmap::map(&file).unwrap() }; - mmap.advise(Advice::random()) + mmap.advise(Advice::Random) .expect("mmap advising should be supported on unix"); // read values back @@ -1855,13 +1948,37 @@ mod test { let mmap = mmap.make_read_only().unwrap(); let a = mmap.as_ref()[0]; - mmap.advise(unsafe { Advice::dont_need() }).unwrap(); + unsafe { + mmap.unchecked_advise(UncheckedAdvice::DontNeed).unwrap(); + } let b = mmap.as_ref()[0]; assert_eq!(a, 255); assert_eq!(b, 0); } + #[test] + #[cfg(target_os = "linux")] + fn advise_writes_unsafely_to_part_of_map() { + let mut mmap = MmapMut::map_anon(8192).unwrap(); + mmap.as_mut().fill(255); + let mmap = mmap.make_read_only().unwrap(); + + let a = mmap.as_ref()[0]; + let b = mmap.as_ref()[4096]; + unsafe { + mmap.unchecked_advise_range(UncheckedAdvice::DontNeed, 4096, 4096) + .unwrap(); + } + let c = mmap.as_ref()[0]; + let d = mmap.as_ref()[4096]; + + assert_eq!(a, 255); + assert_eq!(b, 255); + assert_eq!(c, 255); + assert_eq!(d, 0); + } + /// Returns true if a non-zero amount of memory is locked. #[cfg(target_os = "linux")] fn is_locked() -> bool { diff --git a/src/unix.rs b/src/unix.rs index 3761b27c..1df5691e 100644 --- a/src/unix.rs +++ b/src/unix.rs @@ -6,8 +6,6 @@ use std::os::unix::io::{FromRawFd, RawFd}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{io, ptr}; -use crate::advice::Advice; - #[cfg(any( all(target_os = "linux", not(target_arch = "mips")), target_os = "freebsd", @@ -342,12 +340,12 @@ impl MmapInner { self.len } - pub fn advise(&self, advice: Advice, offset: usize, len: usize) -> io::Result<()> { + pub fn advise(&self, advice: libc::c_int, offset: usize, len: usize) -> io::Result<()> { let alignment = (self.ptr as usize + offset) % page_size(); let offset = offset as isize - alignment as isize; let len = len + alignment; unsafe { - if libc::madvise(self.ptr.offset(offset), len, advice.0) != 0 { + if libc::madvise(self.ptr.offset(offset), len, advice) != 0 { Err(io::Error::last_os_error()) } else { Ok(())