Skip to content

Commit

Permalink
feat: Remove lifetime from NamedLockGuard and make it sendable
Browse files Browse the repository at this point in the history
Closes #8
  • Loading branch information
oblique committed Feb 26, 2024
1 parent 70f6eb9 commit 02cee67
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ keywords = ["process", "inter-process", "cross-process", "flock", "CreateMutexW"
repository = "https://github.com/oblique/named-lock"

[dependencies]
thiserror = "1.0.35"
once_cell = "1.14.0"
parking_lot = "0.12.1"
parking_lot = { version = "0.12.1", features = ["arc_lock", "send_guard"] }
thiserror = "1.0.35"

[target.'cfg(unix)'.dependencies]
libc = "0.2.132"
Expand All @@ -24,6 +24,7 @@ winapi = { version = "0.3.9", features = ["handleapi", "synchapi", "winbase", "w
widestring = "1.0.2"

[dev-dependencies]
static_assertions = "1.1.0"
uuid = { version = "1.1.2", features = ["v4"] }

[package.metadata.docs.rs]
Expand Down
52 changes: 45 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
//! ```

use once_cell::sync::Lazy;
use parking_lot::{Mutex, MutexGuard};
use parking_lot::lock_api::ArcMutexGuard;
use parking_lot::{Mutex, RawMutex};
use std::collections::HashMap;
use std::fmt;
#[cfg(unix)]
use std::path::{Path, PathBuf};
use std::sync::{Arc, Weak};
Expand Down Expand Up @@ -152,7 +154,7 @@ impl NamedLock {
///
/// If it is already locked, `Error::WouldBlock` will be returned.
pub fn try_lock(&self) -> Result<NamedLockGuard> {
let guard = self.raw.try_lock().ok_or(Error::WouldBlock)?;
let guard = self.raw.try_lock_arc().ok_or(Error::WouldBlock)?;

guard.try_lock()?;

Expand All @@ -163,7 +165,7 @@ impl NamedLock {

/// Lock named lock.
pub fn lock(&self) -> Result<NamedLockGuard> {
let guard = self.raw.lock();
let guard = self.raw.lock_arc();

guard.lock()?;

Expand All @@ -174,21 +176,28 @@ impl NamedLock {
}

/// Scoped guard that unlocks NamedLock.
#[derive(Debug)]
pub struct NamedLockGuard<'r> {
raw: MutexGuard<'r, RawNamedLock>,
pub struct NamedLockGuard {
raw: ArcMutexGuard<RawMutex, RawNamedLock>,
}

impl<'r> Drop for NamedLockGuard<'r> {
impl Drop for NamedLockGuard {
fn drop(&mut self) {
let _ = self.raw.unlock();
}
}

impl fmt::Debug for NamedLockGuard {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("NamedLockGuard").field("raw", &*self.raw).finish()
}
}

#[cfg(test)]
mod tests {
use super::*;
use static_assertions::assert_impl_all;
use std::env;
use std::fmt::Debug;
use std::process::{Child, Command};
use std::thread::sleep;
use std::time::Duration;
Expand Down Expand Up @@ -272,6 +281,29 @@ mod tests {
Ok(())
}

#[test]
fn owned_guard() -> Result<()> {
let uuid = Uuid::new_v4().as_hyphenated().to_string();
let lock1 = NamedLock::create(&uuid)?;
let lock2 = NamedLock::create(&uuid)?;

// Lock
let guard1 = lock1.try_lock()?;
assert!(matches!(lock2.try_lock(), Err(Error::WouldBlock)));

// If `NamedLockGuard` is still alive the lock must stay locked
drop(lock1);
assert!(matches!(lock2.try_lock(), Err(Error::WouldBlock)));

// Unlock by dropping the guard
drop(guard1);

// Now locking will succeed
let _guard2 = lock2.try_lock()?;

Ok(())
}

#[test]
fn invalid_names() {
assert!(matches!(NamedLock::create(""), Err(Error::EmptyName)));
Expand All @@ -291,4 +323,10 @@ mod tests {
Err(Error::InvalidCharacter)
));
}

#[test]
fn check_traits() {
assert_impl_all!(NamedLock: Debug, Send, Sync);
assert_impl_all!(NamedLockGuard: Debug, Send, Sync);
}
}

0 comments on commit 02cee67

Please sign in to comment.