1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
use std::io::{self, Result};
use std::ptr;
use libc::{close, munmap, PROT_READ};
use crate::shmem_sys;
pub(crate) struct ShmemReader {
ptr: *const u8,
size: usize,
fd: i32,
name: String,
}
// SAFETY: the only non-auto field is `ptr`, a raw pointer into a read-only
// mmap'd shared-memory region whose address is fixed for the handle's lifetime.
// Sharing the read-only handle across threads is sound.
unsafe impl Send for ShmemReader {}
unsafe impl Sync for ShmemReader {}
impl ShmemReader {
/// Opens and maps a shared memory region for read-only access.
pub fn new(name: &str, size: usize) -> Result<Self> {
// Open existing shared memory (read-only)
let fd = shmem_sys::open(name, libc::O_RDONLY)?;
// Map the memory region for read-only (always locked)
let ptr = shmem_sys::map(fd, size, PROT_READ, true, name)?;
let ptr_u8 = ptr as *const u8;
Ok(Self { ptr: ptr_u8, size, fd, name: name.to_string() })
}
unsafe fn unmap(&mut self) {
if munmap(self.ptr as *mut _, self.size) != 0 {
tracing::error!("munmap failed: {:?}", io::Error::last_os_error());
} else {
self.ptr = ptr::null();
self.size = 0;
tracing::trace!("Unmapped shared memory '{}'", self.name);
}
}
/// Reads a u64 from shared memory at a specific offset (in bytes)
///
/// # Arguments
/// * `offset` - Byte offset from the start of shared memory (must be 8-byte aligned)
///
/// # Safety
/// This method assumes that:
/// - The shared memory contains at least `offset + 8` bytes of valid data
/// - The offset should be aligned to 8 bytes
///
/// # Returns
/// * The u64 value read from the specified offset (in native endianness)
#[inline]
pub fn read_u64_at(&self, offset: usize) -> u64 {
debug_assert_eq!(offset % 8, 0, "Offset must be 8-byte aligned");
unsafe { (self.ptr.add(offset) as *const u64).read() }
}
}
impl Drop for ShmemReader {
fn drop(&mut self) {
unsafe {
self.unmap();
close(self.fd);
}
}
}