#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Stat
{
pub process_identifier: ProcessIdentifier,
pub command_name: CommandName,
pub state: ProcessState,
pub parent_process_identifier: Option<ProcessIdentifier>,
pub process_group_identifier: Option<ProcessGroupIdentifier>,
pub session_identifier: Option<ProcessGroupIdentifier>,
pub controlling_terminal: Option<CharacterDevice>,
pub controlling_terminal_foreground_process_group: Option<ProcessGroupIdentifier>,
pub kernel_flags: StatProcessFlags,
pub number_of_minor_page_faults: usize,
pub number_of_minor_page_faults_for_waited_for_children: usize,
pub number_of_major_page_faults: usize,
pub number_of_major_page_faults_for_waited_for_children: usize,
pub user_mode_time: ClockTicks,
pub kernel_mode_time: ClockTicks,
pub guest_time: ClockTicks,
pub user_mode_time_for_waited_for_children: ClockTicks,
pub kernel_mode_time_for_waited_for_children: ClockTicks,
pub guest_time_for_waited_for_children: ClockTicks,
pub aggregated_block_io_delays: ClockTicks,
pub priority: i32,
pub nice: Nice,
pub num_threads: Option<NonZeroUsize>,
pub start_time: ClockTicks,
pub virtual_memory_size_in_bytes: u64,
pub resident_set_size: NumberOfPages,
pub resident_set_size_soft_limit_in_bytes: u64,
pub start_code: Option<VirtualAddress>,
pub end_code: Option<VirtualAddress>,
pub start_stack: Option<VirtualAddress>,
pub stack_pointer: Option<VirtualAddress>,
pub instruction_pointer: Option<VirtualAddress>,
#[deprecated]
pub pending_non_real_time_signals: Signals,
#[deprecated]
pub blocked_non_real_time_signals: Signals,
#[deprecated]
pub ignored_non_real_time_signals: Signals,
#[deprecated]
pub caught_non_real_time_signals: Signals,
pub wait_channel: bool,
pub signal_sent_to_parent_when_this_child_process_exits: Signal,
pub last_hyper_thread_process_executed_on: HyperThread,
pub real_time_priority: Option<RealTimePriority>,
pub scheduling_policy: u32,
pub start_data: Option<VirtualAddress>,
pub end_data: Option<VirtualAddress>,
pub start_brk: Option<VirtualAddress>,
pub start_command_line_arguments: Option<VirtualAddress>,
pub end_command_line_arguments: Option<VirtualAddress>,
pub start_environment_variables: Option<VirtualAddress>,
pub end_environment_variables: Option<VirtualAddress>,
pub wait_status: Option<ChildStatus>,
}
impl Stat
{
#[inline(always)]
pub fn self_stat(proc_path: &ProcPath) -> Result<Self, StatParseError>
{
Self::process_stat(proc_path, ProcessIdentifierChoice::Current)
}
#[inline(always)]
pub fn process_stat(proc_path: &ProcPath, process_identifier: ProcessIdentifierChoice) -> Result<Self, StatParseError>
{
use self::StatParseError::*;
#[inline(always)]
fn clock_ticks_unsigned(value: u64) -> Result<ClockTicks, StatParseError>
{
Ok(ClockTicks::from(value))
}
#[inline(always)]
fn clock_ticks_signed(value: i64) -> Result<ClockTicks, StatParseError>
{
if likely!(value >= 0)
{
clock_ticks_unsigned(value as u64)
}
else
{
Err(NegativeValue)
}
}
#[inline(always)]
fn optional_signed_process_identifier(value: i64) -> Result<Option<ProcessIdentifier>, StatParseError>
{
if unlikely!(value < 0)
{
Err(NegativeValue)
}
else if unlikely!(value > (i32::MAX as i64))
{
Err(LargeValue)
}
else if unlikely!(value == 0)
{
Ok(None)
}
else
{
Ok(Some(ProcessIdentifier::from(new_non_zero_i32(value as i32))))
}
}
#[inline(always)]
fn unsigned_process_identifier(value: u64) -> Result<ProcessIdentifier, StatParseError>
{
if unlikely!(value == 0)
{
Err(ZeroValue)
}
else if unlikely!(value > (i32::MAX as u64))
{
Err(LargeValue)
}
else
{
Ok(ProcessIdentifier::from(new_non_zero_i32(value as i32)))
}
}
#[inline(always)]
fn optional_process_group_identifier(value: i64) -> Result<Option<ProcessGroupIdentifier>, StatParseError>
{
if value == -1
{
return Ok(None)
}
process_group_identifier(value).map(|process_group_identifier| Some(process_group_identifier))
}
#[inline(always)]
fn process_group_identifier(value: i64) -> Result<ProcessGroupIdentifier, StatParseError>
{
if unlikely!(value < 1)
{
Err(NegativeValue)
}
else if unlikely!(value > (i32::MAX as i64))
{
Err(LargeValue)
}
else
{
Ok(ProcessGroupIdentifier::from(new_non_zero_i32(value as i32)))
}
}
#[inline(always)]
fn real_time_priority(value: u64) -> Result<Option<RealTimePriority>, StatParseError>
{
if value == 0
{
Ok(None)
}
else if value <= 99
{
Ok(Some(unsafe { transmute(value as u8) }))
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn boolean(value: u64) -> Result<bool, StatParseError>
{
match value
{
0 => Ok(false),
1 => Ok(true),
_ => Err(LargeValue)
}
}
#[inline(always)]
fn virtual_address(value: u64) -> Result<Option<VirtualAddress>, StatParseError>
{
if value == 0
{
Ok(None)
}
else
{
Ok(Some(VirtualAddress::from(to_usize(value)?)))
}
}
#[inline(always)]
fn to_usize(value: u64) -> Result<usize, StatParseError>
{
if likely!(value <= (usize::MAX as u64))
{
Ok(value as usize)
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn num_threads(value: i64) -> Result<Option<NonZeroUsize>, StatParseError>
{
if unlikely!(value < 0)
{
Err(NegativeValue)
}
else if likely!((value as u64) <= (usize::MAX as u64))
{
Ok(NonZeroUsize::new(value as usize))
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn to_i32(value: i64) -> Result<i32, StatParseError>
{
if likely!(value >= (i32::MIN as i64) && value <= (i32::MAX as i64))
{
Ok(value as i32)
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn to_u32(value: u64) -> Result<u32, StatParseError>
{
if likely!(value <= (u32::MAX as u64))
{
Ok(value as u32)
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn nice(value: i64) -> Result<Nice, StatParseError>
{
if likely!(value >= -20 && value <= 19)
{
Ok(unsafe { transmute(value as i32) })
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn child_status(value: i64) -> Result<Option<ChildStatus>, StatParseError>
{
if value == 0
{
Ok(None)
}
else if likely!(value >= (i32::MIN as i64) && value <= (i32::MAX as i64))
{
Ok(Some(ChildStatus::parse(value as i32)?))
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn signal(value: i64) -> Result<Signal, StatParseError>
{
if likely!(value >= 0 && value <= (u8::MAX as i64))
{
Ok(Signal::parse_raw_signal_number_u8(value as u8)?)
}
else
{
Err(LargeValue)
}
}
#[inline(always)]
fn optional_character_device(value: i64) -> Result<Option<CharacterDevice>, StatParseError>
{
if value == 0
{
Ok(None)
}
else
{
Ok(Some(CharacterDevice::from(value as dev_t)))
}
}
#[inline(always)]
fn process_state(value: i8) -> Result<ProcessState, StatParseError>
{
Ok(ProcessState::try_from(value)?)
}
#[inline(always)]
fn kernel_flags(value: u64) -> Result<StatProcessFlags, StatParseError>
{
if unlikely!(value > (u32::MAX as u64))
{
Err(LargeValue)
}
else
{
Ok(StatProcessFlags::from_bits_truncate(value as u32))
}
}
#[inline(always)]
fn signals(value: u64) -> Result<Signals, StatParseError>
{
Ok(Signals(BitSet::new_from_u64(value)))
}
#[inline(always)]
fn hyper_thread(value: i64) -> Result<HyperThread, StatParseError>
{
if value > (i16::MAX as i64)
{
Err(LargeValue)
}
else if value < 0
{
Err(NegativeValue)
}
else
{
Ok(HyperThread::try_from(value as u16)?)
}
}
let bytes = proc_path.process_file_path(process_identifier, "stat").read_raw_without_line_feed()?;
let bytes = &bytes[..];
let mut fields = StatFieldIterator::new(bytes);
#[allow(deprecated)]
let this = Self
{
process_identifier: fields.decimal_unsigned_long_long_to("process_identifier", unsigned_process_identifier)?,
command_name: CommandName::from_bytes(fields.next_field("command_name")?)?,
state: fields.character_to("state", process_state)?,
parent_process_identifier: fields.decimal_signed_long_long_to("ppid", optional_signed_process_identifier)?,
process_group_identifier: fields.decimal_signed_long_long_to("pgrp", optional_process_group_identifier)?,
session_identifier: fields.decimal_signed_long_long_to("session", optional_process_group_identifier)?,
controlling_terminal: fields.decimal_signed_long_long_to("tty_nr", optional_character_device)?,
controlling_terminal_foreground_process_group: fields.decimal_signed_long_long_to("tpgid", optional_process_group_identifier)?,
kernel_flags: fields.decimal_unsigned_long_long_to("flags", kernel_flags)?,
number_of_minor_page_faults: fields.decimal_unsigned_long_long_to("minflt", to_usize)?,
number_of_minor_page_faults_for_waited_for_children: fields.decimal_unsigned_long_long_to("cminflt", to_usize)?,
number_of_major_page_faults: fields.decimal_unsigned_long_long_to("majflt", to_usize)?,
number_of_major_page_faults_for_waited_for_children: fields.decimal_unsigned_long_long_to("cmajflt", to_usize)?,
user_mode_time: fields.decimal_unsigned_long_long_to("utime", clock_ticks_unsigned)?,
kernel_mode_time: fields.decimal_unsigned_long_long_to("stime", clock_ticks_unsigned)?,
user_mode_time_for_waited_for_children: fields.decimal_signed_long_long_to("cutime", clock_ticks_signed)?,
kernel_mode_time_for_waited_for_children: fields.decimal_signed_long_long_to("cstime", clock_ticks_signed)?,
priority: fields.decimal_signed_long_long_to("priority", to_i32)?,
nice: fields.decimal_signed_long_long_to("nice", nice)?,
num_threads: fields.decimal_signed_long_long_to("num_threads", num_threads)?,
start_time:
{
fields.zero_decimal_unsigned_long_long("itrealvalue")?;
fields.decimal_unsigned_long_long_to("starttime", clock_ticks_unsigned)?
},
virtual_memory_size_in_bytes: fields.decimal_unsigned_long_long("vsize")?,
resident_set_size: fields.decimal_unsigned_long_long("rss")?,
resident_set_size_soft_limit_in_bytes: fields.decimal_unsigned_long_long("rsslim")?,
start_code: fields.decimal_unsigned_long_long_to("startcode", virtual_address)?,
end_code: fields.decimal_unsigned_long_long_to("endcode", virtual_address)?,
start_stack: fields.decimal_unsigned_long_long_to("startstack", virtual_address)?,
stack_pointer: fields.decimal_unsigned_long_long_to("kstkesp", virtual_address)?,
instruction_pointer: fields.decimal_unsigned_long_long_to("kstkeip", virtual_address)?,
pending_non_real_time_signals: fields.decimal_unsigned_long_long_to("signal", signals)?,
blocked_non_real_time_signals: fields.decimal_unsigned_long_long_to("blocked", signals)?,
ignored_non_real_time_signals: fields.decimal_unsigned_long_long_to("sigignore", signals)?,
caught_non_real_time_signals: fields.decimal_unsigned_long_long_to("sigcatch", signals)?,
wait_channel: fields.decimal_unsigned_long_long_to("wchan", boolean)?,
signal_sent_to_parent_when_this_child_process_exits:
{
fields.zero_decimal_unsigned_long_long("nswap")?;
fields.zero_decimal_unsigned_long_long("cnswap")?;
fields.decimal_signed_long_long_to("exit_signal", signal)?
},
last_hyper_thread_process_executed_on: fields.decimal_signed_long_long_to("processor", hyper_thread)?,
real_time_priority: fields.decimal_unsigned_long_long_to("rt_priority", real_time_priority)?,
scheduling_policy: fields.decimal_unsigned_long_long_to("policy", to_u32)?,
aggregated_block_io_delays: fields.decimal_unsigned_long_long_to("delayacct_blkio_ticks", clock_ticks_unsigned)?,
guest_time: fields.decimal_unsigned_long_long_to("guest_time", clock_ticks_unsigned)?,
guest_time_for_waited_for_children: fields.decimal_signed_long_long_to("cguest_time", clock_ticks_signed)?,
start_data: fields.decimal_unsigned_long_long_to("start_data", virtual_address)?,
end_data: fields.decimal_unsigned_long_long_to("end_data", virtual_address)?,
start_brk: fields.decimal_unsigned_long_long_to("start_brk", virtual_address)?,
start_command_line_arguments: fields.decimal_unsigned_long_long_to("arg_start", virtual_address)?,
end_command_line_arguments: fields.decimal_unsigned_long_long_to("arg_end", virtual_address)?,
start_environment_variables: fields.decimal_unsigned_long_long_to("env_start", virtual_address)?,
end_environment_variables: fields.decimal_unsigned_long_long_to("env_end", virtual_address)?,
wait_status: fields.decimal_signed_long_long_to("exit_code", child_status)?,
};
if cfg!(debug_assertions)
{
if this.parent_process_identifier.is_none()
{
debug_assert!(!this.process_identifier.should_have_parent());
debug_assert!(this.controlling_terminal_foreground_process_group.is_none())
}
else
{
debug_assert!(this.process_identifier.should_have_parent());
debug_assert!(this.controlling_terminal_foreground_process_group.is_some())
}
match (this.controlling_terminal, this.controlling_terminal_foreground_process_group)
{
(None, None) => (),
(Some(_), Some(_)) => (),
_ => panic!("controlling_terminal and controlling_terminal_foreground_process_group must either both be None or both be Some")
}
}
Ok(this)
}
}