Coverage Report

Created: 2025-09-27 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/memmap2-0.9.8/src/advice.rs
Line
Count
Source
1
/// Values supported by [`Mmap::advise`][crate::Mmap::advise] and [`MmapMut::advise`][crate::MmapMut::advise] functions.
2
///
3
/// See [madvise()](https://man7.org/linux/man-pages/man2/madvise.2.html) map page.
4
#[repr(i32)]
5
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
6
pub enum Advice {
7
    /// **MADV_NORMAL**
8
    ///
9
    /// No special treatment.  This is the default.
10
    Normal = libc::MADV_NORMAL,
11
12
    /// **MADV_RANDOM**
13
    ///
14
    /// Expect page references in random order.  (Hence, read
15
    /// ahead may be less useful than normally.)
16
    Random = libc::MADV_RANDOM,
17
18
    /// **MADV_SEQUENTIAL**
19
    ///
20
    /// Expect page references in sequential order.  (Hence, pages
21
    /// in the given range can be aggressively read ahead, and may
22
    /// be freed soon after they are accessed.)
23
    Sequential = libc::MADV_SEQUENTIAL,
24
25
    /// **MADV_WILLNEED**
26
    ///
27
    /// Expect access in the near future.  (Hence, it might be a
28
    /// good idea to read some pages ahead.)
29
    WillNeed = libc::MADV_WILLNEED,
30
31
    /// **MADV_DONTFORK** - Linux only (since Linux 2.6.16)
32
    ///
33
    /// Do not make the pages in this range available to the child
34
    /// after a fork(2).  This is useful to prevent copy-on-write
35
    /// semantics from changing the physical location of a page if
36
    /// the parent writes to it after a fork(2).  (Such page
37
    /// relocations cause problems for hardware that DMAs into the
38
    /// page.)
39
    #[cfg(target_os = "linux")]
40
    DontFork = libc::MADV_DONTFORK,
41
42
    /// **MADV_DOFORK** - Linux only (since Linux 2.6.16)
43
    ///
44
    /// Undo the effect of MADV_DONTFORK, restoring the default
45
    /// behavior, whereby a mapping is inherited across fork(2).
46
    #[cfg(target_os = "linux")]
47
    DoFork = libc::MADV_DOFORK,
48
49
    /// **MADV_MERGEABLE** - Linux only (since Linux 2.6.32)
50
    ///
51
    /// Enable Kernel Samepage Merging (KSM) for the pages in the
52
    /// range specified by addr and length.  The kernel regularly
53
    /// scans those areas of user memory that have been marked as
54
    /// mergeable, looking for pages with identical content.
55
    /// These are replaced by a single write-protected page (which
56
    /// is automatically copied if a process later wants to update
57
    /// the content of the page).  KSM merges only private
58
    /// anonymous pages (see mmap(2)).
59
    ///
60
    /// The KSM feature is intended for applications that generate
61
    /// many instances of the same data (e.g., virtualization
62
    /// systems such as KVM).  It can consume a lot of processing
63
    /// power; use with care.  See the Linux kernel source file
64
    /// Documentation/admin-guide/mm/ksm.rst for more details.
65
    ///
66
    /// The MADV_MERGEABLE and MADV_UNMERGEABLE operations are
67
    /// available only if the kernel was configured with
68
    /// CONFIG_KSM.
69
    #[cfg(target_os = "linux")]
70
    Mergeable = libc::MADV_MERGEABLE,
71
72
    /// **MADV_UNMERGEABLE** - Linux only (since Linux 2.6.32)
73
    ///
74
    /// Undo the effect of an earlier MADV_MERGEABLE operation on
75
    /// the specified address range; KSM unmerges whatever pages
76
    /// it had merged in the address range specified by addr and
77
    /// length.
78
    #[cfg(target_os = "linux")]
79
    Unmergeable = libc::MADV_UNMERGEABLE,
80
81
    /// **MADV_HUGEPAGE** - Linux only (since Linux 2.6.38)
82
    ///
83
    /// Enable Transparent Huge Pages (THP) for pages in the range
84
    /// specified by addr and length.  Currently, Transparent Huge
85
    /// Pages work only with private anonymous pages (see
86
    /// mmap(2)).  The kernel will regularly scan the areas marked
87
    /// as huge page candidates to replace them with huge pages.
88
    /// The kernel will also allocate huge pages directly when the
89
    /// region is naturally aligned to the huge page size (see
90
    /// posix_memalign(2)).
91
    ///
92
    /// This feature is primarily aimed at applications that use
93
    /// large mappings of data and access large regions of that
94
    /// memory at a time (e.g., virtualization systems such as
95
    /// QEMU).  It can very easily waste memory (e.g., a 2 MB
96
    /// mapping that only ever accesses 1 byte will result in 2 MB
97
    /// of wired memory instead of one 4 KB page).  See the Linux
98
    /// kernel source file
99
    /// Documentation/admin-guide/mm/transhuge.rst for more
100
    /// details.
101
    ///
102
    /// Most common kernels configurations provide MADV_HUGEPAGE-
103
    /// style behavior by default, and thus MADV_HUGEPAGE is
104
    /// normally not necessary.  It is mostly intended for
105
    /// embedded systems, where MADV_HUGEPAGE-style behavior may
106
    /// not be enabled by default in the kernel.  On such systems,
107
    /// this flag can be used in order to selectively enable THP.
108
    /// Whenever MADV_HUGEPAGE is used, it should always be in
109
    /// regions of memory with an access pattern that the
110
    /// developer knows in advance won't risk to increase the
111
    /// memory footprint of the application when transparent
112
    /// hugepages are enabled.
113
    ///
114
    /// The MADV_HUGEPAGE and MADV_NOHUGEPAGE operations are
115
    /// available only if the kernel was configured with
116
    /// CONFIG_TRANSPARENT_HUGEPAGE.
117
    #[cfg(target_os = "linux")]
118
    HugePage = libc::MADV_HUGEPAGE,
119
120
    /// **MADV_NOHUGEPAGE** - Linux only (since Linux 2.6.38)
121
    ///
122
    /// Ensures that memory in the address range specified by addr
123
    /// and length will not be backed by transparent hugepages.
124
    #[cfg(target_os = "linux")]
125
    NoHugePage = libc::MADV_NOHUGEPAGE,
126
127
    /// **MADV_DONTDUMP** - Linux only (since Linux 3.4)
128
    ///
129
    /// Exclude from a core dump those pages in the range
130
    /// specified by addr and length.  This is useful in
131
    /// applications that have large areas of memory that are
132
    /// known not to be useful in a core dump.  The effect of
133
    /// **MADV_DONTDUMP** takes precedence over the bit mask that is
134
    /// set via the `/proc/[pid]/coredump_filter` file (see
135
    /// core(5)).
136
    #[cfg(target_os = "linux")]
137
    DontDump = libc::MADV_DONTDUMP,
138
139
    /// **MADV_DODUMP** - Linux only (since Linux 3.4)
140
    ///
141
    /// Undo the effect of an earlier MADV_DONTDUMP.
142
    #[cfg(target_os = "linux")]
143
    DoDump = libc::MADV_DODUMP,
144
145
    /// **MADV_HWPOISON** - Linux only (since Linux 2.6.32)
146
    ///
147
    /// Poison the pages in the range specified by addr and length
148
    /// and handle subsequent references to those pages like a
149
    /// hardware memory corruption.  This operation is available
150
    /// only for privileged (CAP_SYS_ADMIN) processes.  This
151
    /// operation may result in the calling process receiving a
152
    /// SIGBUS and the page being unmapped.
153
    ///
154
    /// This feature is intended for testing of memory error-
155
    /// handling code; it is available only if the kernel was
156
    /// configured with CONFIG_MEMORY_FAILURE.
157
    #[cfg(target_os = "linux")]
158
    HwPoison = libc::MADV_HWPOISON,
159
160
    /// **MADV_POPULATE_READ** - Linux only (since Linux 5.14)
161
    ///
162
    /// Populate  (prefault)  page  tables readable, faulting in all
163
    /// pages in the range just as  if  manually  reading  from  each
164
    /// page; however, avoid the actual memory access that would have
165
    /// been performed after handling the fault.
166
    ///
167
    /// In contrast to MAP_POPULATE, MADV_POPULATE_READ does not hide
168
    /// errors,  can  be  applied to (parts of) existing mappings and
169
    /// will always populate (prefault) page  tables  readable.   One
170
    /// example  use  case is prefaulting a file mapping, reading all
171
    /// file content from disk; however, pages won't be  dirtied  and
172
    /// consequently  won't  have  to  be  written  back to disk when
173
    /// evicting the pages from memory.
174
    ///
175
    /// Depending on the underlying mapping, map the shared zeropage,
176
    /// preallocate  memory  or  read the underlying file; files with
177
    /// holes might or might not preallocate blocks.   If  populating
178
    /// fails, a SIGBUS signal is not generated; instead, an error is
179
    /// returned.
180
    ///
181
    /// If MADV_POPULATE_READ succeeds, all  page  tables  have  been
182
    /// populated  (prefaulted) readable once.  If MADV_POPULATE_READ
183
    /// fails, some page tables might have been populated.
184
    ///
185
    /// MADV_POPULATE_READ cannot be applied to mappings without read
186
    /// permissions  and  special  mappings,  for  example,  mappings
187
    /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO,
188
    /// or secret memory regions created using memfd_secret(2).
189
    ///
190
    /// Note  that with MADV_POPULATE_READ, the process can be killed
191
    /// at any moment when the system runs out of memory.
192
    #[cfg(target_os = "linux")]
193
    PopulateRead = libc::MADV_POPULATE_READ,
194
195
    /// **MADV_POPULATE_WRITE** - Linux only (since Linux 5.14)
196
    ///
197
    /// Populate (prefault) page tables  writable,  faulting  in  all
198
    /// pages  in  the range just as if manually writing to each each
199
    /// page; however, avoid the actual memory access that would have
200
    /// been performed after handling the fault.
201
    ///
202
    /// In  contrast  to  MAP_POPULATE,  MADV_POPULATE_WRITE does not
203
    /// hide errors, can be applied to (parts of)  existing  mappings
204
    /// and  will  always  populate  (prefault) page tables writable.
205
    /// One example use case is preallocating  memory,  breaking  any
206
    /// CoW (Copy on Write).
207
    ///
208
    /// Depending  on  the  underlying mapping, preallocate memory or
209
    /// read the underlying file; files with holes  will  preallocate
210
    /// blocks.   If  populating fails, a SIGBUS signal is not gener‐
211
    /// ated; instead, an error is returned.
212
    ///
213
    /// If MADV_POPULATE_WRITE succeeds, all page  tables  have  been
214
    /// populated (prefaulted) writable once.  If MADV_POPULATE_WRITE
215
    /// fails, some page tables might have been populated.
216
    ///
217
    /// MADV_POPULATE_WRITE cannot be  applied  to  mappings  without
218
    /// write permissions and special mappings, for example, mappings
219
    /// marked with kernel-internal flags such as VM_PFNMAP or VM_IO,
220
    /// or secret memory regions created using memfd_secret(2).
221
    ///
222
    /// Note that with MADV_POPULATE_WRITE, the process can be killed
223
    /// at any moment when the system runs out of memory.
224
    #[cfg(target_os = "linux")]
225
    PopulateWrite = libc::MADV_POPULATE_WRITE,
226
227
    /// **MADV_ZERO_WIRED_PAGES** - Darwin only
228
    ///
229
    /// Indicates that the application would like the wired pages in this address range to be
230
    /// zeroed out if the address range is deallocated without first unwiring the pages (i.e.
231
    /// a munmap(2) without a preceding munlock(2) or the application quits).  This is used
232
    /// with `madvise()` system call.
233
    #[cfg(any(target_os = "macos", target_os = "ios"))]
234
    ZeroWiredPages = libc::MADV_ZERO_WIRED_PAGES,
235
}
236
237
/// Values supported by [`Mmap::unchecked_advise`][crate::Mmap::unchecked_advise] and [`MmapMut::unchecked_advise`][crate::MmapMut::unchecked_advise] functions.
238
///
239
/// These flags can be passed to the [madvise (2)][man_page] system call
240
/// and effects on the mapped pages which are conceptually writes,
241
/// i.e. the change the observable contents of these pages which
242
/// implies undefined behaviour if the mapping is still borrowed.
243
///
244
/// Hence, these potentially unsafe flags must be used with the unsafe
245
/// methods and the programmer has to justify that the code
246
/// does not keep any borrows of the mapping active while the mapped pages
247
/// are updated by the kernel's memory management subsystem.
248
///
249
/// [man_page]: https://man7.org/linux/man-pages/man2/madvise.2.html
250
#[repr(i32)]
251
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
252
pub enum UncheckedAdvice {
253
    /// **MADV_DONTNEED**
254
    ///
255
    /// Do not expect access in the near future.  (For the time
256
    /// being, the application is finished with the given range,
257
    /// so the kernel can free resources associated with it.)
258
    ///
259
    /// After a successful MADV_DONTNEED operation, the semantics
260
    /// of memory access in the specified region are changed:
261
    /// subsequent accesses of pages in the range will succeed,
262
    /// but will result in either repopulating the memory contents
263
    /// from the up-to-date contents of the underlying mapped file
264
    /// (for shared file mappings, shared anonymous mappings, and
265
    /// shmem-based techniques such as System V shared memory
266
    /// segments) or zero-fill-on-demand pages for anonymous
267
    /// private mappings.
268
    ///
269
    /// Note that, when applied to shared mappings, MADV_DONTNEED
270
    /// might not lead to immediate freeing of the pages in the
271
    /// range.  The kernel is free to delay freeing the pages
272
    /// until an appropriate moment.  The resident set size (RSS)
273
    /// of the calling process will be immediately reduced
274
    /// however.
275
    ///
276
    /// **MADV_DONTNEED** cannot be applied to locked pages, Huge TLB
277
    /// pages, or VM_PFNMAP pages.  (Pages marked with the kernel-
278
    /// internal VM_PFNMAP flag are special memory areas that are
279
    /// not managed by the virtual memory subsystem.  Such pages
280
    /// are typically created by device drivers that map the pages
281
    /// into user space.)
282
    ///
283
    /// # Safety
284
    ///
285
    /// Using the returned value with conceptually write to the
286
    /// mapped pages, i.e. borrowing the mapping when the pages
287
    /// are freed results in undefined behaviour.
288
    DontNeed = libc::MADV_DONTNEED,
289
290
    //
291
    // The rest are Linux-specific
292
    //
293
    /// **MADV_FREE** - Linux (since Linux 4.5) and Darwin
294
    ///
295
    /// The application no longer requires the pages in the range
296
    /// specified by addr and len.  The kernel can thus free these
297
    /// pages, but the freeing could be delayed until memory
298
    /// pressure occurs.  For each of the pages that has been
299
    /// marked to be freed but has not yet been freed, the free
300
    /// operation will be canceled if the caller writes into the
301
    /// page.  After a successful MADV_FREE operation, any stale
302
    /// data (i.e., dirty, unwritten pages) will be lost when the
303
    /// kernel frees the pages.  However, subsequent writes to
304
    /// pages in the range will succeed and then kernel cannot
305
    /// free those dirtied pages, so that the caller can always
306
    /// see just written data.  If there is no subsequent write,
307
    /// the kernel can free the pages at any time.  Once pages in
308
    /// the range have been freed, the caller will see zero-fill-
309
    /// on-demand pages upon subsequent page references.
310
    ///
311
    /// The MADV_FREE operation can be applied only to private
312
    /// anonymous pages (see mmap(2)).  In Linux before version
313
    /// 4.12, when freeing pages on a swapless system, the pages
314
    /// in the given range are freed instantly, regardless of
315
    /// memory pressure.
316
    ///
317
    /// # Safety
318
    ///
319
    /// Using the returned value with conceptually write to the
320
    /// mapped pages, i.e. borrowing the mapping while the pages
321
    /// are still being freed results in undefined behaviour.
322
    #[cfg(any(target_os = "linux", target_os = "macos", target_os = "ios"))]
323
    Free = libc::MADV_FREE,
324
325
    /// **MADV_REMOVE** - Linux only (since Linux 2.6.16)
326
    ///
327
    /// Free up a given range of pages and its associated backing
328
    /// store.  This is equivalent to punching a hole in the
329
    /// corresponding byte range of the backing store (see
330
    /// fallocate(2)).  Subsequent accesses in the specified
331
    /// address range will see bytes containing zero.
332
    ///
333
    /// The specified address range must be mapped shared and
334
    /// writable.  This flag cannot be applied to locked pages,
335
    /// Huge TLB pages, or VM_PFNMAP pages.
336
    ///
337
    /// In the initial implementation, only tmpfs(5) was supported
338
    /// **MADV_REMOVE**; but since Linux 3.5, any filesystem which
339
    /// supports the fallocate(2) FALLOC_FL_PUNCH_HOLE mode also
340
    /// supports MADV_REMOVE.  Hugetlbfs fails with the error
341
    /// EINVAL and other filesystems fail with the error
342
    /// EOPNOTSUPP.
343
    ///
344
    /// # Safety
345
    ///
346
    /// Using the returned value with conceptually write to the
347
    /// mapped pages, i.e. borrowing the mapping when the pages
348
    /// are freed results in undefined behaviour.
349
    #[cfg(target_os = "linux")]
350
    Remove = libc::MADV_REMOVE,
351
352
    /// **MADV_FREE_REUSABLE** - Darwin only
353
    ///
354
    /// Behaves like **MADV_FREE**, but the freed pages are accounted for in the RSS of the process.
355
    ///
356
    /// # Safety
357
    ///
358
    /// Using the returned value with conceptually write to the
359
    /// mapped pages, i.e. borrowing the mapping while the pages
360
    /// are still being freed results in undefined behaviour.
361
    #[cfg(any(target_os = "macos", target_os = "ios"))]
362
    FreeReusable = libc::MADV_FREE_REUSABLE,
363
364
    /// **MADV_FREE_REUSE** - Darwin only
365
    ///
366
    /// Marks a memory region previously freed by **MADV_FREE_REUSABLE** as non-reusable, accounts
367
    /// for the pages in the RSS of the process. Pages that have been freed will be replaced by
368
    /// zero-filled pages on demand, other pages will be left as is.
369
    ///
370
    /// # Safety
371
    ///
372
    /// Using the returned value with conceptually write to the
373
    /// mapped pages, i.e. borrowing the mapping while the pages
374
    /// are still being freed results in undefined behaviour.
375
    #[cfg(any(target_os = "macos", target_os = "ios"))]
376
    FreeReuse = libc::MADV_FREE_REUSE,
377
}
378
379
// Future expansion:
380
// MADV_SOFT_OFFLINE  (since Linux 2.6.33)
381
// MADV_WIPEONFORK  (since Linux 4.14)
382
// MADV_KEEPONFORK  (since Linux 4.14)
383
// MADV_COLD  (since Linux 5.4)
384
// MADV_PAGEOUT  (since Linux 5.4)
385
386
#[cfg(target_os = "linux")]
387
impl Advice {
388
    /// Performs a runtime check if this advice is supported by the kernel.
389
    /// Only supported on Linux. See the [`madvise(2)`] man page.
390
    ///
391
    /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html#VERSIONS
392
0
    pub fn is_supported(self) -> bool {
393
0
        (unsafe { libc::madvise(std::ptr::null_mut(), 0, self as libc::c_int) }) == 0
394
0
    }
395
}
396
397
#[cfg(target_os = "linux")]
398
impl UncheckedAdvice {
399
    /// Performs a runtime check if this advice is supported by the kernel.
400
    /// Only supported on Linux. See the [`madvise(2)`] man page.
401
    ///
402
    /// [`madvise(2)`]: https://man7.org/linux/man-pages/man2/madvise.2.html#VERSIONS
403
0
    pub fn is_supported(self) -> bool {
404
0
        (unsafe { libc::madvise(std::ptr::null_mut(), 0, self as libc::c_int) }) == 0
405
0
    }
406
}
407
408
#[cfg(test)]
409
mod tests {
410
    #[cfg(target_os = "linux")]
411
    #[test]
412
    fn test_is_supported() {
413
        use super::*;
414
415
        assert!(Advice::Normal.is_supported());
416
        assert!(Advice::Random.is_supported());
417
        assert!(Advice::Sequential.is_supported());
418
        assert!(Advice::WillNeed.is_supported());
419
420
        assert!(UncheckedAdvice::DontNeed.is_supported());
421
    }
422
}