memguar/wrappers/
advisor.rs

1use std::convert::AsMut;
2use std::marker::PhantomData;
3
4use libc::{c_int, c_void, posix_madvise};
5
6use crate::wrappers::advisor::Advise::DontNeed;
7
8/// A wrapper-struct `Adviser` that is used to advise the system
9/// about the expected behavior of memory access patterns of the buffer's page.
10/// # Examples
11///
12/// ```
13/// use memguar::advisor::Advise::DontNeed;
14/// use memguar::advisor::Adviser;
15///
16/// let buf = [420; 16_000]; 
17/// let mut advised_buf = Adviser::new(buf);
18///
19/// advised_buf
20///     .syscall_advise(DontNeed)
21///     .unwrap();
22/// ```
23#[repr(transparent)]
24pub struct Adviser<C: AsMut<[T]>, T> {
25    pub buf: C,
26    item_type: PhantomData<T>,
27}
28
29impl<C: AsMut<[T]>, T> Adviser<C, T> {
30    pub fn new(buf: C) -> Self {
31        Self {
32            buf,
33            item_type: PhantomData,
34        }
35    }
36
37    /// If `syscall_advise` is successful, it allows the system to apply specific optimizations to the page,
38    /// based on the specified flag, such as moving it to the swap file
39    /// or merging it with adjacent pages.
40    pub fn syscall_advise(&mut self, advise: Advise) -> Result<(), AdviseError> {
41        let buf = self.buf.as_mut();
42        assert!(size_of_val(buf) > 0, "Zero size buffer");
43        let ptr = buf.as_mut_ptr() as *mut c_void;
44        let len = size_of_val(buf);
45        let result = unsafe {
46            posix_madvise(ptr, len, advise as c_int)
47        };
48
49        match result {
50            0 => Ok(()),
51            result => Err(AdviseError::from(result)),
52        }
53    }
54}
55
56impl<C: AsMut<[T]>, T> Drop for Adviser<C, T> {
57    fn drop(&mut self) {
58        self.syscall_advise(DontNeed)
59            .expect("Cant give advise while dropping")
60    }
61}
62/// Advises for page
63#[repr(i32)]
64pub enum Advise {
65    WillNeed = 3,
66    DontNeed = 4,
67}
68/// Parsed types of `syscall_advise` errors
69#[derive(Debug)]
70pub enum AdviseError {
71    EFAULT,
72    EINVAL,
73    ENOMEM,
74    ENOSYS,
75    EUNIM(c_int),
76}
77
78impl From<c_int> for AdviseError {
79    fn from(err: c_int) -> Self {
80        match err {
81            12 => AdviseError::ENOMEM,
82            14 => AdviseError::EFAULT,
83            22 => AdviseError::EINVAL,
84            38 => AdviseError::ENOSYS,
85            _ => AdviseError::EUNIM(err),
86        }
87    }
88}