1use crate::{BlockSize, BlockSizeSpec, GenericBlockSize, MaskShiftSpec};
6use std::sync::atomic::{AtomicU64, Ordering};
7
8static PAGE_MASK_SHIFT: AtomicU64 = AtomicU64::new(0);
10
11#[cold]
13#[inline(never)]
14fn initialize_page_mask_shift() -> u64 {
15 let page_size = zx::system_get_page_size();
16 let repr = MaskShiftSpec::new(page_size as u64).0;
17 PAGE_MASK_SHIFT.store(repr, Ordering::Relaxed);
18 repr
19}
20
21#[inline(always)]
24fn page_mask_shift() -> u64 {
25 let val = PAGE_MASK_SHIFT.load(Ordering::Relaxed);
26 if val != 0 { val } else { initialize_page_mask_shift() }
27}
28
29#[derive(Copy, Clone, Debug, Eq, PartialEq)]
31pub struct PageSizeSpec;
32
33impl BlockSizeSpec for PageSizeSpec {
34 #[inline(always)]
35 fn size(self) -> u64 {
36 self.mask() + 1
37 }
38
39 #[inline(always)]
40 fn mask(self) -> u64 {
41 page_mask_shift() >> 32
42 }
43
44 #[inline(always)]
45 fn shift(self) -> u32 {
46 page_mask_shift() as u32
47 }
48}
49
50pub const PAGE_SIZE: GenericBlockSize<PageSizeSpec> = GenericBlockSize(PageSizeSpec);
52
53impl From<GenericBlockSize<PageSizeSpec>> for BlockSize {
54 #[inline(always)]
55 fn from(_value: GenericBlockSize<PageSizeSpec>) -> Self {
56 GenericBlockSize(MaskShiftSpec(page_mask_shift()))
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63
64 #[fuchsia::test]
65 fn test_page_size() {
66 let expected = zx::system_get_page_size() as u64;
67 assert_eq!(PAGE_SIZE.get(), expected);
68 assert_eq!(PAGE_SIZE.mask(), expected - 1);
69 assert_eq!(PAGE_SIZE.shift(), (expected - 1).trailing_ones());
70 assert_eq!(BlockSize::from(PAGE_SIZE).get(), expected);
71 assert_eq!(BlockSize::from(PAGE_SIZE).mask(), expected - 1);
72 assert_eq!(BlockSize::from(PAGE_SIZE).shift(), (expected - 1).trailing_ones());
73 assert!(PAGE_SIZE.is_aligned(expected));
74 assert!(!PAGE_SIZE.is_aligned(expected - 1));
75 }
76}