diff --git a/Cargo.toml b/Cargo.toml index 774551a..1914b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ serde = { version = "1.0", optional = true, features = ["derive"] } [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.9", features = ["minwindef", "processthreadsapi", "psapi"] } -[target.'cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios"))'.dependencies] +[target.'cfg(any(target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios", target_os = "freebsd"))'.dependencies] libc = "0.2" [features] diff --git a/src/freebsd.rs b/src/freebsd.rs new file mode 100644 index 0000000..902d6d3 --- /dev/null +++ b/src/freebsd.rs @@ -0,0 +1,44 @@ +use std::ffi::c_void; +use std::sync::atomic::Ordering; + +use crate::MemoryStats; + +#[path = "page_size.rs"] +mod page_size; + +#[link(name = "util")] +extern "C" { + fn kinfo_getproc(pid: libc::pid_t) -> *mut libc::kinfo_proc; +} + +pub fn memory_stats() -> Option { + struct FreeLater { + p: *mut T, + } + + impl Drop for FreeLater { + fn drop(&mut self) { + if !self.p.is_null() { + unsafe { libc::free(self.p as *mut c_void) }; + } + } + } + + page_size::load_page_size()?; + + let info_ptr = FreeLater { + p: unsafe { kinfo_getproc(libc::getpid()) }, + }; + + if info_ptr.p.is_null() { + None + } else { + // SAFETY: ptr is not null + let info = unsafe { info_ptr.p.read() }; + let page_size = page_size::PAGE_SIZE.load(Ordering::Relaxed); + Some(MemoryStats { + physical_mem: (info.ki_rssize as usize) * page_size, + virtual_mem: info.ki_size, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index fdedb42..cd3598e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,12 +58,17 @@ mod platform; #[path = "darwin.rs"] mod platform; +#[cfg(target_os = "freebsd")] +#[path = "freebsd.rs"] +mod platform; + #[cfg(not(any( target_os = "windows", target_os = "linux", target_os = "android", target_os = "macos", target_os = "ios", + target_os = "freebsd", )))] mod platform { use crate::MemoryStats; diff --git a/src/linux.rs b/src/linux.rs index 25578c4..2bb5590 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1,8 +1,11 @@ use std::fs; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, Ordering}; use crate::MemoryStats; +#[path = "page_size.rs"] +mod page_size; + #[cfg(not(feature = "always_use_statm"))] const SMAPS: &str = "/proc/self/smaps"; const STATM: &str = "/proc/self/statm"; @@ -11,7 +14,6 @@ const STATM: &str = "/proc/self/statm"; static SMAPS_CHECKED: AtomicBool = AtomicBool::new(false); #[cfg(not(feature = "always_use_statm"))] static SMAPS_EXIST: AtomicBool = AtomicBool::new(false); -static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); pub fn memory_stats() -> Option { // If possible, we try to use /proc/self/smaps to retrieve @@ -20,14 +22,14 @@ pub fn memory_stats() -> Option { // as a fallback in case smaps isn't avaliable. #[cfg(feature = "always_use_statm")] - load_page_size()?; + page_size::load_page_size()?; #[cfg(not(feature = "always_use_statm"))] if let Ok(false) = SMAPS_CHECKED.compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) { let smaps_exist = fs::metadata(SMAPS).is_ok(); if !smaps_exist { - load_page_size()?; + page_size::load_page_size()?; } // store SMAPS_EXIST last to prevent code from loading a PAGE_SIZE of 0 @@ -71,7 +73,7 @@ pub fn memory_stats() -> Option { // multiples of the page size, as the first // two columns of output. - let page_size = PAGE_SIZE.load(Ordering::Relaxed); + let page_size = page_size::PAGE_SIZE.load(Ordering::Relaxed); let (total_size_pages, idx) = scan_int(&statm_info); let (total_rss_pages, _) = scan_int(&statm_info[idx..]); Some(MemoryStats { @@ -83,20 +85,6 @@ pub fn memory_stats() -> Option { } } -/// Grabs the value of the SC_PAGESIZE if needed. -fn load_page_size() -> Option<()> { - if PAGE_SIZE.load(Ordering::Relaxed) == 0 { - let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; - if page_size == -1 { - // sysconf returned error - return None; - } else { - PAGE_SIZE.store(page_size as usize, Ordering::Relaxed); - } - } - Some(()) -} - /// Extracts a positive integer from a string that /// may contain leading spaces and trailing chars. /// Returns the extracted number and the index of diff --git a/src/page_size.rs b/src/page_size.rs new file mode 100644 index 0000000..d595238 --- /dev/null +++ b/src/page_size.rs @@ -0,0 +1,17 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub static PAGE_SIZE: AtomicUsize = AtomicUsize::new(0); + +/// Grabs the value of the SC_PAGESIZE if needed. +pub fn load_page_size() -> Option<()> { + if PAGE_SIZE.load(Ordering::Relaxed) == 0 { + let page_size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) }; + if page_size == -1 { + // sysconf returned error + return None; + } else { + PAGE_SIZE.store(page_size as usize, Ordering::Relaxed); + } + } + Some(()) +}