#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use core::any::Any;
use core::ffi::c_void;
use core::ops::Deref;
use std::sync::atomic::Ordering;
use crate::ported::crt::{ColorElements as CE, ColorScheme};
use crate::ported::machine::Machine;
use crate::ported::object::{Object, ObjectClass};
use crate::ported::process::{
spaceship_nullstr, Process, ProcessClass, ProcessField, ProcessFieldData, Process_class,
Process_compare, Process_compareByKey_Base, Process_compareByParent, Process_getPid,
Process_init, Process_isKernelThread, Process_rowGetSortKey, Process_rowIsHighlighted,
Process_rowIsVisible, Process_writeField, PROCESS_FLAG_CWD,
};
use crate::ported::richstring::{RichString, RichString_appendWide};
use crate::ported::row::{
spaceship_number, Row, RowClass, Row_display, Row_pidDigits, Row_printLeftAlignedField,
};
use crate::ported::settings::RowField;
pub const JID: RowField = 100;
pub const JAIL: RowField = 101;
pub const LAST_PROCESSFIELD: usize = 127;
const EMPTY_FIELD: ProcessFieldData = ProcessFieldData {
name: "",
title: None,
description: None,
flags: 0,
pidColumn: false,
defaultSortDesc: false,
autoWidth: false,
autoTitleRightAlign: false,
};
const fn pfd(
name: &'static str,
title: &'static str,
description: &'static str,
flags: u32,
pidColumn: bool,
defaultSortDesc: bool,
autoWidth: bool,
autoTitleRightAlign: bool,
) -> ProcessFieldData {
ProcessFieldData {
name,
title: Some(title),
description: Some(description),
flags,
pidColumn,
defaultSortDesc,
autoWidth,
autoTitleRightAlign,
}
}
pub static Process_fields: [ProcessFieldData; LAST_PROCESSFIELD] = build_process_fields();
const fn build_process_fields() -> [ProcessFieldData; LAST_PROCESSFIELD] {
use ProcessField as PF;
let mut t = [EMPTY_FIELD; LAST_PROCESSFIELD];
t[PF::PID as usize] = pfd(
"PID",
"PID",
"Process/thread ID",
0,
true,
false,
false,
false,
);
t[PF::COMM as usize] = pfd(
"Command",
"Command ",
"Command line (insert as last column only)",
0,
false,
false,
false,
false,
);
t[PF::STATE as usize] = pfd("STATE", "S ", "Process state (S sleeping (<20s), I Idle, Q Queued for Run, R running, D disk, Z zombie, T traced, W paging, B Blocked, A AskedPage, C Core, J Jailed)", 0, false, false, false, false);
t[PF::PPID as usize] = pfd(
"PPID",
"PPID",
"Parent process ID",
0,
true,
false,
false,
false,
);
t[PF::PGRP as usize] = pfd(
"PGRP",
"PGRP",
"Process group ID",
0,
true,
false,
false,
false,
);
t[PF::SESSION as usize] = pfd(
"SESSION",
"SID",
"Process's session ID",
0,
true,
false,
false,
false,
);
t[PF::TTY as usize] = pfd(
"TTY",
"TTY ",
"Controlling terminal",
0,
false,
false,
false,
false,
);
t[PF::TPGID as usize] = pfd(
"TPGID",
"TPGID",
"Process ID of the fg process group of the controlling terminal",
0,
true,
false,
false,
false,
);
t[PF::MINFLT as usize] = pfd(
"MINFLT",
" MINFLT ",
"Number of minor faults which have not required loading a memory page from disk",
0,
false,
true,
false,
false,
);
t[PF::MAJFLT as usize] = pfd(
"MAJFLT",
" MAJFLT ",
"Number of major faults which have required loading a memory page from disk",
0,
false,
true,
false,
false,
);
t[PF::PRIORITY as usize] = pfd(
"PRIORITY",
"PRI ",
"Kernel's internal priority for the process",
0,
false,
false,
false,
false,
);
t[PF::NICE as usize] = pfd(
"NICE",
" NI ",
"Nice value (the higher the value, the more it lets other processes take priority)",
0,
false,
false,
false,
false,
);
t[PF::STARTTIME as usize] = pfd(
"STARTTIME",
"START ",
"Time the process was started",
0,
false,
false,
false,
false,
);
t[PF::ELAPSED as usize] = pfd(
"ELAPSED",
"ELAPSED ",
"Time since the process was started",
0,
false,
false,
false,
false,
);
t[PF::PROCESSOR as usize] = pfd(
"PROCESSOR",
"CPU ",
"Id of the CPU the process last executed on",
0,
false,
false,
false,
false,
);
t[PF::M_VIRT as usize] = pfd(
"M_VIRT",
" VIRT ",
"Total program size in virtual memory",
0,
false,
true,
false,
false,
);
t[PF::M_RESIDENT as usize] = pfd(
"M_RESIDENT",
" RES ",
"Resident set size, size of the text and data sections, plus stack usage",
0,
false,
true,
false,
false,
);
t[PF::ST_UID as usize] = pfd(
"ST_UID",
"UID",
"User ID of the process owner",
0,
false,
false,
false,
false,
);
t[PF::PERCENT_CPU as usize] = pfd(
"PERCENT_CPU",
" CPU%",
"Percentage of the CPU time the process used in the last sampling",
0,
false,
true,
true,
true,
);
t[PF::PERCENT_NORM_CPU as usize] = pfd("PERCENT_NORM_CPU", "NCPU%", "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", 0, false, true, true, false);
t[PF::PERCENT_MEM as usize] = pfd(
"PERCENT_MEM",
"MEM% ",
"Percentage of the memory the process is using, based on resident memory size",
0,
false,
true,
false,
false,
);
t[PF::USER as usize] = pfd(
"USER",
"USER ",
"Username of the process owner (or user ID if name cannot be determined)",
0,
false,
false,
false,
false,
);
t[PF::TIME as usize] = pfd(
"TIME",
" TIME+ ",
"Total time the process has spent in user and system time",
0,
false,
true,
false,
false,
);
t[PF::NLWP as usize] = pfd(
"NLWP",
"NLWP ",
"Number of threads in the process",
0,
false,
false,
false,
false,
);
t[PF::TGID as usize] = pfd(
"TGID",
"TGID",
"Thread group ID (i.e. process ID)",
0,
true,
false,
false,
false,
);
t[PF::PROC_COMM as usize] = pfd(
"COMM",
"COMM ",
"comm string of the process",
0,
false,
false,
false,
false,
);
t[PF::PROC_EXE as usize] = pfd(
"EXE",
"EXE ",
"Basename of exe of the process",
0,
false,
false,
false,
false,
);
t[PF::CWD as usize] = pfd(
"CWD",
"CWD ",
"The current working directory of the process",
PROCESS_FLAG_CWD,
false,
false,
false,
false,
);
t[JID as usize] = pfd("JID", "JID", "Jail prison ID", 0, true, false, false, false);
t[JAIL as usize] = pfd(
"JAIL",
"JAIL ",
"Jail prison name",
0,
false,
false,
false,
false,
);
t
}
#[derive(Debug, Clone, Default)]
pub struct DragonFlyBSDProcess {
pub super_: Process,
pub jid: i32,
pub jname: Option<String>,
}
pub fn DragonFlyBSDProcess_new(host: *const Machine) -> DragonFlyBSDProcess {
let mut this = DragonFlyBSDProcess::default();
Process_init(&mut this.super_, host as *const c_void);
this
}
pub fn DragonFlyBSDProcess_rowWriteField(
super_: &dyn Object,
str: &mut RichString,
field: RowField,
) {
let fp = (super_ as &dyn Any)
.downcast_ref::<DragonFlyBSDProcess>()
.expect("DragonFlyBSDProcess_rowWriteField: row is not a DragonFlyBSDProcess");
let this = &fp.super_;
let scheme = ColorScheme::active();
let attr = CE::DEFAULT_COLOR.packed(scheme);
let buffer: String;
match field {
f if f == ProcessField::PID as RowField => {
let w = Row_pidDigits.load(Ordering::Relaxed) as usize;
let pid = if Process_isKernelThread(this) {
-1
} else {
Process_getPid(this)
};
buffer = format!("{pid:>w$} ");
}
f if f == JID => {
let w = Row_pidDigits.load(Ordering::Relaxed) as usize;
buffer = format!("{:>w$} ", fp.jid);
}
f if f == JAIL => {
let content: &[u8] = fp.jname.as_deref().map(str::as_bytes).unwrap_or(b"");
Row_printLeftAlignedField(str, attr, content, 11);
return;
}
_ => {
Process_writeField(this, str, field);
return;
}
}
RichString_appendWide(str, attr, buffer.as_bytes());
}
pub fn DragonFlyBSDProcess_compareByKey(v1: &dyn Object, v2: &dyn Object, key: RowField) -> i32 {
let p1 = (v1 as &dyn Any)
.downcast_ref::<DragonFlyBSDProcess>()
.expect("DragonFlyBSDProcess_compareByKey: v1 is not a DragonFlyBSDProcess");
let p2 = (v2 as &dyn Any)
.downcast_ref::<DragonFlyBSDProcess>()
.expect("DragonFlyBSDProcess_compareByKey: v2 is not a DragonFlyBSDProcess");
match key {
f if f == JID => spaceship_number!(p1.jid, p2.jid),
f if f == JAIL => spaceship_nullstr!(
p1.jname.as_deref().map(str::as_bytes),
p2.jname.as_deref().map(str::as_bytes)
),
_ => Process_compareByKey_Base(&p1.super_, &p2.super_, key),
}
}
pub static DragonFlyBSDProcess_class: ProcessClass = ProcessClass {
super_: RowClass {
super_: ObjectClass {
extends: Some(&Process_class.super_.super_),
},
isHighlighted: Some(Process_rowIsHighlighted),
isVisible: Some(Process_rowIsVisible),
writeField: Some(DragonFlyBSDProcess_rowWriteField),
matchesFilter: None,
sortKeyString: Some(Process_rowGetSortKey),
compareByParent: Some(Process_compareByParent),
},
compareByKey: Some(DragonFlyBSDProcess_compareByKey),
};
impl Object for DragonFlyBSDProcess {
fn klass(&self) -> &'static ObjectClass {
&DragonFlyBSDProcess_class.super_.super_
}
fn row_class(&self) -> Option<&'static RowClass> {
Some(&DragonFlyBSDProcess_class.super_)
}
fn as_row(&self) -> Option<&Row> {
Some(&self.super_.super_)
}
fn as_process(&self) -> Option<&Process> {
Some(&self.super_)
}
fn process_class(&self) -> Option<&'static ProcessClass> {
Some(&DragonFlyBSDProcess_class)
}
fn display(&self, out: &mut RichString) {
Row_display(self, out)
}
fn compare(&self, other: &dyn Object) -> i32 {
Process_compare(self, other)
}
}
const _: fn() = || {
fn assert_deref<T: Deref<Target = ObjectClass>>() {}
assert_deref::<ProcessClass>();
};
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::object::Object_isA;
#[test]
fn class_chain_extends_process() {
let p = DragonFlyBSDProcess_new(core::ptr::null());
let obj: &dyn Object = &p;
assert!(Object_isA(Some(obj), &DragonFlyBSDProcess_class));
assert!(Object_isA(Some(obj), &Process_class));
let rc = obj.row_class().unwrap();
assert!(rc.writeField.is_some());
assert!(rc.isHighlighted.is_some());
assert!(rc.matchesFilter.is_none());
}
#[test]
fn process_fields_table_has_jail_columns() {
assert_eq!(Process_fields.len(), LAST_PROCESSFIELD);
assert_eq!(Process_fields[JID as usize].name, "JID");
assert!(Process_fields[JID as usize].pidColumn);
assert_eq!(Process_fields[JAIL as usize].name, "JAIL");
assert_eq!(Process_fields[JAIL as usize].title, Some("JAIL "));
assert_eq!(
Process_fields[ProcessField::PID as usize].title,
Some("PID")
);
assert_eq!(Process_fields[0].name, "");
}
#[test]
fn compare_by_key_jail_and_delegate() {
let mut a = DragonFlyBSDProcess_new(core::ptr::null());
let mut b = DragonFlyBSDProcess_new(core::ptr::null());
a.jid = 1;
b.jid = 2;
assert!(DragonFlyBSDProcess_compareByKey(&a as &dyn Object, &b as &dyn Object, JID) < 0);
a.super_.super_.id = 7;
b.super_.super_.id = 3;
assert!(
DragonFlyBSDProcess_compareByKey(
&a as &dyn Object,
&b as &dyn Object,
ProcessField::PID as RowField
) > 0
);
}
}