diff --git a/src/lib.rs b/src/lib.rs index 7a1f657..8f7bbf6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ mod model; pub(crate) mod netlink; pub use model::*; -pub use c_headers::taskstats as __bindgen_taskstats; +pub use c_headers::taskstats; use c_headers::{ __u16, __u32, __u64, __u8, TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK, TASKSTATS_CMD_ATTR_PID, TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, TASKSTATS_CMD_ATTR_TGID, TASKSTATS_CMD_GET, @@ -279,69 +279,6 @@ impl AsBuf for T { } } -/// This is custom copy of the generated `struct taskstats` from linux version 3.10.0 and in this crate -/// this type is used to read binary data transferred from linux kernel. -/// The reason of doing this despite the `bindgen` generates rust bindings including `struct taskstats` -/// is due to potential corruption of on-memory struct layout likely caused by old clang version. -/// ref: https://github.com/rust-lang/rust-bindgen/issues/867 -/// Specifically, when `bindgen` generates `struct taskstats` with older clang version, the resulting -/// struct defined in generated rust source code contains size padding as the last member of the struct -/// causing offset of members after `ac_uid` to shift 4-byte or more and the result data becomes unreliable. -/// The `bindgen` generated definition works well in environment that uses newer clang versions, but I -/// decided to use copied definition of this struct for the time being by following considerations: -/// * The struct definition rarely evolves. -/// * Returning corrupted data silently is critical and much worse than not providing from the beginning. -/// * If user of this crate still needs to access the exactly original definition generated by `bindgen`, -/// it might still be possible by casting type to `__bindgen_taskstats` exported by this crate. -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct taskstats { - pub version: __u16, - pub ac_exitcode: __u32, - pub ac_flag: __u8, - pub ac_nice: __u8, - pub cpu_count: __u64, - pub cpu_delay_total: __u64, - pub blkio_count: __u64, - pub blkio_delay_total: __u64, - pub swapin_count: __u64, - pub swapin_delay_total: __u64, - pub cpu_run_real_total: __u64, - pub cpu_run_virtual_total: __u64, - pub ac_comm: [::std::os::raw::c_char; 32usize], - pub ac_sched: __u8, - pub ac_pad: [__u8; 3usize], - pub __unused_padding: u32, - pub ac_uid: __u32, - pub ac_gid: __u32, - pub ac_pid: __u32, - pub ac_ppid: __u32, - pub ac_btime: __u32, - pub ac_etime: __u64, - pub ac_utime: __u64, - pub ac_stime: __u64, - pub ac_minflt: __u64, - pub ac_majflt: __u64, - pub coremem: __u64, - pub virtmem: __u64, - pub hiwater_rss: __u64, - pub hiwater_vm: __u64, - pub read_char: __u64, - pub write_char: __u64, - pub read_syscalls: __u64, - pub write_syscalls: __u64, - pub read_bytes: __u64, - pub write_bytes: __u64, - pub cancelled_write_bytes: __u64, - pub nvcsw: __u64, - pub nivcsw: __u64, - pub ac_utimescaled: __u64, - pub ac_stimescaled: __u64, - pub cpu_scaled_run_real_total: __u64, - pub freepages_count: __u64, - pub freepages_delay_total: __u64, -} - #[cfg(test)] mod tests { use super::*; @@ -353,8 +290,8 @@ mod tests { let ts = client.pid_stats(std::process::id()).unwrap(); // Just asserts some fields which do likely have positive values - assert!(ts.cpu.utime_total.as_nanos() > 0); - assert!(ts.memory.rss_total > 0); + assert!(ts.delays.cpu.delay_total.as_nanos() > 0); + assert!(ts.cpu.virtual_time_total.as_nanos() > 0); } #[cfg(test_priv)] @@ -364,142 +301,7 @@ mod tests { let ts = client.tgid_stats(std::process::id()).unwrap(); // Just asserts some fields which do likely have positive values - assert!(ts.cpu.utime_total.as_nanos() > 0); - assert!(ts.memory.rss_total > 0); - } - - #[test] - fn test_struct_taskstats_alignment() { - // Automatically generated by tools/gen_layout_test.sh - assert_eq!(328, std::mem::size_of::()); - assert_eq!(0, unsafe { - &(*(std::ptr::null::())).version as *const _ as usize - }); - assert_eq!(4, unsafe { - &(*(std::ptr::null::())).ac_exitcode as *const _ as usize - }); - assert_eq!(8, unsafe { - &(*(std::ptr::null::())).ac_flag as *const _ as usize - }); - assert_eq!(9, unsafe { - &(*(std::ptr::null::())).ac_nice as *const _ as usize - }); - assert_eq!(16, unsafe { - &(*(std::ptr::null::())).cpu_count as *const _ as usize - }); - assert_eq!(24, unsafe { - &(*(std::ptr::null::())).cpu_delay_total as *const _ as usize - }); - assert_eq!(32, unsafe { - &(*(std::ptr::null::())).blkio_count as *const _ as usize - }); - assert_eq!(40, unsafe { - &(*(std::ptr::null::())).blkio_delay_total as *const _ as usize - }); - assert_eq!(48, unsafe { - &(*(std::ptr::null::())).swapin_count as *const _ as usize - }); - assert_eq!(56, unsafe { - &(*(std::ptr::null::())).swapin_delay_total as *const _ as usize - }); - assert_eq!(64, unsafe { - &(*(std::ptr::null::())).cpu_run_real_total as *const _ as usize - }); - assert_eq!(72, unsafe { - &(*(std::ptr::null::())).cpu_run_virtual_total as *const _ as usize - }); - assert_eq!(80, unsafe { - &(*(std::ptr::null::())).ac_comm as *const _ as usize - }); - assert_eq!(112, unsafe { - &(*(std::ptr::null::())).ac_sched as *const _ as usize - }); - assert_eq!(113, unsafe { - &(*(std::ptr::null::())).ac_pad as *const _ as usize - }); - assert_eq!(120, unsafe { - &(*(std::ptr::null::())).ac_uid as *const _ as usize - }); - assert_eq!(124, unsafe { - &(*(std::ptr::null::())).ac_gid as *const _ as usize - }); - assert_eq!(128, unsafe { - &(*(std::ptr::null::())).ac_pid as *const _ as usize - }); - assert_eq!(132, unsafe { - &(*(std::ptr::null::())).ac_ppid as *const _ as usize - }); - assert_eq!(136, unsafe { - &(*(std::ptr::null::())).ac_btime as *const _ as usize - }); - assert_eq!(144, unsafe { - &(*(std::ptr::null::())).ac_etime as *const _ as usize - }); - assert_eq!(152, unsafe { - &(*(std::ptr::null::())).ac_utime as *const _ as usize - }); - assert_eq!(160, unsafe { - &(*(std::ptr::null::())).ac_stime as *const _ as usize - }); - assert_eq!(168, unsafe { - &(*(std::ptr::null::())).ac_minflt as *const _ as usize - }); - assert_eq!(176, unsafe { - &(*(std::ptr::null::())).ac_majflt as *const _ as usize - }); - assert_eq!(184, unsafe { - &(*(std::ptr::null::())).coremem as *const _ as usize - }); - assert_eq!(192, unsafe { - &(*(std::ptr::null::())).virtmem as *const _ as usize - }); - assert_eq!(200, unsafe { - &(*(std::ptr::null::())).hiwater_rss as *const _ as usize - }); - assert_eq!(208, unsafe { - &(*(std::ptr::null::())).hiwater_vm as *const _ as usize - }); - assert_eq!(216, unsafe { - &(*(std::ptr::null::())).read_char as *const _ as usize - }); - assert_eq!(224, unsafe { - &(*(std::ptr::null::())).write_char as *const _ as usize - }); - assert_eq!(232, unsafe { - &(*(std::ptr::null::())).read_syscalls as *const _ as usize - }); - assert_eq!(240, unsafe { - &(*(std::ptr::null::())).write_syscalls as *const _ as usize - }); - assert_eq!(248, unsafe { - &(*(std::ptr::null::())).read_bytes as *const _ as usize - }); - assert_eq!(256, unsafe { - &(*(std::ptr::null::())).write_bytes as *const _ as usize - }); - assert_eq!(264, unsafe { - &(*(std::ptr::null::())).cancelled_write_bytes as *const _ as usize - }); - assert_eq!(272, unsafe { - &(*(std::ptr::null::())).nvcsw as *const _ as usize - }); - assert_eq!(280, unsafe { - &(*(std::ptr::null::())).nivcsw as *const _ as usize - }); - assert_eq!(288, unsafe { - &(*(std::ptr::null::())).ac_utimescaled as *const _ as usize - }); - assert_eq!(296, unsafe { - &(*(std::ptr::null::())).ac_stimescaled as *const _ as usize - }); - assert_eq!(304, unsafe { - &(*(std::ptr::null::())).cpu_scaled_run_real_total as *const _ as usize - }); - assert_eq!(312, unsafe { - &(*(std::ptr::null::())).freepages_count as *const _ as usize - }); - assert_eq!(320, unsafe { - &(*(std::ptr::null::())).freepages_delay_total as *const _ as usize - }); + assert!(ts.delays.cpu.delay_total.as_nanos() > 0); + assert!(ts.cpu.virtual_time_total.as_nanos() > 0); } } diff --git a/src/model.rs b/src/model.rs index 81bca4f..3fb054f 100644 --- a/src/model.rs +++ b/src/model.rs @@ -22,7 +22,7 @@ pub const TASKSTATS_SIZE: usize = const_max( /// There are more (but may not much interested) fields in the original /// `struct taskstats` and they are accessible through obtaining the original /// struct by `TaskStats#inner()`. -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct TaskStats { pub(crate) inner_buf: [u8; TASKSTATS_SIZE], /// The target task ID