Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core: Mark DefaultGuard as !Send #2488

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions tracing-core/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ use crate::{
use core::{
any::Any,
fmt,
marker::PhantomData,
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
};

Expand Down Expand Up @@ -256,12 +257,27 @@ struct State {
#[cfg(feature = "std")]
struct Entered<'a>(&'a State);

/// A trait that implements `Sync`, but not `Send`. Used with PhantomData, this
/// can mark a struct as `!Send`.
#[cfg(feature = "std")]
trait NotSend: Sync {}

/// A guard that resets the current default dispatcher to the prior
/// default dispatcher when dropped.
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
#[derive(Debug)]
pub struct DefaultGuard(Option<Dispatch>);
pub struct DefaultGuard(
Option<Dispatch>,

/// ```compile_fail
/// use tracing_core::dispatch::*;
/// trait AssertSend: Send {}
///
/// impl AssertSend for DefaultGuard {}
/// ```
PhantomData<dyn NotSend>,
);

/// Sets this dispatch as the default for the duration of a closure.
///
Expand Down Expand Up @@ -290,15 +306,24 @@ pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T {
f()
}

/// Sets the dispatch as the default dispatch for the duration of the lifetime
/// of the returned DefaultGuard
/// Sets the dispatch as the current thread's default dispatch for the duration
/// of the lifetime of the returned DefaultGuard.
///
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
///
/// **Note**: This function required the Rust standard library.
/// `no_std` users should use [`set_global_default`] instead.
/// </pre></div>
///
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
///
/// **Note**: Because this sets the dispatch for the current thread only, the
/// returned [`DefaultGuard`] does not implement [`Send`]. If the guard was sent
/// to another thread and dropped there, we'd try to restore the dispatch value
/// for the wrong thread. Thus, [`DefaultGuard`] should not be sent between
/// threads.
/// </pre></div>
#[cfg(feature = "std")]
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
Expand Down Expand Up @@ -1009,7 +1034,7 @@ impl State {
.ok();
EXISTS.store(true, Ordering::Release);
SCOPED_COUNT.fetch_add(1, Ordering::Release);
DefaultGuard(prior)
DefaultGuard(prior, PhantomData)
}

#[inline]
Expand Down Expand Up @@ -1072,6 +1097,9 @@ mod test {
metadata::{Kind, Level, Metadata},
};

trait AssertSync: Sync {}
impl AssertSync for DefaultGuard {}

#[test]
fn dispatch_is() {
let dispatcher = Dispatch::from_static(&NO_COLLECTOR);
Expand Down