From e5f1ae9703eed70ae60e552dac1e3e8ab8371a22 Mon Sep 17 00:00:00 2001 From: David Koloski Date: Fri, 6 Jan 2023 11:08:26 -0500 Subject: [PATCH] Add `set_max_level_racy` and gate `set_max_level` Calling `set_max_level` can result in a race condition on platforms that don't have an atomic compare and swap implementation. This gates `set_max_level` behind `#[cfg(atomic_cas)]` and adds a racy alternative that can be called in these situations. This mirrors the approach for `set_logger`. --- src/lib.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 732637801..f79d3116b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1215,10 +1215,38 @@ where /// /// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs. #[inline] +#[cfg(atomic_cas)] pub fn set_max_level(level: LevelFilter) { MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); } +/// A thread-unsafe version of [`set_max_level`]. +/// +/// This function is available on all platforms, even those that do not have +/// support for atomics that is needed by [`set_max_level`]. +/// +/// In almost all cases, [`set_max_level`] should be preferred. +/// +/// # Safety +/// +/// This function is only safe to call when no other level setting function is +/// called while this function still executes. +/// +/// This can be upheld by (for example) making sure that **there are no other +/// threads**, and (on embedded) that **interrupts are disabled**. +/// +/// Is is safe to use all other logging functions while this function runs +/// (including all logging macros). +/// +/// [`set_max_level`]: fn.set_max_level.html +#[inline] +pub unsafe fn set_max_level_racy(level: LevelFilter) { + // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a + // platform doesn't support `atomic_cas`, so even though this looks the same + // as `set_max_level` it may have different safety properties. + MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed); +} + /// Returns the current maximum log level. /// /// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check