Rust实战内存缺页检测

更多虚拟内存的详情点击https://blog.csdn.net/zhizhengguan/article/details/117568026 查看, 本次实验仅仅作为入门demo

在使用mmap申请一段匿名内存, 或者malloc函数申请的内存, 在没有访问该内存的情况下, 这段内存并不会映射到物理地址中,

so, 我们可以通过mincore函数不断地检测这段内存是否存在物理内存中, 来确定这段内存是否被其他的进程读取

mincore报告在一个虚拟地址范围中哪些分页当前驻留在RAM中,因此在访问这些分页时也不会导致分页故障

int mincore(void *addr, size_t length, unsigned char *vec);

mincore返回起始地址为addr长度为length字节的虚拟地址访问中分页的内存驻留信息。addr 中的地址必须是分页对齐的,并且由于返回的信息是有关整个分页的,因此length 实际上会被向上舍入到系统分页大小的下一个整数倍。

内存驻留相关的信息会通过 vec 返回,它是一个数组,其大小为(length + PAGE_SIZE – 1) / PAGE_SIZE 字节。每个字节的最低有效位在相应分页驻留在内存中时会被设置,而其他位的设置在一些 UNIX 实现上是未定义的,因此可移植的应用程序应该只测试最低有效位。

use std::ffi::c_void;
use std::fs::OpenOptions;
use std::num::NonZeroUsize;
use std::os::fd::AsRawFd;
use nix::sys::mman::{MapFlags, mmap, ProtFlags};
use std::thread;
use std::sync::{Mutex, Arc};
fn main() {

    // 一个文件
    let mem_size = 4096;
    let f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("./test.mmap")
        .unwrap();

    f.set_len(mem_size).unwrap();

    // 映射共享内存
    let p1;
    unsafe {
        let c = mmap(None, NonZeroUsize::new(mem_size as usize).unwrap(), ProtFlags::PROT_READ | ProtFlags::PROT_WRITE, MapFlags::MAP_PRIVATE, f.as_raw_fd(), 0);
        match c {
            Ok(p) => {
                p1 = p;
            }
            Err(e) => {
                panic!("{:?}", e.desc())
            }
        };
    }
    println!("已经映射地址为: {:?}", p1);  // 这个内存映射文件的内容我之前修改的内容为 4i32

    // 转换为安全类型
    let safe_p1 = Arc::new(Mutex::new(unsafe { (p1 as *mut _ as *mut i32).as_ref().unwrap() }));
    let safe_p2 = safe_p1.clone();

    thread::spawn(move || {
        // 5秒后读取共享内存的数据
        thread::sleep(std::time::Duration::from_secs(5));
        let p1_ref = *safe_p1.lock().unwrap();
        println!("线程1: 内存的内容读取到为: {:?}", *p1_ref);
    });

    thread::spawn(move || unsafe {
        loop {
            // 每秒检测是否被映射到物理内存
            thread::sleep(std::time::Duration::from_secs(1));
            let p2_ref = *safe_p2.lock().unwrap();
            let p2_ptr = p2_ref as *const i32 as *const c_void;

            let mut buffer = [0; 128];
            if libc::mincore(p2_ptr, mem_size as usize, buffer.as_mut_ptr()) == -1 {
                println!("错误: {:?}", nix::errno::errno());
            } else {
                let c_str = unsafe {std::ffi::CStr::from_ptr(buffer.as_mut_ptr())};
                println!("线程2: 内存当前状态 {:?}", c_str);
            }
        }
    });

    unsafe {
        libc::pause();
    };
}