From f4e08aec66b010130b7b7b048ccb987654af349b Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Wed, 28 Sep 2022 21:21:31 +0200 Subject: [PATCH] tokio: use const `Mutex::new` for globals (#5061) --- tokio/build.rs | 31 ++++++++++++++++++++++++++ tokio/src/loom/std/mutex.rs | 6 +++++ tokio/src/macros/cfg.rs | 30 +++++++++++++++++++++++++ tokio/src/process/unix/mod.rs | 19 ++++++++++++---- tokio/src/process/unix/orphan.rs | 19 ++++++++++++---- tokio/src/runtime/task/mod.rs | 38 ++++++++++++++++++++++---------- tokio/src/util/mod.rs | 10 ++------- tokio/src/util/once_cell.rs | 2 +- 8 files changed, 126 insertions(+), 29 deletions(-) diff --git a/tokio/build.rs b/tokio/build.rs index 8b47e76559e..93b05092bf9 100644 --- a/tokio/build.rs +++ b/tokio/build.rs @@ -17,9 +17,17 @@ const ADDR_OF_PROBE: &str = r#" } "#; +const CONST_MUTEX_NEW_PROBE: &str = r#" +{ + static MY_MUTEX: ::std::sync::Mutex = ::std::sync::Mutex::new(1); + *MY_MUTEX.lock().unwrap() +} +"#; + fn main() { let mut enable_const_thread_local = false; let mut enable_addr_of = false; + let mut enable_const_mutex_new = false; match AutoCfg::new() { Ok(ac) => { @@ -57,6 +65,21 @@ fn main() { enable_addr_of = true; } } + + // The `Mutex::new` method was made const in 1.63. + if ac.probe_rustc_version(1, 64) { + enable_const_mutex_new = true; + } else if ac.probe_rustc_version(1, 63) { + // This compiler claims to be 1.63, but there are some nightly + // compilers that claim to be 1.63 without supporting the + // feature. Explicitly probe to check if code using them + // compiles. + // + // The oldest nightly that supports the feature is 2022-06-20. + if ac.probe_expression(CONST_MUTEX_NEW_PROBE) { + enable_const_mutex_new = true; + } + } } Err(e) => { @@ -86,6 +109,14 @@ fn main() { autocfg::emit("tokio_no_addr_of") } + if !enable_const_mutex_new { + // To disable this feature on compilers that support it, you can + // explicitly pass this flag with the following environment variable: + // + // RUSTFLAGS="--cfg tokio_no_const_mutex_new" + autocfg::emit("tokio_no_const_mutex_new") + } + let target = ::std::env::var("TARGET").unwrap_or_default(); // We emit cfgs instead of using `target_family = "wasm"` that requires Rust 1.54. diff --git a/tokio/src/loom/std/mutex.rs b/tokio/src/loom/std/mutex.rs index 3f686e0a78e..076f7861104 100644 --- a/tokio/src/loom/std/mutex.rs +++ b/tokio/src/loom/std/mutex.rs @@ -12,6 +12,12 @@ impl Mutex { Mutex(sync::Mutex::new(t)) } + #[inline] + #[cfg(not(tokio_no_const_mutex_new))] + pub(crate) const fn const_new(t: T) -> Mutex { + Mutex(sync::Mutex::new(t)) + } + #[inline] pub(crate) fn lock(&self) -> MutexGuard<'_, T> { match self.0.lock() { diff --git a/tokio/src/macros/cfg.rs b/tokio/src/macros/cfg.rs index 287f072acde..176974593ff 100644 --- a/tokio/src/macros/cfg.rs +++ b/tokio/src/macros/cfg.rs @@ -481,6 +481,36 @@ macro_rules! cfg_not_has_atomic_u64 { } } +macro_rules! cfg_has_const_mutex_new { + ($($item:item)*) => { + $( + #[cfg(all( + not(all(loom, test)), + any( + feature = "parking_lot", + not(tokio_no_const_mutex_new) + ) + ))] + $item + )* + } +} + +macro_rules! cfg_not_has_const_mutex_new { + ($($item:item)*) => { + $( + #[cfg(not(all( + not(all(loom, test)), + any( + feature = "parking_lot", + not(tokio_no_const_mutex_new) + ) + )))] + $item + )* + } +} + macro_rules! cfg_not_wasi { ($($item:item)*) => { $( diff --git a/tokio/src/process/unix/mod.rs b/tokio/src/process/unix/mod.rs index c5a6090c0e6..3606a4899ef 100644 --- a/tokio/src/process/unix/mod.rs +++ b/tokio/src/process/unix/mod.rs @@ -34,7 +34,6 @@ use crate::process::kill::Kill; use crate::process::SpawnedChild; use crate::signal::unix::driver::Handle as SignalHandle; use crate::signal::unix::{signal, Signal, SignalKind}; -use crate::util::once_cell::OnceCell; use mio::event::Source; use mio::unix::SourceFd; @@ -64,10 +63,22 @@ impl Kill for StdChild { } } -fn get_orphan_queue() -> &'static OrphanQueueImpl { - static ORPHAN_QUEUE: OnceCell> = OnceCell::new(); +cfg_not_has_const_mutex_new! { + fn get_orphan_queue() -> &'static OrphanQueueImpl { + use crate::util::once_cell::OnceCell; - ORPHAN_QUEUE.get(OrphanQueueImpl::new) + static ORPHAN_QUEUE: OnceCell> = OnceCell::new(); + + ORPHAN_QUEUE.get(OrphanQueueImpl::new) + } +} + +cfg_has_const_mutex_new! { + fn get_orphan_queue() -> &'static OrphanQueueImpl { + static ORPHAN_QUEUE: OrphanQueueImpl = OrphanQueueImpl::new(); + + &ORPHAN_QUEUE + } } pub(crate) struct GlobalOrphanQueue; diff --git a/tokio/src/process/unix/orphan.rs b/tokio/src/process/unix/orphan.rs index b32b5d77367..864f427927e 100644 --- a/tokio/src/process/unix/orphan.rs +++ b/tokio/src/process/unix/orphan.rs @@ -43,10 +43,21 @@ pub(crate) struct OrphanQueueImpl { } impl OrphanQueueImpl { - pub(crate) fn new() -> Self { - Self { - sigchild: Mutex::new(None), - queue: Mutex::new(Vec::new()), + cfg_not_has_const_mutex_new! { + pub(crate) fn new() -> Self { + Self { + sigchild: Mutex::new(None), + queue: Mutex::new(Vec::new()), + } + } + } + + cfg_has_const_mutex_new! { + pub(crate) const fn new() -> Self { + Self { + sigchild: Mutex::const_new(None), + queue: Mutex::const_new(Vec::new()), + } } } diff --git a/tokio/src/runtime/task/mod.rs b/tokio/src/runtime/task/mod.rs index 5a2c11bd3ea..022d6523405 100644 --- a/tokio/src/runtime/task/mod.rs +++ b/tokio/src/runtime/task/mod.rs @@ -507,21 +507,35 @@ impl Id { } cfg_not_has_atomic_u64! { - pub(crate) fn next() -> Self { - use crate::util::once_cell::OnceCell; - use crate::loom::sync::Mutex; - - fn init_next_id() -> Mutex { - Mutex::new(1) + cfg_has_const_mutex_new! { + pub(crate) fn next() -> Self { + use crate::loom::sync::Mutex; + static NEXT_ID: Mutex = Mutex::const_new(1); + + let mut lock = NEXT_ID.lock(); + let id = *lock; + *lock += 1; + Self(id) } + } - static NEXT_ID: OnceCell> = OnceCell::new(); + cfg_not_has_const_mutex_new! { + pub(crate) fn next() -> Self { + use crate::util::once_cell::OnceCell; + use crate::loom::sync::Mutex; - let next_id = NEXT_ID.get(init_next_id); - let mut lock = next_id.lock(); - let id = *lock; - *lock += 1; - Self(id) + fn init_next_id() -> Mutex { + Mutex::new(1) + } + + static NEXT_ID: OnceCell> = OnceCell::new(); + + let next_id = NEXT_ID.get(init_next_id); + let mut lock = next_id.lock(); + let id = *lock; + *lock += 1; + Self(id) + } } } diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index e88c839e431..e7b645c8183 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -6,14 +6,8 @@ cfg_io_driver! { #[cfg(feature = "rt")] pub(crate) mod atomic_cell; -cfg_has_atomic_u64! { - #[cfg(any(feature = "signal", all(unix, feature = "process")))] - pub(crate) mod once_cell; -} -cfg_not_has_atomic_u64! { - #[cfg(any(feature = "rt", feature = "signal", all(unix, feature = "process")))] - pub(crate) mod once_cell; -} +#[cfg(any(feature = "rt", feature = "signal", feature = "process"))] +pub(crate) mod once_cell; #[cfg(any( // io driver uses `WakeList` directly diff --git a/tokio/src/util/once_cell.rs b/tokio/src/util/once_cell.rs index 15639e6307f..138d2a74626 100644 --- a/tokio/src/util/once_cell.rs +++ b/tokio/src/util/once_cell.rs @@ -1,4 +1,4 @@ -#![cfg_attr(loom, allow(dead_code))] +#![allow(dead_code)] use std::cell::UnsafeCell; use std::mem::MaybeUninit; use std::sync::Once;