diff options
Diffstat (limited to 'vendor/sysinfo/src/apple/macos/system.rs')
-rw-r--r-- | vendor/sysinfo/src/apple/macos/system.rs | 139 |
1 files changed, 84 insertions, 55 deletions
diff --git a/vendor/sysinfo/src/apple/macos/system.rs b/vendor/sysinfo/src/apple/macos/system.rs index 949532234..7c8b957a5 100644 --- a/vendor/sysinfo/src/apple/macos/system.rs +++ b/vendor/sysinfo/src/apple/macos/system.rs @@ -1,5 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. +use crate::SystemExt; + #[allow(deprecated)] use libc::{mach_timebase_info, mach_timebase_info_data_t}; @@ -9,18 +11,52 @@ use libc::{ }; use std::ptr::null_mut; -unsafe fn free_cpu_load_info(cpu_load: &mut processor_cpu_load_info_t) { - if !cpu_load.is_null() { - munmap(*cpu_load as _, vm_page_size); - *cpu_load = null_mut(); +struct ProcessorCpuLoadInfo { + cpu_load: processor_cpu_load_info_t, + cpu_count: natural_t, +} + +impl ProcessorCpuLoadInfo { + fn new(port: mach_port_t) -> Option<Self> { + let mut info_size = std::mem::size_of::<processor_cpu_load_info_t>() as _; + let mut cpu_count = 0; + let mut cpu_load: processor_cpu_load_info_t = null_mut(); + + unsafe { + if host_processor_info( + port, + PROCESSOR_CPU_LOAD_INFO, + &mut cpu_count, + &mut cpu_load as *mut _ as *mut _, + &mut info_size, + ) != 0 + { + sysinfo_debug!("host_processor_info failed, not updating CPU ticks usage..."); + None + } else if cpu_count < 1 || cpu_load.is_null() { + None + } else { + Some(Self { + cpu_load, + cpu_count, + }) + } + } + } +} + +impl Drop for ProcessorCpuLoadInfo { + fn drop(&mut self) { + unsafe { + munmap(self.cpu_load as _, vm_page_size); + } } } pub(crate) struct SystemTimeInfo { timebase_to_ns: f64, clock_per_sec: f64, - old_cpu_load: processor_cpu_load_info_t, - old_cpu_count: natural_t, + old_cpu_info: ProcessorCpuLoadInfo, } unsafe impl Send for SystemTimeInfo {} @@ -49,9 +85,8 @@ impl SystemTimeInfo { info.denom = 1; } - let mut old_cpu_load = null_mut(); - let old_cpu_count = match Self::update_ticks(port, &mut old_cpu_load) { - Some(c) => c, + let old_cpu_info = match ProcessorCpuLoadInfo::new(port) { + Some(cpu_info) => cpu_info, None => { sysinfo_debug!("host_processor_info failed, using old CPU tick measure system"); return None; @@ -63,53 +98,23 @@ impl SystemTimeInfo { Some(Self { timebase_to_ns: info.numer as f64 / info.denom as f64, clock_per_sec: nano_per_seconds / clock_ticks_per_sec as f64, - old_cpu_load, - old_cpu_count, + old_cpu_info, }) } } - fn update_ticks( - port: mach_port_t, - cpu_load: &mut processor_cpu_load_info_t, - ) -> Option<natural_t> { - let mut info_size = std::mem::size_of::<processor_cpu_load_info_t>() as _; - let mut cpu_count = 0; - - unsafe { - free_cpu_load_info(cpu_load); - - if host_processor_info( - port, - PROCESSOR_CPU_LOAD_INFO, - &mut cpu_count, - cpu_load as *mut _ as *mut _, - &mut info_size, - ) != 0 - { - sysinfo_debug!("host_processor_info failed, not updating CPU ticks usage..."); - None - } else if cpu_count < 1 || cpu_load.is_null() { - None - } else { - Some(cpu_count) - } - } - } - pub fn get_time_interval(&mut self, port: mach_port_t) -> f64 { let mut total = 0; - let mut new_cpu_load = null_mut(); - - let new_cpu_count = match Self::update_ticks(port, &mut new_cpu_load) { - Some(c) => c, + let new_cpu_info = match ProcessorCpuLoadInfo::new(port) { + Some(cpu_info) => cpu_info, None => return 0., }; - let cpu_count = std::cmp::min(self.old_cpu_count, new_cpu_count); + let cpu_count = std::cmp::min(self.old_cpu_info.cpu_count, new_cpu_info.cpu_count); unsafe { for i in 0..cpu_count { - let new_load: &processor_cpu_load_info = &*new_cpu_load.offset(i as _); - let old_load: &processor_cpu_load_info = &*self.old_cpu_load.offset(i as _); + let new_load: &processor_cpu_load_info = &*new_cpu_info.cpu_load.offset(i as _); + let old_load: &processor_cpu_load_info = + &*self.old_cpu_info.cpu_load.offset(i as _); for (new, old) in new_load.cpu_ticks.iter().zip(old_load.cpu_ticks.iter()) { if new > old { total += new - old; @@ -117,20 +122,44 @@ impl SystemTimeInfo { } } - free_cpu_load_info(&mut self.old_cpu_load); - self.old_cpu_load = new_cpu_load; - self.old_cpu_count = new_cpu_count; + self.old_cpu_info = new_cpu_info; - // Now we convert the ticks to nanoseconds: - total as f64 / self.timebase_to_ns * self.clock_per_sec / cpu_count as f64 + // Now we convert the ticks to nanoseconds (if the interval is less than + // `MINIMUM_CPU_UPDATE_INTERVAL`, we replace it with it instead): + let base_interval = total as f64 / cpu_count as f64 * self.clock_per_sec; + let smallest = + crate::System::MINIMUM_CPU_UPDATE_INTERVAL.as_secs_f64() * 1_000_000_000.0; + if base_interval < smallest { + smallest + } else { + base_interval / self.timebase_to_ns + } } } } -impl Drop for SystemTimeInfo { - fn drop(&mut self) { - unsafe { - free_cpu_load_info(&mut self.old_cpu_load); +#[cfg(test)] +mod test { + + use super::*; + + /// Regression test for <https://github.com/GuillaumeGomez/sysinfo/issues/956>. + #[test] + fn test_getting_time_interval() { + if !crate::System::IS_SUPPORTED || cfg!(feature = "apple-sandbox") { + return; } + + let port = unsafe { libc::mach_host_self() }; + let mut info = SystemTimeInfo::new(port).unwrap(); + info.get_time_interval(port); + + std::thread::sleep(crate::System::MINIMUM_CPU_UPDATE_INTERVAL.saturating_mul(5)); + + let val = info.get_time_interval(port); + assert_ne!( + val, + crate::System::MINIMUM_CPU_UPDATE_INTERVAL.as_secs_f64() * 1_000_000_000.0 + ); } } |