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)]
23pub fn page_size() -> PageSize {
24 let val = PAGE_MASK_SHIFT.load(Ordering::Relaxed);
25 let val = if val != 0 { val } else { initialize_page_mask_shift() };
26 GenericBlockSize(PageSizeSpec(MaskShiftSpec(val)))
27}
28
29pub type PageSize = GenericBlockSize<PageSizeSpec>;
31
32#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34pub struct PageSizeSpec(MaskShiftSpec);
35
36impl BlockSizeSpec for PageSizeSpec {
37 #[inline(always)]
38 fn size(self) -> u64 {
39 self.0.size()
40 }
41
42 #[inline(always)]
43 fn mask(self) -> u64 {
44 self.0.mask()
45 }
46
47 #[inline(always)]
48 fn shift(self) -> u32 {
49 self.0.shift()
50 }
51}
52
53impl From<PageSize> for BlockSize {
54 #[inline(always)]
55 fn from(page_size: PageSize) -> Self {
56 GenericBlockSize(page_size.0.0)
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 let page_size = page_size();
68 assert_eq!(page_size.get(), expected);
69 assert_eq!(page_size.mask(), expected - 1);
70 assert_eq!(page_size.shift(), (expected - 1).trailing_ones());
71 assert!(page_size.is_aligned(expected));
72 assert!(!page_size.is_aligned(expected - 1));
73 }
74
75 #[fuchsia::test]
76 fn test_page_size_to_block_size() {
77 let page_size = page_size();
78 let block_size: BlockSize = page_size.into();
79 assert_eq!(page_size.get(), block_size.get());
80 assert_eq!(page_size.mask(), block_size.mask());
81 assert_eq!(page_size.shift(), block_size.shift());
82 }
83}