#![allow(non_camel_case_types)]
use std::ffi::CStr;
use std::mem;
use std::ptr;
use std::slice;
use mach::kern_return::{self, kern_return_t};
use mach::mach_port;
use mach::mach_types::host_t;
use mach::message::mach_msg_type_number_t;
use mach::traps::mach_task_self;
use mach::vm_types::{integer_t, natural_t, vm_address_t, vm_map_t, vm_size_t};
use heim_common::prelude::*;
use heim_common::sys::macos;
const PROCESSOR_CPU_LOAD_INFO: libc::c_int = 2;
const HOST_CPU_LOAD_INFO: libc::c_int = 3;
const HOST_VM_INFO: libc::c_int = 2;
const CPU_STATE_USER: usize = 0;
const CPU_STATE_SYSTEM: usize = 1;
const CPU_STATE_IDLE: usize = 2;
const CPU_STATE_NICE: usize = 3;
type processor_flavor_t = libc::c_int;
type processor_info_array_t = *mut integer_t;
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
pub struct host_cpu_load_info {
pub user: natural_t,
pub system: natural_t,
pub idle: natural_t,
pub nice: natural_t,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
pub struct processor_cpu_load_info {
pub user: natural_t,
pub system: natural_t,
pub idle: natural_t,
pub nice: natural_t,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, PartialOrd, PartialEq, Eq, Ord)]
pub struct vmmeter {
pub v_swtch: libc::c_uint,
pub v_trap: libc::c_uint,
pub v_syscall: libc::c_uint,
pub v_intr: libc::c_uint,
pub v_soft: libc::c_uint,
pub v_faults: libc::c_uint,
pub v_lookups: libc::c_uint,
pub v_hits: libc::c_uint,
pub v_vm_faults: libc::c_uint,
pub v_cow_faults: libc::c_uint,
pub v_swpin: libc::c_uint,
pub v_swpout: libc::c_uint,
pub v_pswpin: libc::c_uint,
pub v_pswpout: libc::c_uint,
pub v_pageins: libc::c_uint,
pub v_pageouts: libc::c_uint,
pub v_pgpgin: libc::c_uint,
pub v_pgpgout: libc::c_uint,
pub v_intrans: libc::c_uint,
pub v_reactivated: libc::c_uint,
pub v_rev: libc::c_uint,
pub v_scan: libc::c_uint,
pub v_dfree: libc::c_uint,
pub v_pfree: libc::c_uint,
pub v_zfod: libc::c_uint,
pub v_nzfod: libc::c_uint,
pub v_page_size: libc::c_uint,
pub v_kernel_pages: libc::c_uint,
pub v_free_target: libc::c_uint,
pub v_free_min: libc::c_uint,
pub v_free_count: libc::c_uint,
pub v_wire_count: libc::c_uint,
pub v_active_count: libc::c_uint,
pub v_inactive_target: libc::c_uint,
pub v_inactive_count: libc::c_uint,
}
extern "C" {
fn host_processor_info(
host: host_t,
flavor: processor_flavor_t,
out_processor_count: *mut natural_t,
out_processor_info: *mut processor_info_array_t,
out_processor_infoCnt: *mut mach_msg_type_number_t,
) -> kern_return_t;
fn vm_deallocate(
target_task: vm_map_t,
address: vm_address_t,
size: vm_size_t,
) -> kern_return_t;
}
#[allow(trivial_casts)]
pub unsafe fn cpu_load_info() -> Result<host_cpu_load_info> {
let port = macos::mach_host_self();
let mut stats = host_cpu_load_info::default();
let count = mem::size_of::<host_cpu_load_info>() / mem::size_of::<integer_t>();
let result = macos::host_statistics64(
port,
HOST_CPU_LOAD_INFO,
&mut stats as *mut _ as macos::host_info64_t,
&count as *const _ as *const mach_msg_type_number_t,
);
let port_result = mach_port::mach_port_deallocate(mach_task_self(), port);
if port_result != kern_return::KERN_SUCCESS {
return Err(Error::last_os_error());
}
if result != kern_return::KERN_SUCCESS {
Err(Error::last_os_error())
} else {
Ok(stats)
}
}
#[allow(trivial_casts)]
pub unsafe fn processor_load_info() -> Result<Vec<processor_cpu_load_info>> {
let port = macos::mach_host_self();
let mut cpu_count = 0;
let mut processor_info: processor_info_array_t = ptr::null_mut();
let mut cpu_info_count = 0;
let result = host_processor_info(
port,
PROCESSOR_CPU_LOAD_INFO,
&mut cpu_count,
&mut processor_info,
&mut cpu_info_count,
);
let port_result = mach_port::mach_port_deallocate(mach_task_self(), port);
if port_result != kern_return::KERN_SUCCESS {
return Err(Error::last_os_error());
}
if result != kern_return::KERN_SUCCESS {
Err(Error::last_os_error())
} else {
let cpu_info = slice::from_raw_parts(processor_info, cpu_info_count as usize);
let mut stats = Vec::with_capacity(cpu_count as usize);
for chunk in cpu_info.chunks(4) {
stats.push(processor_cpu_load_info {
user: chunk[CPU_STATE_USER] as natural_t,
system: chunk[CPU_STATE_SYSTEM] as natural_t,
idle: chunk[CPU_STATE_IDLE] as natural_t,
nice: chunk[CPU_STATE_NICE] as natural_t,
})
}
let result = vm_deallocate(
mach_task_self(),
processor_info as vm_address_t,
cpu_info_count as vm_size_t * std::mem::size_of::<natural_t>(),
);
if result != kern_return::KERN_SUCCESS {
return Err(Error::last_os_error());
}
Ok(stats)
}
}
#[allow(trivial_casts)]
pub unsafe fn vm_meter() -> Result<vmmeter> {
let port = macos::mach_host_self();
let mut stats = vmmeter::default();
let count = mem::size_of::<vmmeter>() / mem::size_of::<integer_t>();
let result = macos::host_statistics(
port,
HOST_VM_INFO,
&mut stats as *mut _ as macos::host_info_t,
&count as *const _ as *const mach_msg_type_number_t,
);
let port_result = mach_port::mach_port_deallocate(mach_task_self(), port);
if port_result != kern_return::KERN_SUCCESS {
return Err(Error::last_os_error());
}
if result != kern_return::KERN_SUCCESS {
Err(Error::last_os_error())
} else {
Ok(stats)
}
}
#[allow(trivial_casts)]
unsafe fn frequency(key: &[u8]) -> Result<u64> {
let str = CStr::from_bytes_with_nul_unchecked(key);
let mut value = 0u64;
let mut length = mem::size_of::<u64>();
let result = libc::sysctlbyname(
str.as_ptr(),
&mut value as *mut _ as *mut libc::c_void,
&mut length,
ptr::null_mut(),
0,
);
if result == 0 {
Ok(value)
} else {
Err(Error::last_os_error())
}
}
pub fn cpu_frequency() -> Result<u64> {
unsafe { frequency(b"hw.cpufrequency\0") }
}
pub fn cpu_frequency_max() -> Result<u64> {
unsafe { frequency(b"hw.cpufrequency_max\0") }
}
pub fn cpu_frequency_min() -> Result<u64> {
unsafe { frequency(b"hw.cpufrequency_min\0") }
}