heim_process/process/mod.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246
use std::fmt;
use std::path::PathBuf;
use std::time::Instant;
use heim_common::prelude::*;
use heim_common::units::Time;
use crate::{sys, Pid, ProcessResult};
mod command;
mod cpu_times;
mod cpu_usage;
mod memory;
mod status;
pub use self::command::{Command, CommandIter};
pub use self::cpu_times::CpuTime;
pub use self::cpu_usage::CpuUsage;
pub use self::memory::Memory;
pub use self::status::Status;
/// System process.
///
/// Some extra methods can be found in the [OS extensions](./os/index.html)
#[derive(Eq, PartialEq, Hash)]
pub struct Process(sys::Process);
wrap!(Process, sys::Process);
impl Process {
/// Returns the process pid.
pub fn pid(&self) -> Pid {
self.as_ref().pid()
}
/// Returns future which resolves into the process parent pid.
pub fn parent_pid(&self) -> impl Future<Output = ProcessResult<Pid>> {
self.as_ref().parent_pid()
}
/// Returns future which resolves into the parent [Process].
///
/// [Process]: ./struct.Process.html
pub fn parent(&self) -> impl Future<Output = ProcessResult<Process>> {
self.parent_pid().and_then(get)
}
/// Returns future which resolves into the process name.
pub fn name(&self) -> impl Future<Output = ProcessResult<String>> {
self.as_ref().name()
}
/// Returns future which resolves into the process executable as an absolute path.
pub fn exe(&self) -> impl Future<Output = ProcessResult<PathBuf>> {
self.as_ref().exe()
}
/// Returns future which resolves into the process command line.
///
/// ## Example
///
/// ```rust
/// # use heim_process::{self as process, Process, ProcessResult};
/// #
/// # #[heim_derive::main]
/// # async fn main() -> ProcessResult<()> {
/// let process = process::current().await?;
/// let command = process.command().await?;
/// println!("Command line arguments:");
/// for arg in &command {
/// println!("{:?}", arg);
/// }
///
/// # Ok(())
/// # }
/// ```
pub fn command(&self) -> impl Future<Output = ProcessResult<Command>> {
self.as_ref().command().map_ok(Into::into)
}
/// Returns future which resolves into the process current working directory.
///
/// ## Compatibility
///
/// For Windows this method is not implemented yet and will always return an error,
/// see [#105](https://github.com/heim-rs/heim/issues/105).
pub fn cwd(&self) -> impl Future<Output = ProcessResult<PathBuf>> {
self.as_ref().cwd()
}
/// Returns future which resolves into the current process status.
pub fn status(&self) -> impl Future<Output = ProcessResult<Status>> {
self.as_ref().status()
}
/// Returns future which resolves into the process creation time,
/// expressed as a [Time] amount since the UNIX epoch.
///
/// [Time]: ../units/type.Time.html
pub fn create_time(&self) -> impl Future<Output = ProcessResult<Time>> {
self.as_ref().create_time()
}
/// Returns future which resolves into the accumulated process time.
pub fn cpu_time(&self) -> impl Future<Output = ProcessResult<CpuTime>> {
self.as_ref().cpu_time().map_ok(Into::into)
}
/// Returns future which resolves into the CPU usage measurement.
///
/// Returned [`CpuUsage`] struct represents instantaneous CPU usage and does not represent
/// any reasonable value by itself.
/// It is suggested to wait for a while with help of any async timer
/// (for accuracy recommended delay should be at least 100 ms),
/// call this method once again and subtract former [`CpuUsage`] from the new one.
///
/// Same to any *nix system, calculated CPU usage might exceed 100 %
/// if the process is running multiple threads on different CPU cores.
///
/// ## Example
///
/// ```rust
/// # use std::time::Duration;
/// # use heim_common::units::ratio;
/// # use heim_process::{self as process, Process, ProcessResult};
/// #
/// # #[heim_derive::main]
/// # async fn main() -> ProcessResult<()> {
/// let process = process::current().await?;
/// let measurement_1 = process.cpu_usage().await?;
/// // Or any other async timer at your choice
/// futures_timer::Delay::new(Duration::from_millis(100)).await;
/// let measurement_2 = process.cpu_usage().await?;
///
/// println!("CPU usage: {} %", (measurement_2 - measurement_1).get::<ratio::percent>());
/// # Ok(())
/// # }
/// ```
///
/// [`CpuUsage`]: ./struct.CpuUsage.html
pub fn cpu_usage(&self) -> impl Future<Output = ProcessResult<CpuUsage>> {
self.cpu_time().and_then(|time| {
heim_cpu::logical_count()
.map_err(Into::into)
.map_ok(move |count| CpuUsage {
cpu_count: count,
cpu_time: time,
at: Instant::now(),
})
})
}
/// Returns future which resolves into the memory information about this process.
pub fn memory(&self) -> impl Future<Output = ProcessResult<Memory>> {
self.as_ref().memory().map_ok(Into::into)
}
/// Returns future which checks if this `Process` is still running.
pub fn is_running(&self) -> impl Future<Output = ProcessResult<bool>> {
self.as_ref().is_running()
}
/// Suspend the current process.
///
/// Before the signal send, it checks whether process PID has been reused,
/// and if it is a case, [`NoSuchProcess`] error will be returned.
///
/// ## Compatibility
///
/// For *nix systems it sends the `SIGSTOP` signal to process.
///
/// [`NoSuchProcess`]: ./enum.ProcessError.html#variant.NoSuchProcess
pub fn suspend(&self) -> impl Future<Output = ProcessResult<()>> {
self.0.suspend()
}
/// Resume the current process.
///
/// Before the signal send, it checks whether process PID has been reused,
/// and if it is a case, [`NoSuchProcess`] error will be returned.
///
/// ## Compatibility
///
/// For *nix systems it sends the `SIGCONT` signal to process.
///
/// [`NoSuchProcess`]: ./enum.ProcessError.html#variant.NoSuchProcess
pub fn resume(&self) -> impl Future<Output = ProcessResult<()>> {
self.0.resume()
}
/// Terminate the current process.
///
/// Before the signal send, it checks whether process PID has been reused,
/// and if it is a case, [`NoSuchProcess`] error will be returned.
///
/// ## Compatibility
///
/// For *nix systems it sends the `SIGTERM` signal to process.
///
/// For Windows it is an alias for the [`Process::kill`]
///
/// [`NoSuchProcess`]: ./enum.ProcessError.html#variant.NoSuchProcess
/// [`Process::kill`]: #method.kill
pub fn terminate(&self) -> impl Future<Output = ProcessResult<()>> {
self.0.terminate()
}
/// Kills the current process.
///
/// Before the signal send, it checks whether process PID has been reused,
/// and if it is a case, [`NoSuchProcess`] error will be returned.
///
/// ## Compatibility
///
/// For *nix systems it sends the `SIGKILL` signal to process.
///
/// [`TerminateProcess`] function is used for Windows,
/// it initiates the termination but does not awaits for completion.
///
/// [`NoSuchProcess`]: ./enum.ProcessError.html#variant.NoSuchProcess
/// [`TerminateProcess`]: https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-terminateprocess
pub fn kill(&self) -> impl Future<Output = ProcessResult<()>> {
self.0.kill()
}
}
impl fmt::Debug for Process {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Process").field("pid", &self.pid()).finish()
}
}
/// Returns stream which yields currently running processes.
pub fn processes() -> impl Stream<Item = ProcessResult<Process>> {
sys::processes().map_ok(Into::into)
}
/// Load the process information with `pid` given.
pub fn get(pid: Pid) -> impl Future<Output = ProcessResult<Process>> {
sys::get(pid).map_ok(Into::into)
}
/// Returns the `Process` matching the currently running program.
pub fn current() -> impl Future<Output = ProcessResult<Process>> {
sys::current().map_ok(Into::into)
}