From 1ad4f2ed698f0866e5a1f1c4072d64fd70e367f4 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Sun, 28 Jul 2024 09:04:54 -0700 Subject: [PATCH] sketch out `DefaultMutex` --- Cargo.lock | 7 + maitake-sync/Cargo.toml | 2 + maitake-sync/src/blocking.rs | 2 + maitake-sync/src/blocking/default_mutex.rs | 154 +++++++++++++++++++++ maitake-sync/src/lib.rs | 2 +- 5 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 maitake-sync/src/blocking/default_mutex.rs diff --git a/Cargo.lock b/Cargo.lock index c38d4902..31960cd1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -623,6 +623,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + [[package]] name = "crossbeam-channel" version = "0.5.11" @@ -1438,6 +1444,7 @@ name = "maitake-sync" version = "0.1.2" dependencies = [ "cordyceps", + "critical-section", "futures", "futures-util", "loom", diff --git a/maitake-sync/Cargo.toml b/maitake-sync/Cargo.toml index 53b0cfa1..0a604265 100644 --- a/maitake-sync/Cargo.toml +++ b/maitake-sync/Cargo.toml @@ -23,6 +23,7 @@ rust-version = "1.61.0" [features] default = ["alloc"] alloc = ["cordyceps/alloc"] +std = ["alloc"] no-cache-pad = ["cordyceps/no-cache-pad"] core-error = [] @@ -30,6 +31,7 @@ core-error = [] mycelium-bitfield = { version = "0.1.3", path = "../bitfield" } mutex-traits = "0.999.0" cordyceps = { version = "0.3.0", path = "../cordyceps" } +critical-section = { version = "1.1", optional = true } pin-project = "1" portable-atomic = "1.2" tracing = { version = "0.1", default_features = false, optional = true } diff --git a/maitake-sync/src/blocking.rs b/maitake-sync/src/blocking.rs index 85730803..1e2f0a29 100644 --- a/maitake-sync/src/blocking.rs +++ b/maitake-sync/src/blocking.rs @@ -150,8 +150,10 @@ //! [`lock_api`]: https://crates.io/crates/lock_api //! [`critical-section`]: https://crates.io/crates/critical-section //! [`std::sync::Mutex`]: https://doc.rust-lang.org/stable/std/sync/struct.Mutex.html +mod default_mutex; pub(crate) mod mutex; pub(crate) mod rwlock; pub use self::{mutex::*, rwlock::*}; +pub use default_mutex::DefaultMutex; pub use mutex_traits::ConstInit; diff --git a/maitake-sync/src/blocking/default_mutex.rs b/maitake-sync/src/blocking/default_mutex.rs new file mode 100644 index 00000000..73f18dbb --- /dev/null +++ b/maitake-sync/src/blocking/default_mutex.rs @@ -0,0 +1,154 @@ +#[cfg(loom)] +pub use loom_impl::DefaultMutex; + +#[cfg(all(not(loom), feature = "std"))] +pub use std_impl::DefaultMutex; + +#[cfg(all(not(loom), not(feature = "std"), feature = "critical-section"))] +pub use cs_impl::DefaultMutex; + +#[cfg(all(not(loom), not(feature = "std"), not(feature = "critical-section")))] +pub use spin_impl::DefaultMutex; + +#[cfg(loom)] +mod loom_impl { + #[cfg(feature = "tracing")] + use core::panic::Location; + use mutex_traits::ScopedRawMutex; + + pub struct DefaultMutex(loom::sync::Mutex<()>); + + unsafe impl ScopedRawMutex for DefaultMutex { + #[track_caller] + fn with_lock(&self, f: impl FnOnce() -> R) -> R { + #[cfg(feature = "tracing")] + let location = Location::caller(); + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::with_lock()"); + + let guard = self.0.lock(); + tracing::debug!(%location, "DefaultMutex::with_lock() -> locked"); + + let result = f(); + drop(guard); + + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::with_lock() -> unlocked"); + + result + } + + #[track_caller] + fn try_with_lock(&self, f: impl FnOnce() -> R) -> Option { + #[cfg(feature = "tracing")] + let location = Location::caller(); + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::try_with_lock()"); + + match self.0.try_lock() { + Ok(guard) => { + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::try_with_lock() -> locked"); + + let result = f(); + drop(guard); + + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::try_with_lock() -> unlocked"); + + Some(result) + } + None => { + #[cfg(feature = "tracing")] + tracing::debug!(%location, "DefaultMutex::try_with_lock() -> already locked"); + + None + } + } + } + + fn is_locked(&self) -> bool { + self.0.try_lock().is_none() + } + } +} + +#[cfg(all(not(loom), feature = "std"))] +mod std_impl { + use mutex_traits::ScopedRawMutex; + + pub struct DefaultMutex(std::sync::Mutex<()>); + + unsafe impl ScopedRawMutex for DefaultMutex { + #[track_caller] + #[inline] + fn with_lock(&self, f: impl FnOnce() -> R) -> R { + let _guard = self.0.lock().unwrap(); + f() + } + + #[track_caller] + fn try_with_lock(&self, f: impl FnOnce() -> R) -> Option { + let _guard = self.0.try_lock().ok()?; + Some(f()) + } + + fn is_locked(&self) -> bool { + self.0.try_lock().is_none() + } + } +} + +#[cfg(all(not(loom), not(feature = "std"), feature = "critical-section"))] +mod cs_impl { + use crate::spin::Spinlock; + use mutex_traits::ScopedRawMutex; + + pub struct DefaultMutex(Spinlock); + + unsafe impl ScopedRawMutex for DefaultMutex { + #[track_caller] + #[inline] + fn with_lock(&self, f: impl FnOnce() -> R) -> R { + self.0.with_lock(|| critical_section::with(|| f())) + } + + #[track_caller] + #[inline] + fn try_with_lock(&self, f: impl FnOnce() -> R) -> Option { + self.0.try_with_lock(|| critical_section::with(|| f())) + } + + #[inline] + fn is_locked(&self) -> bool { + self.0.is_locked() + } + } +} + +#[cfg(all(not(loom), not(feature = "std"), not(feature = "critical-section")))] +mod spin_impl { + use crate::spin::Spinlock; + use mutex_traits::ScopedRawMutex; + + pub struct DefaultMutex(Spinlock); + + unsafe impl ScopedRawMutex for DefaultMutex { + #[track_caller] + #[inline] + fn with_lock(&self, f: impl FnOnce() -> R) -> R { + self.0.with_lock(|| critical_section::with(|| f())) + } + + #[track_caller] + #[inline] + fn try_with_lock(&self, f: impl FnOnce() -> R) -> Option { + self.0.try_with_lock(|| critical_section::with(|| f())) + } + + #[inline] + fn is_locked(&self) -> bool { + self.0.is_locked() + } + } +} diff --git a/maitake-sync/src/lib.rs b/maitake-sync/src/lib.rs index e30b71a2..6354efbb 100644 --- a/maitake-sync/src/lib.rs +++ b/maitake-sync/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg, doc_cfg_hide))] #![cfg_attr(docsrs, doc(cfg_hide(docsrs, loom)))] -#![cfg_attr(not(test), no_std)] +#![cfg_attr(not(any(test, feature = "std")), no_std)] #![cfg_attr(feature = "core-error", feature(error_in_core))] #![warn(missing_docs, missing_debug_implementations)]