1pub mod atomic_vec;
6pub use atomic_vec::AtomicBitVec;
7
8use memory_mapped_vmo::MemoryMappedVmo;
9use std::sync::atomic::{AtomicU64, Ordering};
10use zx::Rights;
11
12pub struct PageRefaultCounter {
13 vmo: zx::Vmo,
14 _storage: MemoryMappedVmo,
15 count_ptr: *const AtomicU64,
16}
17
18unsafe impl Send for PageRefaultCounter {}
23unsafe impl Sync for PageRefaultCounter {}
24
25impl PageRefaultCounter {
26 pub fn new() -> Result<Self, zx::Status> {
28 let vmo = zx::Vmo::create(size_of::<AtomicU64>().try_into().unwrap())?;
29 vmo.set_name(&zx::Name::new_lossy("page_refault_counter"))?;
30
31 let mut storage: MemoryMappedVmo = unsafe { MemoryMappedVmo::new_readwrite(&vmo)? };
33 let count_ptr: *mut AtomicU64 =
34 storage.get_object_mut::<AtomicU64>(0).map_err(|_| zx::Status::INVALID_ARGS)?;
35 Ok(PageRefaultCounter { vmo: vmo, _storage: storage, count_ptr })
36 }
37
38 pub fn from_vmo_readonly(vmo: zx::Vmo) -> Result<Self, zx::Status> {
41 if vmo.get_size()? < size_of::<AtomicU64>().try_into().unwrap() {
42 return Err(zx::Status::INVALID_ARGS);
43 }
44 let storage: MemoryMappedVmo = unsafe { MemoryMappedVmo::new_readonly(&vmo)? };
46 let count_ptr: *const AtomicU64 =
47 storage.get_object::<AtomicU64>(0).map_err(|_| zx::Status::INVALID_ARGS)?;
48 Ok(PageRefaultCounter { vmo: vmo, _storage: storage, count_ptr })
49 }
50
51 pub fn increment(&self, count: u64, order: Ordering) {
52 unsafe { &*self.count_ptr }.fetch_add(count, order);
55 }
56
57 pub fn read(&self, order: Ordering) -> u64 {
58 unsafe { &*self.count_ptr }.load(order)
61 }
62
63 pub fn readonly_vmo(&self) -> Result<zx::Vmo, zx::Status> {
65 self.vmo.duplicate_handle(Rights::BASIC | Rights::READ | Rights::MAP | Rights::GET_PROPERTY)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_page_refault_counter() {
75 let counter = PageRefaultCounter::new().unwrap();
76
77 let ro_vmo = counter.readonly_vmo().unwrap();
78 let ro_counter = PageRefaultCounter::from_vmo_readonly(ro_vmo).unwrap();
79
80 counter.increment(100, Ordering::SeqCst);
81 assert_eq!(ro_counter.read(Ordering::SeqCst), 100);
82
83 counter.increment(100, Ordering::SeqCst);
84 assert_eq!(ro_counter.read(Ordering::SeqCst), 200);
85 }
86}