ProcessHandle

Struct ProcessHandle 

Source
pub struct ProcessHandle { /* private fields */ }
Expand description

Represents a handle to a process identified by its process ID (PID).

The ProcessHandle struct is used to encapsulate the process identifier (PID) of a running process. It is designed to be lightweight and can be cloned or debugged as required.

§Fields

  • pid: A u32 value that represents the process ID of the targeted process.

§Traits

  • Debug: Allows instances of ProcessHandle to be formatted using the {:?} formatter for debugging purposes.
  • Clone: Allows the ProcessHandle to be cloned, creating a new instance with the same pid.

§Example

let handle = ProcessHandle { pid: 1234 };
println!("{:?}", handle); // Outputs: ProcessHandle { pid: 1234 }
let cloned_handle = handle.clone();
println!("{:?}", cloned_handle); // Outputs: ProcessHandle { pid: 1234 }

Implementations§

Source§

impl ProcessHandle

Source

pub async fn receive_output(&mut self) -> Result<Option<String>>

Source

pub async fn receive_output_with_timeout( &mut self, timeout: Duration, ) -> Result<Option<String>>

Receives an output message asynchronously from the process associated with the instance’s pid if available, with a specified timeout.

This function is similar to receive_output() but allows specifying a custom timeout duration instead of using the default timeout.

§Arguments
  • timeout - A std::time::Duration specifying how long to wait for a message before giving up.
§Returns
  • Ok(Some(String)) - If a message is successfully received from the receiver channel.
  • Ok(None) - If no message is received before the timeout expires.
  • Err(Error) - If an error occurs during the process, such as:
    • The process pool is not initialized
    • The process with the specified PID is not found
    • The receiver channel is not available
    • The receiver channel is disconnected
§Example
// Wait for up to 5 seconds for a message
match instance.receive_output_with_timeout(std::time::Duration::from_secs(5)).await {
    Ok(Some(output)) => println!("Received output: {}", output),
    Ok(None) => println!("No output received within timeout."),
    Err(e) => eprintln!("Error receiving output: {}", e),
}
Source

pub async fn send_input(&self, input: impl Into<String>) -> Result<()>

Sends the provided input to a process associated with this instance’s PID asynchronously.

§Arguments
  • input - An input of any type that can be converted into a String. This is the data that will be sent to the respective process’s input queue.
§Returns
  • Ok(()) if the input was successfully sent or queued for sending.
  • Err - Returns an error in the following cases:
    • If the process pool is not initialized.
    • If the process associated with this PID is not found.
    • If the process was not started or its sender channel is not available.
    • If the sender channel is closed and input cannot be sent.
§Details

This function retrieves the process associated with the current instance’s pid from a global process pool. If a valid process is found:

  • The input is sent via an asynchronous channel to the process.
  • If the channel is full, the input is queued for later sending.
  • If the channel is closed, an error is returned.

The function also ensures thread safety by acquiring a lock on the process pool before attempting any operations related to the process.

§Errors

This function propagates several potential issues as errors:

  • If the process pool is uninitialized (PROCESS_POOL.get() returns None).
  • If the process associated with the PID is missing in the pool.
  • If the sender channel was never initialized or is unavailable.
  • If the sender channel is closed and no new messages can be sent.
§Example
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let manager = ProcessManager::new(1); // Assumes a struct is managing process with ID 1.
    manager.send_input("Some input").await?;
    Ok(())
}
§Note

This function expects a global process pool (PROCESS_POOL) to be properly initialized before being called. Additionally, the associated process must have a valid sender channel to accept input.

Source

pub async fn is_process_running(&self) -> bool

Checks if the process associated with the current instance is running.

This method attempts to determine if a process with the pid of the current instance exists in the global PROCESS_POOL.

§Returns
  • true - If the process with the associated pid is currently present in the global process pool.
  • false - If the process is not found in the global process pool or if the pool is not initialized.
§Async Behavior

This method is asynchronous because it acquires a lock on the PROCESS_POOL.

§Notes
  • The PROCESS_POOL must be initialized before calling this function. If PROCESS_POOL is not set, the function will return false.
  • The PROCESS_POOL is expected to be a globally accessible, asynchronous, and thread-safe data structure that tracks active processes.
§Example
let result = instance.is_process_running().await;
if result {
    println!("Process is running.");
} else {
    println!("Process is not running.");
}
Source

pub async fn shutdown(&self, timeout: Duration) -> Result<()>

Asynchronously terminates a process identified by its pid.

This method performs the following operations tailored to the target operating system:

  • Windows: Opens a handle to the process using its process ID (pid) and forcefully terminates it using the TerminateProcess function from the WinAPI.
  • Linux: Utilizes the kill system call with the SIGKILL signal to forcefully terminate the process.
§Platform-specific Notes:
  • On Windows, the process is identified and terminated using the OpenProcess and TerminateProcess functions from the WinAPI.
  • On Linux, the kill system call is used with the signal SIGKILL (9) to ensure the process is terminated.
§Errors
  • Returns an error if the process termination fails (on Linux) due to system call errors or invalid process IDs. On failure, the error contains details about the pid and the last OS error encountered.
§Safety

This method uses unsafe code blocks to interact with system APIs (libc on Linux, WinAPI on Windows). Ensure that the provided pid corresponds to a valid process, and consider the implications of forcefully terminating processes.

§Example
let process_manager = SomeProcessManager::new(pid); // Example struct containing the pid
if let Err(e) = process_manager.kill().await {
    eprintln!("Failed to terminate process: {}", e);
}

Attempts to gracefully shut down the process, falling back to forceful termination if needed.

This method first tries to gracefully shut down the process by:

  • On Linux: Sending a SIGTERM signal
  • On Windows: Sending a WM_CLOSE message to the main window

If the process doesn’t exit within the specified timeout, it will forcefully terminate the process using the kill() method.

§Arguments
  • timeout - A std::time::Duration specifying how long to wait for the process to exit gracefully before forcefully terminating it.
§Returns
  • Ok(()) - If the process was successfully shut down (either gracefully or forcefully).
  • Err(Error) - If an error occurred during the shutdown process.
§Example
// Try to shut down gracefully, waiting up to 5 seconds before force killing
if let Err(e) = process.shutdown(std::time::Duration::from_secs(5)).await {
    eprintln!("Failed to shut down process: {}", e);
}
Source

pub async fn kill(&self) -> Result<()>

Forcefully terminates the process immediately.

This method should be used as a last resort when a process needs to be terminated immediately. For a more graceful approach, consider using shutdown() first.

§Returns
  • Ok(()) - If the process was successfully terminated.
  • Err(Error) - If an error occurred during the termination process.
§Example
if let Err(e) = process.kill().await {
    eprintln!("Failed to terminate process: {}", e);
}

Trait Implementations§

Source§

impl Debug for ProcessHandle

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.