pub struct Pidlock { /* private fields */ }Expand description
A pid-centered lock. A lock is considered “acquired” when a file exists on disk at the path specified, containing the process id of the locking process.
§Examples
§Basic Usage
use pidlock::Pidlock;
use std::fs;
// Create a lock in a temporary location
let temp_dir = std::env::temp_dir();
let lock_path = temp_dir.join("example.pid");
let mut lock = Pidlock::new_validated(&lock_path)?;
// Acquire the lock
lock.acquire()?;
assert!(lock.locked());
// The lock file now exists and contains our PID
assert!(lock.exists());
// Release the lock
lock.release()?;
assert!(!lock.locked());
assert!(!lock.exists()); // File is removed§Handling Lock Conflicts
use pidlock::{Pidlock, PidlockError};
use std::fs;
let temp_dir = std::env::temp_dir();
let lock_path = temp_dir.join("conflict_example.pid");
// First lock
let mut lock1 = Pidlock::new_validated(&lock_path)?;
lock1.acquire()?;
// Try to acquire the same lock from another instance
let mut lock2 = Pidlock::new_validated(&lock_path)?;
match lock2.acquire() {
Err(PidlockError::LockExists) => {
println!("Lock is already held by another process");
// This is expected behavior
}
_ => panic!("Should have failed with LockExists"),
}
// Clean up
lock1.release()?;§Automatic Cleanup on Drop
use pidlock::Pidlock;
use std::fs;
let temp_dir = std::env::temp_dir();
let lock_path = temp_dir.join("drop_example.pid");
{
let mut lock = Pidlock::new_validated(&lock_path)?;
lock.acquire()?;
assert!(lock.exists());
// Lock goes out of scope here and is automatically cleaned up
}
// Lock file should be removed by the Drop implementation
assert!(!lock_path.exists());Implementations§
Source§impl Pidlock
impl Pidlock
Sourcepub fn new(path: impl AsRef<Path>) -> Self
👎Deprecated since 0.2.0: Use new_validated for path validation and better cross-platform compatibility
pub fn new(path: impl AsRef<Path>) -> Self
new_validated for path validation and better cross-platform compatibilityCreate a new Pidlock at the provided path.
For backwards compatibility, this method does not validate the path.
Use new_validated if you want path validation.
Sourcepub fn new_validated(path: impl AsRef<Path>) -> Result<Self, PidlockError>
pub fn new_validated(path: impl AsRef<Path>) -> Result<Self, PidlockError>
Create a new Pidlock at the provided path with path validation.
This is the recommended way to create a Pidlock as it validates the path
for cross-platform compatibility and common issues.
§Arguments
path- The path where the lock file will be created. The parent directory must exist or be creatable.
§Returns
Ok(Pidlock)- A new pidlock instance ready to be acquiredErr(PidlockError::InvalidPath)- If the path is not suitable for use as a lock file
§Examples
use pidlock::Pidlock;
use std::env;
// Valid path
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("valid.pid");
let lock = Pidlock::new_validated(&lock_path)?;use pidlock::{Pidlock, PidlockError, InvalidPathError};
// Invalid path with problematic characters
let result = Pidlock::new_validated("invalid<file.pid");
match result {
Err(PidlockError::InvalidPath(InvalidPathError::ProblematicCharacter { .. })) => {
// Expected error for invalid characters
}
_ => panic!("Should have failed with InvalidPath"),
}§Errors
Returns PidlockError::InvalidPath if the path is not suitable for use as a lock file.
Sourcepub fn acquire(&mut self) -> Result<(), PidlockError>
pub fn acquire(&mut self) -> Result<(), PidlockError>
Acquire a lock.
This method attempts to create the lock file containing the current process ID. If a stale lock file exists (from a dead process), it will be automatically cleaned up.
§Returns
Ok(())- Lock was successfully acquiredErr(PidlockError::LockExists)- Another active process holds the lockErr(PidlockError::InvalidState)- Lock is already acquired or releasedErr(PidlockError::IOError)- File system error occurred
§Examples
use pidlock::{Pidlock, PidlockError};
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("acquire_example.pid");
let mut lock = Pidlock::new_validated(&lock_path)?;
match lock.acquire() {
Ok(()) => {
println!("Lock acquired successfully!");
// Do your work here...
lock.release()?;
}
Err(PidlockError::LockExists) => {
println!("Another instance is already running");
}
Err(e) => {
eprintln!("Unexpected error: {}", e);
}
}§Behavior
- State validation: Can only be called on a
Newpidlock - Stale lock cleanup: Automatically removes locks from dead processes
- Atomic creation: Uses
O_EXCL/CREATE_NEWfor atomic lock file creation - Secure permissions: Creates files with restrictive permissions (600 on Unix)
- Reliable writes: Flushes data to disk before returning success
Sourcepub fn locked(&self) -> bool
pub fn locked(&self) -> bool
Returns true when the lock is in an acquired state.
This is a local state check only - it tells you whether this Pidlock instance
has successfully acquired a lock, but doesn’t check if the lock file still exists
on disk or if another process might have interfered with it.
§Returns
true if this Pidlock instance has acquired the lock, false otherwise.
§Examples
use pidlock::Pidlock;
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("locked_example.pid");
let mut lock = Pidlock::new_validated(&lock_path)?;
// Initially not locked
assert!(!lock.locked());
// After acquiring
lock.acquire()?;
assert!(lock.locked());
// After releasing
lock.release()?;
assert!(!lock.locked());§Note
For checking if a lock file exists on disk, use exists().
For checking if a lock is held by an active process, use is_active().
Sourcepub fn exists(&self) -> bool
pub fn exists(&self) -> bool
Check if the lock file exists on disk. This is a read-only operation that doesn’t modify the lock state.
§Returns
true if the lock file exists, false otherwise.
§Examples
use pidlock::Pidlock;
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("exists_example.pid");
let lock = Pidlock::new_validated(&lock_path)?;
// Initially, no lock file exists
assert!(!lock.exists());
// Create a lock file manually to test
std::fs::write(&lock_path, "12345")?;
assert!(lock.exists());
// Clean up
std::fs::remove_file(&lock_path)?;Sourcepub fn is_active(&self) -> Result<bool, PidlockError>
pub fn is_active(&self) -> Result<bool, PidlockError>
Check if the lock file exists and if so, whether it’s stale (owned by a dead process). This is a read-only operation that doesn’t modify the lock state.
§Returns
Ok(true) if a lock exists and the owning process is still running,
Ok(false) if no lock exists or the lock is stale,
Err(_) if there was an error determining the lock status.
§Examples
use pidlock::Pidlock;
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("is_active_example.pid");
let lock = Pidlock::new_validated(&lock_path)?;
match lock.is_active()? {
true => println!("Lock is held by an active process"),
false => println!("No active lock found"),
}
// Test with our own process
std::fs::write(&lock_path, std::process::id().to_string())?;
assert!(lock.is_active()?); // Our process is definitely active
// Clean up
std::fs::remove_file(&lock_path)?;Sourcepub fn release(&mut self) -> Result<(), PidlockError>
pub fn release(&mut self) -> Result<(), PidlockError>
Release the lock.
This method removes the lock file from disk and transitions the lock to the Released state.
Once released, the lock cannot be re-acquired (create a new Pidlock instance instead).
§Returns
Ok(())- Lock was successfully releasedErr(PidlockError::InvalidState)- Lock is not currently acquiredErr(PidlockError::IOError)- File system error occurred during removal
§Examples
use pidlock::Pidlock;
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("release_example.pid");
let mut lock = Pidlock::new_validated(&lock_path)?;
lock.acquire()?;
// Explicitly release the lock
lock.release()?;
// Lock file should be gone
assert!(!lock.exists());
assert!(!lock.locked());§Note
Releasing a lock is optional - the Drop implementation will automatically
clean up acquired locks when the Pidlock goes out of scope. However, explicit
release is recommended for better error handling and immediate cleanup.
Sourcepub fn get_owner(&self) -> Result<Option<i32>, PidlockError>
pub fn get_owner(&self) -> Result<Option<i32>, PidlockError>
Gets the owner of this lockfile, returning the PID if it exists and is valid.
This method reads the lock file and attempts to parse the PID contained within. If the PID is invalid, the process no longer exists, or the file is corrupted, the lock file will be automatically cleaned up.
§Returns
Ok(Some(pid))- Lock file exists and contains a valid PID for an active processOk(None)- No lock file exists, or the lock file was invalid and cleaned upErr(_)- I/O error occurred while reading or cleaning up the file
§Examples
use pidlock::Pidlock;
use std::env;
let temp_dir = env::temp_dir();
let lock_path = temp_dir.join("owner_example.pid");
let mut lock = Pidlock::new_validated(&lock_path)?;
// No owner initially
assert_eq!(lock.get_owner()?, None);
// After acquiring, we should be the owner
lock.acquire()?;
if let Some(owner_pid) = lock.get_owner()? {
println!("Lock is owned by PID: {}", owner_pid);
assert_eq!(owner_pid, std::process::id() as i32);
}
lock.release()?;§Behavior
This method will automatically clean up lock files in the following cases:
- File contains non-numeric content
- File contains a PID that doesn’t correspond to a running process
- File contains a PID outside the valid range for the platform
- File is empty or contains only whitespace
Trait Implementations§
Source§impl Drop for Pidlock
impl Drop for Pidlock
Source§fn drop(&mut self)
fn drop(&mut self)
Automatically release the lock when the Pidlock goes out of scope. This ensures that lock files are cleaned up even if the process panics or exits unexpectedly while holding a lock.
Note: This implementation uses a best-effort approach. If cleanup fails,
we don’t panic because that could mask the original panic that triggered
the drop. Errors are logged when the log feature is enabled.