#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
#![allow(deprecated)]
use std::mem::size_of;
use std::os::raw::{c_int, c_void};
use std::ptr;
use crate::ported::crt::CRT_fatalError;
use crate::ported::linux::linuxmachine::ZfsArcStats;
use crate::ported::machine::{Machine, Machine_init};
const HOST_BASIC_INFO: c_int = 1;
extern "C" {
fn host_info(
host: libc::host_t,
flavor: c_int,
host_info_out: libc::host_info_t,
host_info_outCnt: *mut libc::mach_msg_type_number_t,
) -> libc::kern_return_t;
}
#[repr(C)]
#[derive(Clone, Copy, Default)]
pub struct host_basic_info_data_t {
pub max_cpus: i32,
pub avail_cpus: i32,
pub memory_size: u32,
pub cpu_type: i32,
pub cpu_subtype: i32,
pub cpu_threadtype: i32,
pub physical_cpu: i32,
pub physical_cpu_max: i32,
pub logical_cpu: i32,
pub logical_cpu_max: i32,
pub max_mem: u64,
}
#[repr(C)]
pub struct DarwinMachine {
pub super_: Machine,
pub host_info: host_basic_info_data_t,
pub vm_stats: libc::vm_statistics64,
pub prev_load: libc::processor_cpu_load_info_t,
pub curr_load: libc::processor_cpu_load_info_t,
pub GPUService: libc::mach_port_t,
pub zfs: ZfsArcStats,
}
pub fn DarwinMachine_getHostInfo(p: &mut host_basic_info_data_t) {
let mut info_size =
(size_of::<host_basic_info_data_t>() / size_of::<c_int>()) as libc::mach_msg_type_number_t;
let rc = unsafe {
host_info(
libc::mach_host_self(),
HOST_BASIC_INFO,
p as *mut host_basic_info_data_t as libc::host_info_t,
&mut info_size,
)
};
if rc != 0 {
CRT_fatalError("Unable to retrieve host info");
}
}
pub fn DarwinMachine_freeCPULoadInfo(p: &mut libc::processor_cpu_load_info_t) {
if p.is_null() {
return;
}
if unsafe { libc::munmap(*p as *mut c_void, libc::vm_page_size) } != 0 {
CRT_fatalError("Unable to free old CPU load information");
}
*p = ptr::null_mut();
}
pub fn DarwinMachine_allocateCPULoadInfo(p: &mut libc::processor_cpu_load_info_t) -> u32 {
let mut info_size =
size_of::<libc::processor_cpu_load_info_t>() as libc::mach_msg_type_number_t;
let mut cpu_count: libc::natural_t = 0;
let rc = unsafe {
libc::host_processor_info(
libc::mach_host_self(),
libc::PROCESSOR_CPU_LOAD_INFO,
&mut cpu_count,
p as *mut libc::processor_cpu_load_info_t as *mut libc::processor_info_array_t,
&mut info_size,
)
};
if rc != 0 {
CRT_fatalError("Unable to retrieve CPU info");
}
cpu_count
}
pub fn DarwinMachine_getVMStats(this: &mut DarwinMachine) {
let mut info_size = libc::HOST_VM_INFO64_COUNT;
let rc = unsafe {
libc::host_statistics64(
libc::mach_host_self(),
libc::HOST_VM_INFO64,
&mut this.vm_stats as *mut libc::vm_statistics64 as *mut c_int,
&mut info_size,
)
};
if rc != 0 {
CRT_fatalError("Unable to retrieve VM statistics64");
}
}
pub fn Machine_scan(host: &mut DarwinMachine) {
DarwinMachine_freeCPULoadInfo(&mut host.prev_load);
host.prev_load = host.curr_load;
DarwinMachine_allocateCPULoadInfo(&mut host.curr_load);
DarwinMachine_getVMStats(host);
}
pub fn Machine_new(usersTable: Option<usize>, userId: u32) -> Box<DarwinMachine> {
let mut this = Box::new(DarwinMachine {
super_: Machine::default(),
host_info: host_basic_info_data_t::default(),
vm_stats: unsafe { std::mem::zeroed() },
prev_load: ptr::null_mut(),
curr_load: ptr::null_mut(),
GPUService: 0,
zfs: ZfsArcStats::default(),
});
Machine_init(&mut this.super_, usersTable, userId);
this.super_.activeCPUs = DarwinMachine_allocateCPULoadInfo(&mut this.prev_load);
this.super_.existingCPUs = this.super_.activeCPUs;
DarwinMachine_getHostInfo(&mut this.host_info);
DarwinMachine_allocateCPULoadInfo(&mut this.curr_load);
DarwinMachine_getVMStats(&mut this);
this
}
pub fn Machine_delete() {
todo!("port of DarwinMachine.c:121")
}
pub fn Machine_isCPUonline(host: &Machine, id: u32) -> bool {
debug_assert!(id < host.existingCPUs);
true
}
pub fn Machine_getCPUPhysicalCoreID(host: &Machine, id: u32) -> i32 {
debug_assert!(id < host.existingCPUs);
id as i32
}
pub fn Machine_getCPUThreadIndex(host: &Machine, id: u32) -> i32 {
debug_assert!(id < host.existingCPUs);
0
}
#[cfg(test)]
mod tests {
use super::*;
fn darwin_machine() -> Box<DarwinMachine> {
Box::new(DarwinMachine {
super_: Machine::default(),
host_info: host_basic_info_data_t::default(),
vm_stats: unsafe { std::mem::zeroed() },
prev_load: ptr::null_mut(),
curr_load: ptr::null_mut(),
GPUService: 0,
zfs: ZfsArcStats::default(),
})
}
#[test]
fn getHostInfo_reports_physical_memory_and_cpus() {
let mut hi = host_basic_info_data_t::default();
DarwinMachine_getHostInfo(&mut hi);
assert!(hi.max_mem > 0);
assert!(hi.max_cpus > 0);
}
#[test]
fn machine_scan_allocates_cpu_load_and_fills_vm() {
let mut dm = darwin_machine();
Machine_scan(&mut dm);
assert!(!dm.curr_load.is_null());
assert!(dm.vm_stats.free_count > 0 || dm.vm_stats.active_count > 0);
DarwinMachine_freeCPULoadInfo(&mut dm.curr_load);
assert!(dm.curr_load.is_null());
}
#[test]
fn machine_new_builds_a_populated_host() {
let mut m = Machine_new(None, 0);
assert!(m.super_.activeCPUs > 0);
assert_eq!(m.super_.existingCPUs, m.super_.activeCPUs);
assert!(m.host_info.max_mem > 0);
assert!(!m.prev_load.is_null());
assert!(!m.curr_load.is_null());
assert_eq!(m.super_.htopUserId, unsafe { libc::getuid() });
assert!(m.super_.realtimeMs > 0);
assert_eq!(m.GPUService, 0);
DarwinMachine_freeCPULoadInfo(&mut m.prev_load);
DarwinMachine_freeCPULoadInfo(&mut m.curr_load);
}
}