summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml6
-rw-r--r--README.md6
-rw-r--r--examples/basic.rs5
-rw-r--r--examples/double_mutex.rs7
-rw-r--r--examples/list.rs7
-rw-r--r--src/key.rs25
-rw-r--r--src/lib.rs3
-rw-r--r--src/lockable.rs4
-rw-r--r--src/mutex.rs76
9 files changed, 38 insertions, 101 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 496b53f..30a8bf7 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,4 +9,8 @@ license = "Unlicense"
[dependencies]
thread_local = "1"
-once_cell = "1" \ No newline at end of file
+once_cell = "1"
+antidote = "1"
+lock_api = "0.4"
+parking_lot = "0.12"
+spin = "0.9"
diff --git a/README.md b/README.md
index 9888404..d0c82f8 100644
--- a/README.md
+++ b/README.md
@@ -80,12 +80,12 @@ There might be some promise in trying to prevent circular wait. There could be a
It would be nice to try to get this working without the standard library. There are a few problems with this though. For instance, this crate uses `thread_local` to allow other threads to have their own keys. Also, the only practical type of mutex that would work is a spinlock. Although, more could be implemented using the `RawMutex` trait.
-Currently, the mutex is implemented using a spinlock. We need to not do that. We could use parking lot, or mutexes from the operating system.
+Currently, the mutex is implemented using a spinlock. We need to not do that. We could use parking lot, or the standard library.
A more fair system for getting sets locks would help, but I have no clue what that looks like.
-A read-write lock would be very useful here, and maybe condvars?
+A read-write lock would be very useful here, and maybe other primitives such as condvars and once?
-Personally, I don't like mutex poisoning, but maybe it can be worked into the library if you're into that sort of thing.
+Personally, I don't like mutex poisoning, but maybe it can be worked into the library if you're into that sort of thing. For now, that can be implemented using the `poison` crate.
More types might be lockable using a `LockGuard`. \ No newline at end of file
diff --git a/examples/basic.rs b/examples/basic.rs
index 87e7a60..4ff85f8 100644
--- a/examples/basic.rs
+++ b/examples/basic.rs
@@ -1,11 +1,10 @@
use std::thread;
-use happylock::mutex::{Mutex, SpinLock};
-use happylock::ThreadKey;
+use happylock::{Mutex, ThreadKey};
const N: usize = 10;
-static DATA: SpinLock<i32> = Mutex::new(0);
+static DATA: Mutex<i32> = Mutex::new(0);
fn main() {
for _ in 0..N {
diff --git a/examples/double_mutex.rs b/examples/double_mutex.rs
index 18460e4..1469f45 100644
--- a/examples/double_mutex.rs
+++ b/examples/double_mutex.rs
@@ -1,12 +1,11 @@
use std::thread;
-use happylock::mutex::{Mutex, SpinLock};
-use happylock::{LockGuard, ThreadKey};
+use happylock::{LockGuard, Mutex, ThreadKey};
const N: usize = 10;
-static DATA_1: SpinLock<i32> = Mutex::new(0);
-static DATA_2: SpinLock<String> = Mutex::new(String::new());
+static DATA_1: Mutex<i32> = Mutex::new(0);
+static DATA_2: Mutex<String> = Mutex::new(String::new());
fn main() {
for _ in 0..N {
diff --git a/examples/list.rs b/examples/list.rs
index 448f70a..f9b8db8 100644
--- a/examples/list.rs
+++ b/examples/list.rs
@@ -1,11 +1,10 @@
use std::thread;
-use happylock::mutex::{Mutex, SpinLock};
-use happylock::{LockGuard, ThreadKey};
+use happylock::{LockGuard, Mutex, ThreadKey};
const N: usize = 10;
-static DATA: [SpinLock<usize>; 6] = [
+static DATA: [Mutex<usize>; 6] = [
Mutex::new(0),
Mutex::new(1),
Mutex::new(2),
@@ -14,7 +13,7 @@ static DATA: [SpinLock<usize>; 6] = [
Mutex::new(5),
];
-static SEED: SpinLock<u32> = Mutex::new(42);
+static SEED: Mutex<u32> = Mutex::new(42);
fn random(key: &mut ThreadKey) -> usize {
let mut seed = SEED.lock(key);
diff --git a/src/key.rs b/src/key.rs
index 92f3b99..0297bc1 100644
--- a/src/key.rs
+++ b/src/key.rs
@@ -22,12 +22,6 @@ static KEY: Lazy<ThreadLocal<AtomicLock>> = Lazy::new(ThreadLocal::new);
/// [`ThreadKey::lock`]. If the `ThreadKey` is dropped, it can be reobtained.
pub type ThreadKey = Key<'static>;
-/// A dumb lock that's just a wrapper for an [`AtomicBool`].
-#[derive(Debug, Default)]
-pub struct AtomicLock {
- is_locked: AtomicBool,
-}
-
pub struct Key<'a> {
phantom: PhantomData<*const ()>, // implement !Send and !Sync
lock: &'a AtomicLock,
@@ -76,20 +70,13 @@ impl ThreadKey {
}
}
-impl AtomicLock {
- /// Create a new unlocked `AtomicLock`.
- #[must_use]
- pub const fn new() -> Self {
- Self {
- is_locked: AtomicBool::new(false),
- }
- }
-
- /// Checks whether this `Lock` is currently locked.
- pub fn is_locked(&self) -> bool {
- self.is_locked.load(Ordering::Relaxed)
- }
+/// A dumb lock that's just a wrapper for an [`AtomicBool`].
+#[derive(Debug, Default)]
+struct AtomicLock {
+ is_locked: AtomicBool,
+}
+impl AtomicLock {
/// Attempt to lock the `AtomicLock`.
///
/// If the lock is already locked, then this'll return false. If it is
diff --git a/src/lib.rs b/src/lib.rs
index 35f7bb4..3e09572 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,4 +11,5 @@ pub mod mutex;
pub use guard::LockGuard;
pub use key::{Key, ThreadKey};
pub use lockable::Lockable;
-pub use mutex::Mutex;
+pub use mutex::ParkingMutex as Mutex;
+pub use mutex::SpinLock;
diff --git a/src/lockable.rs b/src/lockable.rs
index cda4e13..5e6d614 100644
--- a/src/lockable.rs
+++ b/src/lockable.rs
@@ -1,10 +1,12 @@
use std::mem::MaybeUninit;
-use crate::mutex::{Mutex, MutexRef, RawMutex};
+use crate::mutex::{Mutex, MutexRef};
+use lock_api::RawMutex;
mod sealed {
#[allow(clippy::wildcard_imports)]
use super::*;
+
pub trait Sealed {}
impl<'a, T, R: RawMutex + 'a> Sealed for Mutex<T, R> {}
impl<T: Sealed> Sealed for &T {}
diff --git a/src/mutex.rs b/src/mutex.rs
index 28e1786..f395055 100644
--- a/src/mutex.rs
+++ b/src/mutex.rs
@@ -1,72 +1,18 @@
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
-use crate::key::{AtomicLock, Keyable};
+use lock_api::RawMutex;
-/// A spinning mutex
-pub type SpinLock<T> = Mutex<T, RawSpin>;
-
-/// Implements a raw C-like mutex.
-///
-/// # Safety
-///
-/// It cannot be possible to lock the mutex when it is already locked.
-pub unsafe trait RawMutex {
- /// The initial value for an unlocked mutex
- const INIT: Self;
-
- /// Lock the mutex, blocking until the lock is acquired
- fn lock(&self);
-
- /// Attempt to lock the mutex without blocking.
- ///
- /// Returns `true` if successful, `false` otherwise.
- fn try_lock(&self) -> bool;
-
- /// Checks whether the mutex is currently locked or not
- fn is_locked(&self) -> bool;
-
- /// Unlock the mutex.
- ///
- /// # Safety
- ///
- /// The lock must be acquired in the current context.
- unsafe fn unlock(&self);
-}
+use crate::key::Keyable;
-/// A raw mutex which just spins
-pub struct RawSpin {
- lock: AtomicLock,
-}
-
-unsafe impl RawMutex for RawSpin {
- const INIT: Self = Self {
- lock: AtomicLock::new(),
- };
-
- fn lock(&self) {
- loop {
- std::hint::spin_loop();
-
- if let Some(key) = self.lock.try_lock() {
- std::mem::forget(key);
- return;
- }
- }
- }
-
- fn try_lock(&self) -> bool {
- self.lock.try_lock().is_some()
- }
+/// A spinning mutex
+pub type SpinLock<T> = Mutex<T, spin::Mutex<()>>;
- fn is_locked(&self) -> bool {
- self.lock.is_locked()
- }
+/// A parking lot mutex
+pub type ParkingMutex<T> = Mutex<T, parking_lot::RawMutex>;
- unsafe fn unlock(&self) {
- self.lock.force_unlock();
- }
-}
+/// A standard library mutex
+pub type StdMutex<T> = Mutex<T, antidote::Mutex<()>>;
/// A mutual exclusion primitive useful for protecting shared data, which
/// cannot deadlock.
@@ -82,7 +28,7 @@ unsafe impl RawMutex for RawSpin {
///
/// [`lock`]: `Mutex::lock`
/// [`try_lock`]: `Mutex::try_lock`
-pub struct Mutex<T: ?Sized, R> {
+pub struct Mutex<T: ?Sized, R: RawMutex> {
raw: R,
value: UnsafeCell<T>,
}
@@ -125,7 +71,7 @@ impl<'a, T: ?Sized + 'a, R: RawMutex> DerefMut for MutexRef<'a, T, R> {
///
/// [`lock`]: `Mutex::lock`
/// [`try_lock`]: `Mutex::try_lock`
-pub struct MutexGuard<'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex = RawSpin> {
+pub struct MutexGuard<'a, T: ?Sized + 'a, Key: Keyable, R: RawMutex> {
mutex: MutexRef<'a, T, R>,
_thread_key: Key,
}
@@ -290,5 +236,5 @@ impl<T: ?Sized, R: RawMutex> Mutex<T, R> {
}
}
-unsafe impl<R: Send, T: ?Sized + Send> Send for Mutex<T, R> {}
+unsafe impl<R: RawMutex + Send, T: ?Sized + Send> Send for Mutex<T, R> {}
unsafe impl<R: RawMutex + Sync, T: ?Sized + Send> Sync for Mutex<T, R> {}