#![allow(non_snake_case)]
#![allow(dead_code)]
use crate::ported::generic::gettime::{Generic_gettime_monotonic, Generic_gettime_realtime};
use crate::ported::panel::Panel;
use crate::ported::row::{Row_resetFieldWidths, Row_setPidColumnWidth, Row_setUidColumnWidth};
use crate::ported::table::{
Table, Table_scanCleanup, Table_scanIterate, Table_scanPrepare, Table_setPanel,
};
#[cfg(target_os = "macos")]
use crate::ported::darwin::platform::Platform_getMaxPid;
#[cfg(target_os = "dragonfly")]
use crate::ported::dragonflybsd::platform::Platform_getMaxPid;
#[cfg(target_os = "freebsd")]
use crate::ported::freebsd::platform::Platform_getMaxPid;
#[cfg(target_os = "linux")]
use crate::ported::linux::platform::Platform_getMaxPid;
#[cfg(target_os = "netbsd")]
use crate::ported::netbsd::platform::Platform_getMaxPid;
#[cfg(target_os = "openbsd")]
use crate::ported::openbsd::platform::Platform_getMaxPid;
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
use crate::ported::solaris::platform::Platform_getMaxPid;
#[cfg(not(any(
target_os = "macos",
target_os = "linux",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "solaris",
target_os = "illumos",
target_os = "dragonfly"
)))]
use crate::ported::unsupported::platform::Platform_getMaxPid;
pub type TableHandle = *mut Table;
pub use crate::ported::settings::{ScreenSettings, Settings};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct Machine {
pub settings: Option<Settings>,
pub realtimeMs: u64,
pub monotonicMs: u64,
pub prevMonotonicMs: u64,
pub iterationsRemaining: i64,
pub totalMem: u64,
pub totalSwap: u64,
pub usedSwap: u64,
pub cachedSwap: u64,
pub activeCPUs: u32,
pub existingCPUs: u32,
pub usersTable: Option<usize>,
pub htopUserId: u32,
pub maxUserId: u32,
pub userId: u32,
pub maxProcessId: i32,
pub tableCount: usize,
pub tables: Vec<TableHandle>,
pub activeTable: Option<TableHandle>,
pub processTable: Option<TableHandle>,
}
pub fn Machine_init(this: &mut Machine, usersTable: Option<usize>, userId: u32) {
this.usersTable = usersTable;
this.userId = userId;
this.htopUserId = unsafe { libc::getuid() };
Row_setPidColumnWidth(Platform_getMaxPid());
let mut realtime: libc::timeval = unsafe { core::mem::zeroed() };
Generic_gettime_realtime(&mut realtime, &mut this.realtimeMs);
}
pub fn Machine_done(this: &mut Machine) {
#[cfg(target_os = "macos")]
if let Some(pt) = this.processTable.take() {
drop(unsafe {
Box::from_raw(pt as *mut crate::ported::darwin::darwinprocesstable::DarwinProcessTable)
});
}
#[cfg(not(target_os = "macos"))]
let _ = this.processTable.take();
this.tables.clear();
}
fn Machine_addTable(this: &mut Machine, table: TableHandle) {
for i in 0..this.tableCount {
if this.tables[i] == table {
return;
}
}
this.tables.push(table);
this.tableCount += 1;
}
pub fn Machine_populateTablesFromSettings(
this: &mut Machine,
settings: Settings,
processTable: TableHandle,
) {
this.settings = Some(settings);
this.processTable = Some(processTable);
let nScreens = this.settings.as_ref().unwrap().screens.len();
for i in 0..nScreens {
if this.settings.as_ref().unwrap().screens[i].table.is_none() {
this.settings.as_mut().unwrap().screens[i].table = Some(processTable);
}
let table = this.settings.as_ref().unwrap().screens[i].table.unwrap();
if i == 0 {
this.activeTable = Some(table);
}
Machine_addTable(this, table);
}
}
pub fn Machine_setTablesPanel(this: &mut Machine, panel: *mut Panel) {
for i in 0..this.tableCount {
unsafe {
Table_setPanel(&mut *this.tables[i], panel);
}
}
}
pub fn Machine_scanTables(this: &mut Machine) {
use std::sync::atomic::{AtomicBool, Ordering};
static FIRST_SCAN_DONE: AtomicBool = AtomicBool::new(false);
if FIRST_SCAN_DONE.load(Ordering::Relaxed) {
this.prevMonotonicMs = this.monotonicMs;
Generic_gettime_monotonic(&mut this.monotonicMs);
} else {
this.prevMonotonicMs = 0;
this.monotonicMs = 1;
FIRST_SCAN_DONE.store(true, Ordering::Relaxed);
}
if this.monotonicMs <= this.prevMonotonicMs {
return;
}
this.maxUserId = 0;
Row_resetFieldWidths();
for i in 0..this.tableCount {
let table = this.tables[i];
Table_scanPrepare(table);
Table_scanIterate(table);
Table_scanCleanup(table);
}
Row_setUidColumnWidth(this.maxUserId);
Row_setPidColumnWidth(this.maxProcessId);
}
#[cfg(test)]
mod tests {
use super::*;
const T10: TableHandle = 10 as TableHandle;
const T20: TableHandle = 20 as TableHandle;
const T30: TableHandle = 30 as TableHandle;
const T42: TableHandle = 42 as TableHandle;
#[test]
fn addTable_dedup_keeps_first_occurrence_and_ignores_repeats() {
let mut m = Machine::default();
Machine_addTable(&mut m, T10);
Machine_addTable(&mut m, T20);
Machine_addTable(&mut m, T10);
Machine_addTable(&mut m, T20);
Machine_addTable(&mut m, T30);
assert_eq!(m.tables, vec![T10, T20, T30]);
assert_eq!(m.tableCount, 3);
assert_eq!(m.tableCount, m.tables.len());
}
#[test]
fn addTable_first_insert_grows_from_empty() {
let mut m = Machine::default();
assert_eq!(m.tableCount, 0);
assert!(m.tables.is_empty());
Machine_addTable(&mut m, T42);
assert_eq!(m.tables, vec![T42]);
assert_eq!(m.tableCount, 1);
}
fn settings_with_screens(n: usize) -> Settings {
Settings {
screens: vec![ScreenSettings::default(); n],
..Default::default()
}
}
#[test]
fn populate_defaults_null_tables_to_processTable() {
let mut m = Machine::default();
let pt: TableHandle = 7 as TableHandle;
Machine_populateTablesFromSettings(&mut m, settings_with_screens(2), pt);
let s = m.settings.as_ref().unwrap();
assert_eq!(s.screens[0].table, Some(pt));
assert_eq!(s.screens[1].table, Some(pt));
assert_eq!(m.processTable, Some(pt));
assert_eq!(m.activeTable, Some(pt)); assert_eq!(m.tables, vec![pt]); assert_eq!(m.tableCount, 1);
}
#[test]
fn populate_first_screen_becomes_active_and_explicit_tables_are_kept() {
let explicit: TableHandle = 100 as TableHandle;
let pt: TableHandle = 9 as TableHandle;
let settings = Settings {
screens: vec![
ScreenSettings {
table: Some(explicit),
treeView: false,
..Default::default()
},
ScreenSettings::default(),
ScreenSettings {
table: Some(explicit),
treeView: false,
..Default::default()
},
],
..Default::default()
};
let mut m = Machine::default();
Machine_populateTablesFromSettings(&mut m, settings, pt);
let s = m.settings.as_ref().unwrap();
assert_eq!(s.screens[0].table, Some(explicit)); assert_eq!(s.screens[1].table, Some(pt)); assert_eq!(s.screens[2].table, Some(explicit));
assert_eq!(m.activeTable, Some(explicit)); assert_eq!(m.tables, vec![explicit, pt]); assert_eq!(m.tableCount, 2);
}
#[test]
fn populate_with_no_screens_registers_nothing() {
let mut m = Machine::default();
let pt: TableHandle = 5 as TableHandle;
Machine_populateTablesFromSettings(&mut m, settings_with_screens(0), pt);
assert_eq!(m.processTable, Some(pt));
assert_eq!(m.activeTable, None); assert!(m.tables.is_empty());
assert_eq!(m.tableCount, 0);
}
#[test]
fn setTablesPanel_points_every_table_at_the_panel() {
use crate::ported::panel::Panel;
let mut t0 = Box::new(Table::empty());
let mut t1 = Box::new(Table::empty());
let panel = 0xABCD as *mut Panel;
let mut m = Machine::default();
Machine_addTable(&mut m, &mut *t0 as *mut Table);
Machine_addTable(&mut m, &mut *t1 as *mut Table);
Machine_setTablesPanel(&mut m, panel);
assert_eq!(t0.panel, panel);
assert_eq!(t1.panel, panel);
}
}