hcl/
mapped_page.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use std::cell::UnsafeCell;
5use std::fs::File;
6use std::io;
7use std::os::fd::AsRawFd;
8use std::ptr::NonNull;
9
10pub(crate) struct MappedPage<T>(NonNull<UnsafeCell<T>>);
11
12impl<T> MappedPage<T> {
13    pub fn new(fd: &File, pg_off: i64) -> io::Result<Self> {
14        // Make sure any T we're using can fit in any size page.
15        assert!(size_of::<T>() <= 4096);
16
17        // SAFETY: calling mmap as documented to create a new mapping.
18        let ptr = unsafe {
19            let page_size = libc::sysconf(libc::_SC_PAGESIZE);
20            libc::mmap(
21                std::ptr::null_mut(),
22                page_size as usize,
23                libc::PROT_READ | libc::PROT_WRITE,
24                libc::MAP_SHARED,
25                fd.as_raw_fd(),
26                pg_off * page_size,
27            )
28        };
29        if ptr == libc::MAP_FAILED {
30            return Err(io::Error::last_os_error());
31        }
32
33        Ok(Self(NonNull::new(ptr).unwrap().cast()))
34    }
35
36    pub fn as_ptr(&self) -> *mut T {
37        UnsafeCell::raw_get(self.0.as_ptr())
38    }
39
40    pub fn as_ref(&self) -> &UnsafeCell<T> {
41        // SAFETY: The pointer is valid and mapped for the lifetime of the struct,
42        // it will only every point to a T, and UnsafeCell allows interior mutability.
43        unsafe { self.0.as_ref() }
44    }
45}
46
47impl<T> std::fmt::Debug for MappedPage<T> {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        f.debug_tuple("MappedPage").field(&self.0).finish()
50    }
51}
52
53impl<T> Drop for MappedPage<T> {
54    fn drop(&mut self) {
55        // SAFETY: unmapping memory mapped at construction.
56        unsafe {
57            libc::munmap(
58                self.0.as_ptr().cast(),
59                libc::sysconf(libc::_SC_PAGESIZE) as usize,
60            );
61        }
62    }
63}
64
65// SAFETY: this is just a pointer value.
66unsafe impl<T> Send for MappedPage<T> {}
67// SAFETY: see above comment
68unsafe impl<T> Sync for MappedPage<T> {}