use crate::{shmem_control_input_name, ShmemWriter};
use anyhow::Result;
pub struct ControlShmem {
writer: ShmemWriter,
}
#[derive(Copy, Clone)]
enum ControlShmemOffsets {
PrecompilesSize = 0,
ShutdownFlag = 8,
InputsSize = 16,
ResetFlag = 24,
}
impl ControlShmem {
pub const CONTROL_WRITER_SIZE: u64 = 0x1000;
pub fn new(shm_prefix: &str, unlock_mapped_memory: bool) -> Result<Self> {
let name = shmem_control_input_name(shm_prefix);
let writer =
ShmemWriter::new(&name, Self::CONTROL_WRITER_SIZE as usize, unlock_mapped_memory)
.map_err(anyhow::Error::from)?;
Ok(Self { writer })
}
pub fn reset(&self) -> Result<()> {
self.writer.write_u64_at(ControlShmemOffsets::PrecompilesSize as usize, 0)?;
self.writer.write_u64_at(ControlShmemOffsets::ShutdownFlag as usize, 0)?;
self.writer.write_u64_at(ControlShmemOffsets::InputsSize as usize, 0)?;
self.writer.write_u64_at(ControlShmemOffsets::ResetFlag as usize, 0)?;
Ok(())
}
pub fn set_prec_hints_size(&self, size: u64) -> Result<()> {
self.writer.write_u64_at(ControlShmemOffsets::PrecompilesSize as usize, size)?;
Ok(())
}
pub fn prec_hints_size(&self) -> u64 {
self.writer.read_u64_at(ControlShmemOffsets::PrecompilesSize as usize)
}
pub fn set_reset_flag(&self) -> Result<()> {
self.writer.write_u64_at(ControlShmemOffsets::ResetFlag as usize, 1)?;
Ok(())
}
pub fn inc_inputs_size(&self, size: usize) -> Result<()> {
let current_size = self.writer.read_u64_at(ControlShmemOffsets::InputsSize as usize);
let new_size = current_size + size as u64;
self.writer.write_u64_at(ControlShmemOffsets::InputsSize as usize, new_size)?;
Ok(())
}
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[cfg(test)]
mod tests {
use super::*;
use crate::{shmem_control_input_name, ShmemReader};
use std::ffi::CString;
fn create_segment(name: &str, size: usize) {
let c = CString::new(name).unwrap();
unsafe {
libc::shm_unlink(c.as_ptr());
let fd = libc::shm_open(c.as_ptr(), libc::O_CREAT | libc::O_RDWR, 0o600);
assert!(fd >= 0);
assert_eq!(libc::ftruncate(fd, size as libc::off_t), 0);
libc::close(fd);
}
}
fn unlink_segment(name: &str) {
let c = CString::new(name).unwrap();
unsafe { libc::shm_unlink(c.as_ptr()) };
}
#[test]
fn control_fields_round_trip_at_their_offsets() {
let prefix = format!("ZISK_unittest_ctrl_{}", std::process::id());
let seg = shmem_control_input_name(&prefix);
let size = ControlShmem::CONTROL_WRITER_SIZE as usize;
create_segment(&seg, size);
let c = ControlShmem::new(&prefix, true).unwrap();
let r = ShmemReader::new(&seg, size).unwrap();
c.set_prec_hints_size(99).unwrap();
assert_eq!(c.prec_hints_size(), 99);
assert_eq!(r.read_u64_at(0), 99);
c.inc_inputs_size(10).unwrap();
c.inc_inputs_size(5).unwrap();
assert_eq!(r.read_u64_at(16), 15);
c.set_reset_flag().unwrap();
assert_eq!(r.read_u64_at(24), 1);
c.reset().unwrap();
assert_eq!(c.prec_hints_size(), 0);
assert_eq!(r.read_u64_at(16), 0);
assert_eq!(r.read_u64_at(24), 0);
drop(r);
unlink_segment(&seg);
}
}