#![allow(non_snake_case)]
#![allow(dead_code)]
#[cfg(target_os = "linux")]
pub use linux_impl::*;
#[cfg(target_os = "linux")]
mod linux_impl {
use crate::ported::linux::linuxprocess::LinuxProcess;
use crate::ported::linux::linuxprocesstable::LinuxProcessTable;
use crate::ported::process::Process_getPid;
use neli::consts::nl::{NlmF, NlmFFlags};
use neli::consts::socket::NlFamily;
use neli::genl::{Genlmsghdr, Nlattr};
use neli::nl::{NlPayload, Nlmsghdr};
use neli::socket::NlSocketHandle;
use neli::types::{Buffer, GenlBuffer};
const TASKSTATS_GENL_NAME: &str = "TASKSTATS";
const TASKSTATS_VERSION: u8 = 14;
const TASKSTATS_CMD_GET: u8 = 1;
const TASKSTATS_CMD_ATTR_PID: u16 = 1;
const TASKSTATS_TYPE_STATS: u16 = 3;
const TASKSTATS_TYPE_AGGR_PID: u16 = 4;
const TASKSTATS_TYPE_NULL: u16 = 6;
pub fn load_libnl() -> i32 {
0
}
pub fn unload_libnl() {}
pub fn initNetlinkSocket(this: &mut LinuxProcessTable) {
if load_libnl() < 0 {
return;
}
let sock = match NlSocketHandle::connect(NlFamily::Generic, None, &[]) {
Ok(s) => s,
Err(_) => return,
};
this.netlink_socket = Some(sock);
this.netlink_family = match this
.netlink_socket
.as_mut()
.unwrap()
.resolve_genl_family(TASKSTATS_GENL_NAME)
{
Ok(family) => i32::from(family),
Err(_) => -1,
};
}
pub fn LibNl_destroyNetlinkSocket(this: &mut LinuxProcessTable) {
if this.netlink_socket.is_some() {
this.netlink_socket = None;
}
unload_libnl();
}
pub fn handleNetlinkMsg(nlmsg: &Nlmsghdr<u16, Genlmsghdr<u8, u16>>, lp: &mut LinuxProcess) {
#[repr(C)]
#[derive(Clone, Copy)]
struct taskstats {
version: u16,
ac_exitcode: u32,
ac_flag: u8,
ac_nice: u8,
cpu_count: u64,
cpu_delay_total: u64,
blkio_count: u64,
blkio_delay_total: u64,
swapin_count: u64,
swapin_delay_total: u64,
cpu_run_real_total: u64,
cpu_run_virtual_total: u64,
ac_comm: [u8; 32],
ac_sched: u8,
ac_pad: [u8; 3],
ac_uid: u32,
ac_gid: u32,
ac_pid: u32,
ac_ppid: u32,
ac_btime: u32,
ac_etime: u64,
ac_utime: u64,
ac_stime: u64,
ac_minflt: u64,
ac_majflt: u64,
coremem: u64,
virtmem: u64,
hiwater_rss: u64,
hiwater_vm: u64,
read_char: u64,
write_char: u64,
read_syscalls: u64,
write_syscalls: u64,
read_bytes: u64,
write_bytes: u64,
cancelled_write_bytes: u64,
nvcsw: u64,
nivcsw: u64,
ac_utimescaled: u64,
ac_stimescaled: u64,
cpu_scaled_run_real_total: u64,
freepages_count: u64,
freepages_delay_total: u64,
thrashing_count: u64,
thrashing_delay_total: u64,
ac_btime64: u64,
compact_count: u64,
compact_delay_total: u64,
ac_tgid: u32,
ac_tgetime: u64,
ac_exe_dev: u64,
ac_exe_inode: u64,
wpcopy_count: u64,
wpcopy_delay_total: u64,
irq_count: u64,
irq_delay_total: u64,
}
let genl = match nlmsg.get_payload() {
Ok(p) => p,
Err(_) => return,
};
let mut attrs = genl.get_attr_handle();
let nested = match attrs.get_nested_attributes::<u16>(TASKSTATS_TYPE_AGGR_PID) {
Ok(h) => Some(h),
Err(_) => attrs.get_nested_attributes::<u16>(TASKSTATS_TYPE_NULL).ok(),
};
let nested = match nested {
Some(h) => h,
None => return,
};
let payload = match nested.get_attr_payload_as_with_len::<Buffer>(TASKSTATS_TYPE_STATS) {
Ok(b) => b,
Err(_) => return,
};
let bytes: &[u8] = payload.as_ref();
let mut stats: taskstats = unsafe { std::mem::zeroed() };
let n = std::cmp::min(bytes.len(), std::mem::size_of::<taskstats>());
unsafe {
std::ptr::copy_nonoverlapping(
bytes.as_ptr(),
(&mut stats as *mut taskstats).cast::<u8>(),
n,
);
}
debug_assert_eq!(Process_getPid(&lp.super_), stats.ac_pid as i32);
let time_delta = stats
.ac_etime
.wrapping_mul(1000)
.wrapping_sub(lp.delay_read_time);
let deltaperc = |x: u64, y: u64| -> f32 {
if time_delta != 0 {
(x.wrapping_sub(y) as f32 / time_delta as f32 * 100.0f32).min(100.0f32)
} else {
f32::NAN
}
};
lp.cpu_delay_percent = deltaperc(stats.cpu_delay_total, lp.cpu_delay_total);
lp.blkio_delay_percent = deltaperc(stats.blkio_delay_total, lp.blkio_delay_total);
lp.swapin_delay_percent = deltaperc(stats.swapin_delay_total, lp.swapin_delay_total);
lp.swapin_delay_total = stats.swapin_delay_total;
lp.blkio_delay_total = stats.blkio_delay_total;
lp.cpu_delay_total = stats.cpu_delay_total;
lp.delay_read_time = stats.ac_etime.wrapping_mul(1000);
}
pub fn LibNl_readDelayAcctData(this: &mut LinuxProcessTable, process: &mut LinuxProcess) {
fn delayacct_failure(process: &mut LinuxProcess) {
process.swapin_delay_percent = f32::NAN;
process.blkio_delay_percent = f32::NAN;
process.cpu_delay_percent = f32::NAN;
}
if this.netlink_socket.is_none() {
initNetlinkSocket(this);
if this.netlink_socket.is_none() {
delayacct_failure(process);
return;
}
}
let pid = Process_getPid(&process.super_);
let family = this.netlink_family as u16;
let mut attrs: GenlBuffer<u16, Buffer> = GenlBuffer::new();
match Nlattr::new(false, false, TASKSTATS_CMD_ATTR_PID, pid as u32) {
Ok(attr) => attrs.push(attr),
Err(_) => {
delayacct_failure(process);
return;
}
}
let genlhdr = Genlmsghdr::<u8, u16>::new(TASKSTATS_CMD_GET, TASKSTATS_VERSION, attrs);
let nlhdr = Nlmsghdr::new(
None,
family,
NlmFFlags::new(&[NlmF::Request]),
None,
None,
NlPayload::Payload(genlhdr),
);
let sock = this.netlink_socket.as_mut().unwrap();
if sock.send(nlhdr).is_err() {
delayacct_failure(process);
return;
}
match sock.recv::<u16, Genlmsghdr<u8, u16>>() {
Ok(Some(msg)) => handleNetlinkMsg(&msg, process),
Ok(None) => {}
Err(_) => {
delayacct_failure(process);
}
}
}
}
#[cfg(not(target_os = "linux"))]
pub use fallback::*;
#[cfg(not(target_os = "linux"))]
mod fallback {
use crate::ported::linux::linuxprocess::LinuxProcess;
use crate::ported::linux::linuxprocesstable::LinuxProcessTable;
pub fn load_libnl() -> i32 {
-1
}
pub fn unload_libnl() {}
pub fn initNetlinkSocket(_this: &mut LinuxProcessTable) {}
pub fn LibNl_destroyNetlinkSocket(_this: &mut LinuxProcessTable) {}
pub fn handleNetlinkMsg(_lp: &mut LinuxProcess) {}
pub fn LibNl_readDelayAcctData(_this: &mut LinuxProcessTable, process: &mut LinuxProcess) {
process.swapin_delay_percent = f32::NAN;
process.blkio_delay_percent = f32::NAN;
process.cpu_delay_percent = f32::NAN;
}
}