//! Data structures for process management use core::{ffi::CStr, fmt, marker::PhantomData, time::Duration}; use crate::io::{FileMode, RawFd}; mod exit; pub mod thread; pub use crate::generated::{ ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnFlags, SpawnOptions, ThreadId, ThreadSpawnOptions, }; pub use exit::ExitCode; pub use thread::ThreadOption; // TODO this is ugly pub mod auxv { pub const TLS_MASTER_COPY: u64 = 0x80; pub const TLS_FULL_SIZE: u64 = 0x81; pub const TLS_DATA_SIZE: u64 = 0x82; pub const TLS_ALIGN: u64 = 0x83; pub const TLS_MODULE_ID: u64 = 0x84; pub const TLS_MODULE_OFFSET: u64 = 0x85; pub const TLS_ALREADY_INITIALIZED: u64 = 0x86; pub const NULL: u64 = 0x00; } /// Defines an optional argument for controlling process creation #[derive(Debug)] pub enum SpawnOption { /// Indicates a new process should inherit a file descriptor from its creator InheritFile { /// FD on the creator side source: RawFd, /// What FD number should be used in the child child: RawFd, }, /// The new process should be placed in the specified group SetProcessGroup(ProcessGroupId), /// Gain terminal control for the given FD GainTerminal(RawFd), /// Attach debugging to a channel in parent's I/O context. The process will start in /// single-stepping mode AttachDebug(RawFd), } /// Describes a single mutex operation #[derive(Clone, Debug)] #[repr(C)] pub enum MutexOperation { /// Waits on the mutex object until it is different from "compare value" Wait(u32, Option), /// Waits on the mutex object until it becomes equal to the "compare value" WaitUntil(u32, Option), /// Wakes a single mutex-waiting thread Wake, /// Wakes all threads waiting on the mutex WakeAll, } /// Provides some amount of process-related information #[derive(Clone, Debug)] pub enum ProcessInfoElement { /// Mask applied to file modes when creating new files/directories Umask(FileMode), } #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct AuxValue { pub tag: u64, pub val: u64, } #[derive(Clone, Copy)] pub struct StringArgIter<'a> { ptr: *const *const u8, _pd: PhantomData<&'a ProgramArgumentInner>, } #[derive(Clone, Copy)] pub struct AuxValueIter<'a> { ptr: *const AuxValue, _pd: PhantomData<&'a ProgramArgumentInner>, } #[repr(C)] pub struct ProgramArgumentInner { pub args: *const *const u8, pub envs: *const *const u8, pub auxv: *const AuxValue, } impl ProcessId { pub const ZERO: Self = Self(0); } impl fmt::Display for ProcessId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "", self.0) } } impl fmt::Display for ProcessGroupId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "", self.0) } } impl<'a> Iterator for StringArgIter<'a> { type Item = &'a CStr; fn next(&mut self) -> Option { if self.ptr.is_null() { return None; } let entry = unsafe { self.ptr.read() }; if entry.is_null() { return None; } self.ptr = unsafe { self.ptr.add(1) }; let entry = unsafe { CStr::from_ptr(entry.cast()) }; Some(entry) } } impl<'a> Iterator for AuxValueIter<'a> { type Item = &'a AuxValue; fn next(&mut self) -> Option { if self.ptr.is_null() { return None; } let entry = unsafe { &*self.ptr }; if entry.tag == auxv::NULL { return None; } self.ptr = unsafe { self.ptr.add(1) }; Some(entry) } } impl ProgramArgumentInner { pub fn args(&self) -> impl Iterator { StringArgIter { ptr: self.args, _pd: PhantomData, } } pub fn envs(&self) -> impl Iterator { StringArgIter { ptr: self.envs, _pd: PhantomData, } } pub fn auxv(&self) -> impl Iterator { AuxValueIter { ptr: self.auxv, _pd: PhantomData, } } } impl Signal { pub fn is_synchronous(&self) -> bool { matches!(self, Self::MemoryAccessViolation) } pub fn is_handleable(&self) -> bool { !matches!(self, Self::Killed) } }