page_size/
lib.rs

1#![no_std]
2//! This crate provides an easy, fast, cross-platform way to retrieve the
3//! memory page size of the current system.
4//!
5//! Modern hardware and software tend to load data into RAM (and transfer data
6//! from RAM to disk) in discrete chunk called pages. This crate provides a
7//! helper method to retrieve the size in bytes of these pages. Since the page
8//! size *should not* change during execution, this crate will cache the result
9//! after it has been called once.
10//!
11//! To make this crate useful for writing memory allocators, it does not require
12//! (but can use) the Rust standard library.
13//!
14//! Since Windows addresses sometimes have to correspond with an allocation
15//! granularity that does not always match the size of the page, I have included
16//! a method to retrieve that as well.
17//!
18//! # Example
19//!
20//! ```rust
21//! extern crate page_size;
22//! println!("{}", page_size::get());
23//! ```
24
25#[cfg(feature = "no_std")]
26extern crate spin;
27#[cfg(feature = "no_std")]
28use spin::Once;
29
30#[cfg(not(feature = "no_std"))]
31extern crate std;
32#[cfg(not(feature = "no_std"))]
33use std::sync::Once;
34
35#[cfg(unix)]
36extern crate libc;
37
38#[cfg(windows)]
39extern crate winapi;
40
41/// This function retrieves the system's memory page size.
42///
43/// # Example
44///
45/// ```rust
46/// extern crate page_size;
47/// println!("{}", page_size::get());
48/// ```
49pub fn get() -> usize {
50    get_helper()
51}
52
53/// This function retrieves the system's memory allocation granularity.
54///
55/// # Example
56///
57/// ```rust
58/// extern crate page_size;
59/// println!("{}", page_size::get_granularity());
60/// ```
61pub fn get_granularity() -> usize {
62    get_granularity_helper()
63}
64
65// Unix Section
66
67#[cfg(all(unix, feature = "no_std"))]
68#[inline]
69fn get_helper() -> usize {
70    static INIT: Once<usize> = Once::new();
71
72    *INIT.call_once(unix::get)
73}
74
75#[cfg(all(unix, not(feature = "no_std")))]
76#[inline]
77fn get_helper() -> usize {
78    static INIT: Once = Once::new();
79    static mut PAGE_SIZE: usize = 0;
80
81    unsafe {
82        INIT.call_once(|| PAGE_SIZE = unix::get());
83        PAGE_SIZE
84    }
85}
86
87// Unix does not have a specific allocation granularity.
88// The page size works well.
89#[cfg(unix)]
90#[inline]
91fn get_granularity_helper() -> usize {
92    get_helper()
93}
94
95#[cfg(unix)]
96mod unix {
97    use libc::{sysconf, _SC_PAGESIZE};
98
99    #[inline]
100    pub fn get() -> usize {
101        unsafe { sysconf(_SC_PAGESIZE) as usize }
102    }
103}
104
105// WebAssembly section
106
107// WebAssembly does not have a specific allocation granularity.
108// The page size works well.
109#[cfg(all(not(target_os = "emscripten"), any(target_arch = "wasm32", target_arch = "wasm64")))]
110#[inline]
111fn get_granularity_helper() -> usize {
112    // <https://webassembly.github.io/spec/core/exec/runtime.html#page-size>
113    65536
114}
115
116// Windows Section
117
118#[cfg(all(windows, feature = "no_std"))]
119#[inline]
120fn get_helper() -> usize {
121    static INIT: Once<usize> = Once::new();
122
123    *INIT.call_once(windows::get)
124}
125
126#[cfg(all(windows, not(feature = "no_std")))]
127#[inline]
128fn get_helper() -> usize {
129    static INIT: Once = Once::new();
130    static mut PAGE_SIZE: usize = 0;
131
132    unsafe {
133        INIT.call_once(|| PAGE_SIZE = windows::get());
134        PAGE_SIZE
135    }
136}
137
138#[cfg(all(windows, feature = "no_std"))]
139#[inline]
140fn get_granularity_helper() -> usize {
141    static GRINIT: Once<usize> = Once::new();
142
143    *GRINIT.call_once(windows::get_granularity)
144}
145
146#[cfg(all(windows, not(feature = "no_std")))]
147#[inline]
148fn get_granularity_helper() -> usize {
149    static GRINIT: Once = Once::new();
150    static mut GRANULARITY: usize = 0;
151
152    unsafe {
153        GRINIT.call_once(|| GRANULARITY = windows::get_granularity());
154        GRANULARITY
155    }
156}
157
158#[cfg(windows)]
159mod windows {
160    #[cfg(feature = "no_std")]
161    use core::mem;
162    #[cfg(not(feature = "no_std"))]
163    use std::mem;
164
165    use winapi::um::sysinfoapi::GetSystemInfo;
166    use winapi::um::sysinfoapi::{LPSYSTEM_INFO, SYSTEM_INFO};
167
168    #[inline]
169    pub fn get() -> usize {
170        unsafe {
171            let mut info: SYSTEM_INFO = mem::zeroed();
172            GetSystemInfo(&mut info as LPSYSTEM_INFO);
173
174            info.dwPageSize as usize
175        }
176    }
177
178    #[inline]
179    pub fn get_granularity() -> usize {
180        unsafe {
181            let mut info: SYSTEM_INFO = mem::zeroed();
182            GetSystemInfo(&mut info as LPSYSTEM_INFO);
183
184            info.dwAllocationGranularity as usize
185        }
186    }
187}
188
189// Stub Section
190
191#[cfg(not(any(unix, windows)))]
192#[inline]
193fn get_helper() -> usize {
194    4096 // 4k is the default on many systems
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200
201    #[test]
202    fn test_get() {
203        #[allow(unused_variables)]
204        let page_size = get();
205    }
206
207    #[test]
208    fn test_get_granularity() {
209        #[allow(unused_variables)]
210        let granularity = get_granularity();
211    }
212}