diff --git a/tracing-subscriber/src/filter/mod.rs b/tracing-subscriber/src/filter/mod.rs index 52ae6cd8..95c7f628 100644 --- a/tracing-subscriber/src/filter/mod.rs +++ b/tracing-subscriber/src/filter/mod.rs @@ -171,15 +171,19 @@ impl Layer for Filter { fn enabled(&self, metadata: &Metadata<'_>, _: Context<'_, S>) -> bool { let level = metadata.level(); - for filter in self.scope.get().iter() { - if filter >= level { - return true; - } - } + self.scope + .with(|scope| { + for filter in scope.iter() { + if filter >= level { + return true; + } + } - // TODO: other filters... + // TODO: other filters... - false + false + }) + .unwrap_or(false) } fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, _: Context<'_, S>) { @@ -201,13 +205,13 @@ impl Layer for Filter { // that to allow changing the filter while a span is already entered. // But that might be much less efficient... if let Some(span) = try_lock!(self.by_id.read()).get(id) { - self.scope.get().push(span.level()); + self.scope.with(|scope| scope.push(span.level())); } } fn on_exit(&self, id: &span::Id, _: Context<'_, S>) { if self.cares_about_span(id) { - self.scope.get().pop(); + self.scope.with(|scope| scope.pop()); } } diff --git a/tracing-subscriber/src/lib.rs b/tracing-subscriber/src/lib.rs index 4a06265a..873ae681 100644 --- a/tracing-subscriber/src/lib.rs +++ b/tracing-subscriber/src/lib.rs @@ -98,17 +98,19 @@ impl CurrentSpan { /// Returns the [`Id`](::Id) of the span in which the current thread is /// executing, or `None` if it is not inside of a span. pub fn id(&self) -> Option { - self.current.get().last().cloned() + self.current.with(|current| current.last().cloned())? } /// Records that the current thread has entered the span with the provided ID. pub fn enter(&self, span: Id) { - self.current.get().push(span) + self.current.with(|current| current.push(span)); } /// Records that the current thread has exited a span. pub fn exit(&self) { - self.current.get().pop(); + self.current.with(|current| { + let _ = current.pop(); + }); } } diff --git a/tracing-subscriber/src/thread.rs b/tracing-subscriber/src/thread.rs index 2816a5cf..3b563c26 100644 --- a/tracing-subscriber/src/thread.rs +++ b/tracing-subscriber/src/thread.rs @@ -1,14 +1,11 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; use std::{ cell::{Cell, UnsafeCell}, fmt, marker::PhantomData, }; -use std::{ - ops::{Deref, DerefMut}, - sync::atomic::{AtomicUsize, Ordering}, -}; -use crossbeam_utils::sync::{ShardedLock, ShardedLockReadGuard}; +use crossbeam_utils::sync::ShardedLock; pub(crate) struct Local { inner: ShardedLock>, @@ -16,14 +13,6 @@ pub(crate) struct Local { type Inner = Vec>>; -pub(crate) struct LocalGuard<'a, T> { - inner: *mut T, - /// Hold the read guard for the lifetime of this guard. We're not actually - /// accessing the data behind that guard, but holding the read lock will - /// keep another thread from reallocating the vec. - _lock: ShardedLockReadGuard<'a, Inner>, -} - /// Uniquely identifies a thread. #[repr(transparent)] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -46,26 +35,25 @@ impl Local { } } - /// Returns a `LocalGuard` that dereferences to the local data for the - /// current thread. If no local data exists, the provided function is - /// invoked and the result is inserted. - pub(crate) fn get_or_else<'a>(&'a self, new: impl FnOnce() -> T) -> LocalGuard<'a, T> { + pub(crate) fn with_or_else( + &self, + new: impl FnOnce() -> T, + f: impl FnOnce(&mut T) -> O, + ) -> Option { let i = Id::current().as_usize(); - if let Some(guard) = self.try_get(i) { - guard - } else { - self.new_thread(i, new); - self.try_get(i).expect("data was just inserted") - } + let mut f = Some(f); + self.try_with_index(i, |item| f.take().expect("called twice")(item)) + .or_else(move || { + self.new_thread(i, new); + self.try_with_index(i, |item| f.take().expect("called twice")(item)) + }) } - // Returns a `LocalGuard` for the local data for this thread, or `None` if - // no local data has been inserted. - fn try_get<'a>(&'a self, i: usize) -> Option> { + fn try_with_index(&self, i: usize, f: impl FnOnce(&mut T) -> O) -> Option { let lock = try_lock!(self.inner.read(), else return None); let slot = lock.get(i)?.as_ref()?; - let inner = slot.get(); - Some(LocalGuard { inner, _lock: lock }) + let item = unsafe { &mut *slot.get() }; + Some(f(item)) } #[cold] @@ -78,10 +66,9 @@ impl Local { } impl Local { - /// Returns a `LocalGuard` that dereferences to the local data for the - /// current thread. If no local data exists, the default value is inserted. - pub(crate) fn get<'a>(&'a self) -> LocalGuard<'a, T> { - self.get_or_else(T::default) + #[inline] + pub(crate) fn with(&self, f: impl FnOnce(&mut T) -> O) -> Option { + self.with_or_else(T::default, f) } } @@ -90,55 +77,18 @@ unsafe impl Sync for Local {} impl fmt::Debug for Local { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let id = Id::current(); - match self.try_get(id.as_usize()) { - Some(local) => f - .debug_struct("Local") + self.try_with_index(id.as_usize(), |local| { + f.debug_struct("Local") .field("thread", &id) .field("local", &*local) - .finish(), - None => f - .debug_struct("Local") + .finish() + }) + .unwrap_or_else(|| { + f.debug_struct("Local") .field("thread", &id) .field("local", &format_args!("")) - .finish(), - } - } -} - -// === impl LocalGuard === - -impl<'a, T> Deref for LocalGuard<'a, T> { - type Target = T; - #[inline] - fn deref(&self) -> &T { - unsafe { - // this is safe, as the `Local` only allows access to each slot - // from a single thread. - &*self.inner - } - } -} - -impl<'a, T> DerefMut for LocalGuard<'a, T> { - #[inline] - fn deref_mut(&mut self) -> &mut T { - unsafe { - // this is safe, as the `Local` only allows access to each slot - // from a single thread. - &mut *self.inner - } - } -} - -impl<'a, T: fmt::Debug> fmt::Debug for LocalGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.deref().fmt(f) - } -} - -impl<'a, T: fmt::Display> fmt::Display for LocalGuard<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.deref().fmt(f) + .finish() + }) } }