#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[repr(transparent)]
pub struct ProcessIdentifier(NonZeroI32);
impl Display for ProcessIdentifier
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter) -> fmt::Result
{
write!(f, "{}", self.0)
}
}
impl Default for ProcessIdentifier
{
#[inline(always)]
fn default() -> Self
{
let pid = unsafe { getpid() };
debug_assert!(pid > 0);
Self(new_non_zero_i32(pid))
}
}
impl TryFrom<pid_t> for ProcessIdentifier
{
type Error = ParseNumberError;
#[inline(always)]
fn try_from(value: pid_t) -> Result<Self, Self::Error>
{
if likely!(value > 0)
{
Ok(Self(new_non_zero_i32(value)))
}
else
{
Err(ParseNumberError::TooSmall)
}
}
}
impl From<NonZeroI32> for ProcessIdentifier
{
#[inline(always)]
fn from(value: NonZeroI32) -> Self
{
Self(value)
}
}
impl Into<NonZeroI32> for ProcessIdentifier
{
#[inline(always)]
fn into(self) -> NonZeroI32
{
self.0
}
}
impl Into<pid_t> for ProcessIdentifier
{
#[inline(always)]
fn into(self) -> pid_t
{
self.0.get()
}
}
impl<'a> IntoLineFeedTerminatedByteString<'a> for ProcessIdentifier
{
#[inline(always)]
fn into_line_feed_terminated_byte_string(self) -> Cow<'a, [u8]>
{
UnpaddedDecimalInteger(self.0).into_line_feed_terminated_byte_string()
}
}
impl ParseNumber for ProcessIdentifier
{
#[inline(always)]
fn parse_number(bytes: &[u8], radix: Radix, parse_byte: impl Fn(Radix, u8) -> Result<u8, ParseNumberError>) -> Result<Self, ParseNumberError>
{
let pid = pid_t::parse_number(bytes, radix, parse_byte)?;
if unlikely!(pid < 0)
{
Err(ParseNumberError::TooShort)
}
else if unlikely!(pid == 0)
{
Err(ParseNumberError::WasZero)
}
else
{
Ok(Self(new_non_zero_i32(pid)))
}
}
}
impl ParseNumberOption for ProcessIdentifier
{
#[inline(always)]
fn parse_number_option(bytes: &[u8], radix: Radix, parse_byte: impl Fn(Radix, u8) -> Result<u8, ParseNumberError>) -> Result<Option<Self>, ParseNumberError>
{
let pid = pid_t::parse_number(bytes, radix, parse_byte)?;
if unlikely!(pid < 0)
{
Err(ParseNumberError::TooShort)
}
else if pid == 0
{
Ok(None)
}
else
{
Ok(Some(ProcessIdentifier(new_non_zero_i32(pid))))
}
}
}
impl ProcessIdentifier
{
pub const Init: Self = Self(new_non_zero_i32(1));
#[inline(always)]
pub fn get_current_process_child_subreaper_process() -> Result<Option<Self>, Errno>
{
let mut attribute: i32 = unsafe_uninitialized();
process_control_wrapper2
(
PR_GET_CHILD_SUBREAPER,
&mut attribute as *mut i32 as usize,
|non_negative_result| if likely!(non_negative_result == 0)
{
if attribute == 0
{
Ok(None)
}
else
{
Ok(Some(Self(new_non_zero_i32(attribute))))
}
}
else
{
unreachable_code(format_args!("Positive result"))
},
Err,
)
}
#[inline(always)]
pub fn set_current_process_child_subreaper_process(process_identifier: Option<ProcessIdentifier>) -> Result<(), Errno>
{
let attribute: i32 = match process_identifier
{
None => 0,
Some(process_identifier) => process_identifier.into(),
};
process_control_wrapper2(PR_SET_CHILD_SUBREAPER, &attribute as *const i32 as usize, result_must_be_zero,Err)
}
#[inline(always)]
pub fn should_have_parent(self) -> bool
{
self != Self::Init
}
#[inline(always)]
pub fn open_file_descriptor(self) -> Result<ProcessIdentifierFileDescriptor, CreationError>
{
ProcessIdentifierChoice::Other(self).open_file_descriptor()
}
#[inline(always)]
pub fn process_group_identifier(self) -> Result<ProcessGroupIdentifier, ()>
{
ProcessGroupIdentifier::process_group_identifier(ProcessIdentifierChoice::Other(self))
}
#[inline(always)]
pub fn session_identifier(self) -> Result<ProcessGroupIdentifier, ()>
{
ProcessGroupIdentifier::session_identifier(ProcessIdentifierChoice::Other(self))
}
#[inline(always)]
pub fn thread_identifier(self) -> ThreadIdentifier
{
ThreadIdentifier::from(self)
}
pub fn set_maximum_value_to_maximum(proc_path: &ProcPath) -> io::Result<()>
{
#[cfg(target_pointer_width = "64")] const PID_MAX_LIMIT: u32 = 4_194_304;
#[cfg(target_pointer_width = "32")] const PID_MAX_LIMIT: u32 = 32_768;
let file_path = proc_path.sys_kernel_file_path("pid_max");
if file_path.exists()
{
file_path.write_value(UnpaddedDecimalInteger(PID_MAX_LIMIT))
}
else
{
Ok(())
}
}
#[inline(always)]
pub fn round_robin_scheduler_interval(self) -> Option<RoundRobinInterval>
{
RoundRobinInterval::for_process(ProcessIdentifierChoice::Other(self))
}
#[inline(always)]
pub fn process_name(self, proc_path: &ProcPath) -> io::Result<ProcessName>
{
ProcessName::get_process_name(ProcessIdentifierChoice::Other(self), proc_path)
}
#[inline(always)]
pub fn set_process_name(self, process_name: ProcessName, proc_path: &ProcPath) -> io::Result<()>
{
process_name.set_process_name(ProcessIdentifierChoice::Other(self), proc_path)
}
#[inline(always)]
pub fn to_vectored_read<'a>(self, from_remote: &'a [&'a [u8]]) -> ProcessIdentifierVectoredRead<'a>
{
ProcessIdentifierVectoredRead
{
process_identifier: self,
from_remote,
}
}
#[inline(always)]
pub fn vectored_read(self, to_local: &[&mut [u8]], from_remote: &[&[u8]]) -> Result<usize, CreationError>
{
let to_local_length = to_local.len();
let from_remote_length = from_remote.len();
debug_assert!(to_local_length < MaximumNumberOfBuffers, "to_local length '{}' equals or exceeds MaximumNumberOfBuffers {}", to_local_length, MaximumNumberOfBuffers);
debug_assert!(from_remote_length < MaximumNumberOfBuffers, "from_remote length '{}' equals or exceeds MaximumNumberOfBuffers {}", from_remote_length, MaximumNumberOfBuffers);
const FlagsArgumentIsUnused: u64 = 0;
let result = unsafe { process_vm_readv(self.0.get(), to_local.as_ptr() as *const iovec, to_local_length as u64, from_remote.as_ptr() as *const iovec, from_remote_length as u64, FlagsArgumentIsUnused) };
if likely!(result >= 0)
{
Ok(result as usize)
}
else if likely!(result == -1)
{
use self::CreationError::*;
match errno().0
{
ENOMEM => Err(KernelWouldBeOutOfMemory),
EPERM => Err(PermissionDenied),
ESRCH => Err(ProcessForProcessIdentifierDoesNotExist),
EFAULT => panic!("The memory described by local_iov is outside the caller's accessible address space. Or the memory described by remote_iov is outside the accessible address space of the process pid."),
EINVAL => panic!("The sum of the iov_len values of either local_iov or remote_iov overflows a ssize_t value. Or flags is not 0. Or liovcnt or riovcnt is too large."),
_ => unreachable_code(format_args!("")),
}
}
else
{
unreachable_code(format_args!(""))
}
}
#[inline(always)]
pub fn to_vectored_write<'a>(self, to_remote: &'a [&'a mut [u8]]) -> ProcessIdentifierVectoredWrite<'a>
{
ProcessIdentifierVectoredWrite
{
process_identifier: self,
to_remote,
}
}
#[inline(always)]
pub fn vectored_write(self, from_local: &[&[u8]], to_remote: &[&mut [u8]]) -> Result<usize, CreationError>
{
let from_local_length = from_local.len();
let to_remote_length = to_remote.len();
debug_assert!(from_local_length < MaximumNumberOfBuffers, "to_local length '{}' equals or exceeds MaximumNumberOfBuffers {}", from_local_length, MaximumNumberOfBuffers);
debug_assert!(to_remote_length < MaximumNumberOfBuffers, "from_remote length '{}' equals or exceeds MaximumNumberOfBuffers {}", to_remote_length, MaximumNumberOfBuffers);
const FlagsArgumentIsUnused: u64 = 0;
let result = unsafe { process_vm_writev(self.0.get(), from_local.as_ptr() as *const iovec, from_local_length as u64, to_remote.as_ptr() as *const iovec, to_remote_length as u64, FlagsArgumentIsUnused) };
if likely!(result >= 0)
{
Ok(result as usize)
}
else if likely!(result == -1)
{
use self::CreationError::*;
match errno().0
{
ENOMEM => Err(KernelWouldBeOutOfMemory),
EPERM => Err(PermissionDenied),
ESRCH => Err(ProcessForProcessIdentifierDoesNotExist),
EFAULT => panic!("The memory described by local_iov is outside the caller's accessible address space. Or the memory described by remote_iov is outside the accessible address space of the process pid."),
EINVAL => panic!("The sum of the iov_len values of either local_iov or remote_iov overflows a ssize_t value. Or flags is not 0. Or liovcnt or riovcnt is too large."),
_ => unreachable_code(format_args!("")),
}
}
else
{
unreachable_code(format_args!(""))
}
}
}