forked from tokio-rs/tracing
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
core: fix warnings when compiling without
std
(tokio-rs#2022)
Currently, compiling `tracing-core` with `default-features = false` (i.e. for `no_std` targets) emits a few warnings. This is due to the spinlock implementation's use of the deprecated `atomic::spin_loop_hint` function (renamed to `hint::spin_loop`), and the use of deprecated `compare_and_swap` instead of `compare_exchange` methods. Now that our MSRV is 1.49 (the version in which `hint::spin_loop` was stabilized), we can fix these warnings. This branch replaces the deprecated APIs. Also, I noticed that one of the tests emits unused-imports warnings with `--no-default-features`. This is because the actual tests are feature flagged to require `std`, but the module itself doesn't, so the imports are just hanging out and not getting used for anything. I went ahead and fixed that as well. Signed-off-by: Eliza Weisman <[email protected]>
- Loading branch information
Showing
2 changed files
with
118 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
use core::cell::UnsafeCell; | ||
use core::default::Default; | ||
use core::fmt; | ||
use core::hint; | ||
use core::marker::Sync; | ||
use core::ops::{Deref, DerefMut, Drop}; | ||
use core::option::Option::{self, None, Some}; | ||
use core::sync::atomic::{AtomicBool, Ordering}; | ||
|
||
/// This type provides MUTual EXclusion based on spinning. | ||
pub(crate) struct Mutex<T: ?Sized> { | ||
lock: AtomicBool, | ||
data: UnsafeCell<T>, | ||
} | ||
|
||
/// A guard to which the protected data can be accessed | ||
/// | ||
/// When the guard falls out of scope it will release the lock. | ||
#[derive(Debug)] | ||
pub(crate) struct MutexGuard<'a, T: ?Sized> { | ||
lock: &'a AtomicBool, | ||
data: &'a mut T, | ||
} | ||
|
||
// Same unsafe impls as `std::sync::Mutex` | ||
unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {} | ||
unsafe impl<T: ?Sized + Send> Send for Mutex<T> {} | ||
|
||
impl<T> Mutex<T> { | ||
/// Creates a new spinlock wrapping the supplied data. | ||
pub(crate) const fn new(user_data: T) -> Mutex<T> { | ||
Mutex { | ||
lock: AtomicBool::new(false), | ||
data: UnsafeCell::new(user_data), | ||
} | ||
} | ||
} | ||
|
||
impl<T: ?Sized> Mutex<T> { | ||
fn obtain_lock(&self) { | ||
while self | ||
.lock | ||
.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed) | ||
.is_err() | ||
{ | ||
// Wait until the lock looks unlocked before retrying | ||
while self.lock.load(Ordering::Relaxed) { | ||
hint::spin_loop(); | ||
} | ||
} | ||
} | ||
|
||
/// Locks the spinlock and returns a guard. | ||
/// | ||
/// The returned value may be dereferenced for data access | ||
/// and the lock will be dropped when the guard falls out of scope. | ||
pub(crate) fn lock(&self) -> MutexGuard<'_, T> { | ||
self.obtain_lock(); | ||
MutexGuard { | ||
lock: &self.lock, | ||
data: unsafe { &mut *self.data.get() }, | ||
} | ||
} | ||
|
||
/// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns | ||
/// a guard within Some. | ||
pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> { | ||
if self | ||
.lock | ||
.compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed) | ||
.is_ok() | ||
{ | ||
Some(MutexGuard { | ||
lock: &self.lock, | ||
data: unsafe { &mut *self.data.get() }, | ||
}) | ||
} else { | ||
None | ||
} | ||
} | ||
} | ||
|
||
impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self.try_lock() { | ||
Some(guard) => write!(f, "Mutex {{ data: ") | ||
.and_then(|()| (&*guard).fmt(f)) | ||
.and_then(|()| write!(f, "}}")), | ||
None => write!(f, "Mutex {{ <locked> }}"), | ||
} | ||
} | ||
} | ||
|
||
impl<T: ?Sized + Default> Default for Mutex<T> { | ||
fn default() -> Mutex<T> { | ||
Mutex::new(Default::default()) | ||
} | ||
} | ||
|
||
impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> { | ||
type Target = T; | ||
fn deref<'b>(&'b self) -> &'b T { | ||
&*self.data | ||
} | ||
} | ||
|
||
impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> { | ||
fn deref_mut<'b>(&'b mut self) -> &'b mut T { | ||
&mut *self.data | ||
} | ||
} | ||
|
||
impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> { | ||
/// The dropping of the MutexGuard will release the lock it was created from. | ||
fn drop(&mut self) { | ||
self.lock.store(false, Ordering::Release); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters