diff --git a/.circleci/config.yml b/.circleci/config.yml index d8d8ca672ec..bf073e2e555 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,7 +6,7 @@ jobs: resource_class: arm.medium environment: # Change to pin rust version - RUST_STABLE: stable + RUST_STABLE: 1.62.1 steps: - checkout - run: @@ -22,4 +22,4 @@ jobs: workflows: ci: jobs: - - test-arm \ No newline at end of file + - test-arm diff --git a/.cirrus.yml b/.cirrus.yml index 1adc492ad6c..5a8fb83f805 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -1,7 +1,7 @@ freebsd_instance: image: freebsd-12-3-release-amd64 env: - RUST_STABLE: stable + RUST_STABLE: 1.62.1 RUST_NIGHTLY: nightly-2022-03-21 RUSTFLAGS: -D warnings diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 78bdfbc7e9b..c51c730dcf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,9 @@ env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 # Change to specific Rust release to pin - rust_stable: stable + rust_stable: 1.62.1 rust_nightly: nightly-2022-04-18 - rust_clippy: 1.52.0 + rust_clippy: 1.56.0 # When updating this, also update: # - README.md # - tokio/README.md @@ -295,8 +295,9 @@ jobs: toolchain: ${{ env.rust_min }} override: true - uses: Swatinem/rust-cache@v1 - - name: "test --workspace --all-features" - run: cargo check --workspace --all-features + - name: "test --all-features" + run: cargo check --all-features + working-directory: tokio minimal-versions: name: minimal-versions diff --git a/.github/workflows/loom.yml b/.github/workflows/loom.yml index 760b6347b5c..557f6ab9ccc 100644 --- a/.github/workflows/loom.yml +++ b/.github/workflows/loom.yml @@ -11,7 +11,7 @@ env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 # Change to specific Rust release to pin - rust_stable: stable + rust_stable: 1.62.1 jobs: loom: diff --git a/.github/workflows/stress-test.yml b/.github/workflows/stress-test.yml index bcbede18efd..d85d6034088 100644 --- a/.github/workflows/stress-test.yml +++ b/.github/workflows/stress-test.yml @@ -9,7 +9,7 @@ env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 # Change to specific Rust release to pin - rust_stable: stable + rust_stable: 1.62.1 jobs: stess-test: diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d2aca69d84a..a6f6eda3267 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -21,7 +21,6 @@ serde_derive = "1.0" serde_json = "1.0" httparse = "1.0" httpdate = "1.0" -once_cell = "1.5.2" rand = "0.8.3" [target.'cfg(windows)'.dev-dependencies.winapi] @@ -71,11 +70,6 @@ path = "udp-codec.rs" name = "tinyhttp" path = "tinyhttp.rs" -[[example]] -name = "custom-executor" -path = "custom-executor.rs" - - [[example]] name = "custom-executor-tokio-context" path = "custom-executor-tokio-context.rs" diff --git a/tokio/CHANGELOG.md b/tokio/CHANGELOG.md index 3758fc44f32..d2f097db5b8 100644 --- a/tokio/CHANGELOG.md +++ b/tokio/CHANGELOG.md @@ -116,6 +116,13 @@ This release fixes a bug in `Notified::enable`. ([#4747]) [#4729]: https://github.com/tokio-rs/tokio/pull/4729 [#4739]: https://github.com/tokio-rs/tokio/pull/4739 +# 1.18.3 (September 27, 2022) + +This release removes the dependency on the `once_cell` crate to restore the MSRV +of the 1.18.x LTS release. ([#5048]) + +[#5048]: https://github.com/tokio-rs/tokio/pull/5048 + # 1.18.2 (May 5, 2022) Add missing features for the `winapi` dependency. ([#4663]) diff --git a/tokio/Cargo.toml b/tokio/Cargo.toml index 661962494dd..db51686aca5 100644 --- a/tokio/Cargo.toml +++ b/tokio/Cargo.toml @@ -61,7 +61,6 @@ net = [ ] process = [ "bytes", - "once_cell", "libc", "mio/os-poll", "mio/os-ext", @@ -75,13 +74,12 @@ process = [ "winapi/minwindef", ] # Includes basic task execution capabilities -rt = ["once_cell"] +rt = [] rt-multi-thread = [ "num_cpus", "rt", ] signal = [ - "once_cell", "libc", "mio/os-poll", "mio/net", @@ -110,7 +108,6 @@ pin-project-lite = "0.2.0" # Everything else is optional... bytes = { version = "1.0.0", optional = true } -once_cell = { version = "1.5.2", optional = true } memchr = { version = "2.2", optional = true } mio = { version = "0.8.1", optional = true } socket2 = { version = "0.4.4", optional = true, features = [ "all" ] } diff --git a/tokio/src/loom/std/parking_lot.rs b/tokio/src/loom/std/parking_lot.rs index 034a0ce69a5..e3af258d116 100644 --- a/tokio/src/loom/std/parking_lot.rs +++ b/tokio/src/loom/std/parking_lot.rs @@ -52,7 +52,7 @@ impl Mutex { } #[inline] - #[cfg(all(feature = "parking_lot", not(all(loom, test)),))] + #[cfg(all(feature = "parking_lot", not(all(loom, test))))] #[cfg_attr(docsrs, doc(cfg(all(feature = "parking_lot",))))] pub(crate) const fn const_new(t: T) -> Mutex { Mutex(PhantomData, parking_lot::const_mutex(t)) diff --git a/tokio/src/process/unix/mod.rs b/tokio/src/process/unix/mod.rs index 576fe6cb47f..0bc4e78503f 100644 --- a/tokio/src/process/unix/mod.rs +++ b/tokio/src/process/unix/mod.rs @@ -34,10 +34,10 @@ 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; -use once_cell::sync::Lazy; use std::fmt; use std::fs::File; use std::future::Future; @@ -64,25 +64,29 @@ impl Kill for StdChild { } } -static ORPHAN_QUEUE: Lazy> = Lazy::new(OrphanQueueImpl::new); +fn get_orphan_queue() -> &'static OrphanQueueImpl { + static ORPHAN_QUEUE: OnceCell> = OnceCell::new(); + + ORPHAN_QUEUE.get(OrphanQueueImpl::new) +} pub(crate) struct GlobalOrphanQueue; impl fmt::Debug for GlobalOrphanQueue { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - ORPHAN_QUEUE.fmt(fmt) + get_orphan_queue().fmt(fmt) } } impl GlobalOrphanQueue { fn reap_orphans(handle: &SignalHandle) { - ORPHAN_QUEUE.reap_orphans(handle) + get_orphan_queue().reap_orphans(handle) } } impl OrphanQueue for GlobalOrphanQueue { fn push_orphan(&self, orphan: StdChild) { - ORPHAN_QUEUE.push_orphan(orphan) + get_orphan_queue().push_orphan(orphan) } } diff --git a/tokio/src/runtime/task/mod.rs b/tokio/src/runtime/task/mod.rs index e73b3f35a54..973eb7eb12c 100644 --- a/tokio/src/runtime/task/mod.rs +++ b/tokio/src/runtime/task/mod.rs @@ -505,11 +505,17 @@ impl Id { cfg_not_has_atomic_u64! { pub(crate) fn next() -> Self { - use once_cell::sync::Lazy; + use crate::util::once_cell::OnceCell; use crate::loom::sync::Mutex; - static NEXT_ID: Lazy> = Lazy::new(|| Mutex::new(1)); - let mut lock = NEXT_ID.lock(); + 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/signal/registry.rs b/tokio/src/signal/registry.rs index 7795ca8dfa8..e1b3d108767 100644 --- a/tokio/src/signal/registry.rs +++ b/tokio/src/signal/registry.rs @@ -1,10 +1,9 @@ #![allow(clippy::unit_arg)] use crate::signal::os::{OsExtraData, OsStorage}; - use crate::sync::watch; +use crate::util::once_cell::OnceCell; -use once_cell::sync::Lazy; use std::ops; use std::pin::Pin; use std::sync::atomic::{AtomicBool, Ordering}; @@ -152,19 +151,25 @@ impl Globals { } } +fn globals_init() -> Globals +where + OsExtraData: 'static + Send + Sync + Init, + OsStorage: 'static + Send + Sync + Init, +{ + Globals { + extra: OsExtraData::init(), + registry: Registry::new(OsStorage::init()), + } +} + pub(crate) fn globals() -> Pin<&'static Globals> where OsExtraData: 'static + Send + Sync + Init, OsStorage: 'static + Send + Sync + Init, { - static GLOBALS: Lazy>> = Lazy::new(|| { - Box::pin(Globals { - extra: OsExtraData::init(), - registry: Registry::new(OsStorage::init()), - }) - }); - - GLOBALS.as_ref() + static GLOBALS: OnceCell = OnceCell::new(); + + Pin::new(GLOBALS.get(globals_init)) } #[cfg(all(test, not(loom)))] diff --git a/tokio/src/util/mod.rs b/tokio/src/util/mod.rs index 618f5543802..0d538c147c2 100644 --- a/tokio/src/util/mod.rs +++ b/tokio/src/util/mod.rs @@ -6,6 +6,15 @@ 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( // io driver uses `WakeList` directly feature = "net", diff --git a/tokio/src/util/once_cell.rs b/tokio/src/util/once_cell.rs new file mode 100644 index 00000000000..15639e6307f --- /dev/null +++ b/tokio/src/util/once_cell.rs @@ -0,0 +1,70 @@ +#![cfg_attr(loom, allow(dead_code))] +use std::cell::UnsafeCell; +use std::mem::MaybeUninit; +use std::sync::Once; + +pub(crate) struct OnceCell { + once: Once, + value: UnsafeCell>, +} + +unsafe impl Send for OnceCell {} +unsafe impl Sync for OnceCell {} + +impl OnceCell { + pub(crate) const fn new() -> Self { + Self { + once: Once::new(), + value: UnsafeCell::new(MaybeUninit::uninit()), + } + } + + /// Get the value inside this cell, intiailizing it using the provided + /// function if necessary. + /// + /// If the `init` closure panics, then the `OnceCell` is poisoned and all + /// future calls to `get` will panic. + #[inline] + pub(crate) fn get(&self, init: fn() -> T) -> &T { + if !self.once.is_completed() { + self.do_init(init); + } + + // Safety: The `std::sync::Once` guarantees that we can only reach this + // line if a `call_once` closure has been run exactly once and without + // panicking. Thus, the value is not uninitialized. + // + // There is also no race because the only `&self` method that modifies + // `value` is `do_init`, but if the `call_once` closure is still + // running, then no thread has gotten past the `call_once`. + unsafe { &*(self.value.get() as *const T) } + } + + #[cold] + fn do_init(&self, init: fn() -> T) { + let value_ptr = self.value.get() as *mut T; + + self.once.call_once(|| { + let set_to = init(); + + // Safety: The `std::sync::Once` guarantees that this initialization + // will run at most once, and that no thread can get past the + // `call_once` until it has run exactly once. Thus, we have + // exclusive access to `value`. + unsafe { + std::ptr::write(value_ptr, set_to); + } + }); + } +} + +impl Drop for OnceCell { + fn drop(&mut self) { + if self.once.is_completed() { + let value_ptr = self.value.get() as *mut T; + unsafe { + std::ptr::drop_in_place(value_ptr); + } + } + } +}