summaryrefslogtreecommitdiff
path: root/src/lock.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lock.rs')
-rw-r--r--src/lock.rs44
1 files changed, 41 insertions, 3 deletions
diff --git a/src/lock.rs b/src/lock.rs
index 45dd1ad..fb74f25 100644
--- a/src/lock.rs
+++ b/src/lock.rs
@@ -6,18 +6,56 @@ pub struct Lock {
is_locked: AtomicBool,
}
+#[derive(Debug)]
+pub struct Key<'a> {
+ lock: &'a Lock,
+}
+
+impl<'a> Key<'a> {
+ fn new(lock: &'a Lock) -> Self {
+ Self { lock }
+ }
+}
+
+impl<'a> Drop for Key<'a> {
+ fn drop(&mut self) {
+ // safety: this key will soon be destroyed
+ unsafe { self.lock.force_unlock() }
+ }
+}
+
impl Lock {
+ /// Create a new unlocked `Lock`.
pub const fn new() -> Self {
Self {
is_locked: AtomicBool::new(false),
}
}
- pub fn try_lock(&self) -> bool {
- !self.is_locked.fetch_or(true, Ordering::Acquire)
+ /// Attempt to lock the `Lock`.
+ ///
+ /// If the lock is already locked, then this'll return false. If it is
+ /// unlocked, it'll return true. If the lock is currently unlocked, then it
+ /// will be locked after this function is called.
+ ///
+ /// This is not a fair lock. It is not recommended to call this function
+ /// repeatedly in a loop.
+ pub fn try_lock(&self) -> Option<Key> {
+ (!self.is_locked.fetch_or(true, Ordering::Acquire)).then_some(Key::new(self))
}
- pub fn unlock(&self) {
+ /// Unlock the lock, without a key.
+ ///
+ /// # Safety
+ ///
+ /// This should only be called if the key to the lock has been "lost". That
+ /// means the program no longer has a reference to the key, but it has not
+ /// been dropped.
+ unsafe fn force_unlock(&self) {
self.is_locked.store(false, Ordering::Release)
}
+
+ pub fn unlock(key: Key) {
+ drop(key)
+ }
}