Skip to content

Commit 05e6614

Browse files
authored
chore: don't use once_cell for 1.18.x LTS release (#5048)
The latest release of once_cell has an MSRV that is incompatible with the MSRV of the 1.18.x LTS release.
1 parent 7aa1566 commit 05e6614

File tree

13 files changed

+125
-39
lines changed

13 files changed

+125
-39
lines changed

.circleci/config.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ jobs:
55
image: ubuntu-2004:202101-01
66
resource_class: arm.medium
77
environment:
8-
# Change to pin rust versino
9-
RUST_STABLE: stable
8+
# Change to pin rust version
9+
RUST_STABLE: 1.60.0
1010
steps:
1111
- checkout
1212
- run:
@@ -22,4 +22,4 @@ jobs:
2222
workflows:
2323
ci:
2424
jobs:
25-
- test-arm
25+
- test-arm

.cirrus.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
freebsd_instance:
22
image: freebsd-12-3-release-amd64
33
env:
4-
RUST_STABLE: stable
4+
RUST_STABLE: 1.60.0
55
RUST_NIGHTLY: nightly-2022-03-21
66
RUSTFLAGS: -D warnings
77

.github/workflows/ci.yml

+5-4
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ env:
1010
RUSTFLAGS: -Dwarnings
1111
RUST_BACKTRACE: 1
1212
# Change to specific Rust release to pin
13-
rust_stable: stable
13+
rust_stable: 1.60.0
1414
rust_nightly: nightly-2022-03-21
15-
rust_clippy: 1.52.0
15+
rust_clippy: 1.56.0
1616
rust_min: 1.49.0
1717

1818
defaults:
@@ -284,8 +284,9 @@ jobs:
284284
toolchain: ${{ env.rust_min }}
285285
override: true
286286
- uses: Swatinem/rust-cache@v1
287-
- name: "test --workspace --all-features"
288-
run: cargo check --workspace --all-features
287+
- name: "test --all-features"
288+
run: cargo check --all-features
289+
working-directory: tokio
289290

290291
minimal-versions:
291292
name: minimal-versions

.github/workflows/loom.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ env:
1111
RUSTFLAGS: -Dwarnings
1212
RUST_BACKTRACE: 1
1313
# Change to specific Rust release to pin
14-
rust_stable: stable
14+
rust_stable: 1.60.0
1515

1616
jobs:
1717
loom:

.github/workflows/stress-test.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ env:
99
RUSTFLAGS: -Dwarnings
1010
RUST_BACKTRACE: 1
1111
# Change to specific Rust release to pin
12-
rust_stable: stable
12+
rust_stable: 1.60.0
1313

1414
jobs:
1515
stess-test:

examples/Cargo.toml

-6
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ serde_derive = "1.0"
2121
serde_json = "1.0"
2222
httparse = "1.0"
2323
httpdate = "1.0"
24-
once_cell = "1.5.2"
2524
rand = "0.8.3"
2625

2726
[target.'cfg(windows)'.dev-dependencies.winapi]
@@ -71,11 +70,6 @@ path = "udp-codec.rs"
7170
name = "tinyhttp"
7271
path = "tinyhttp.rs"
7372

74-
[[example]]
75-
name = "custom-executor"
76-
path = "custom-executor.rs"
77-
78-
7973
[[example]]
8074
name = "custom-executor-tokio-context"
8175
path = "custom-executor-tokio-context.rs"

tokio/Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ net = [
5656
]
5757
process = [
5858
"bytes",
59-
"once_cell",
6059
"libc",
6160
"mio/os-poll",
6261
"mio/os-ext",
@@ -65,13 +64,12 @@ process = [
6564
"winapi/threadpoollegacyapiset",
6665
]
6766
# Includes basic task execution capabilities
68-
rt = ["once_cell"]
67+
rt = []
6968
rt-multi-thread = [
7069
"num_cpus",
7170
"rt",
7271
]
7372
signal = [
74-
"once_cell",
7573
"libc",
7674
"mio/os-poll",
7775
"mio/net",
@@ -95,7 +93,6 @@ pin-project-lite = "0.2.0"
9593

9694
# Everything else is optional...
9795
bytes = { version = "1.0.0", optional = true }
98-
once_cell = { version = "1.5.2", optional = true }
9996
memchr = { version = "2.2", optional = true }
10097
mio = { version = "0.8.1", optional = true }
10198
socket2 = { version = "0.4.4", optional = true, features = [ "all" ] }

tokio/src/loom/std/parking_lot.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<T> Mutex<T> {
5252
}
5353

5454
#[inline]
55-
#[cfg(all(feature = "parking_lot", not(all(loom, test)),))]
55+
#[cfg(all(feature = "parking_lot", not(all(loom, test))))]
5656
#[cfg_attr(docsrs, doc(cfg(all(feature = "parking_lot",))))]
5757
pub(crate) const fn const_new(t: T) -> Mutex<T> {
5858
Mutex(PhantomData, parking_lot::const_mutex(t))

tokio/src/process/unix/mod.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ use crate::process::kill::Kill;
3434
use crate::process::SpawnedChild;
3535
use crate::signal::unix::driver::Handle as SignalHandle;
3636
use crate::signal::unix::{signal, Signal, SignalKind};
37+
use crate::util::once_cell::OnceCell;
3738

3839
use mio::event::Source;
3940
use mio::unix::SourceFd;
40-
use once_cell::sync::Lazy;
4141
use std::fmt;
4242
use std::fs::File;
4343
use std::future::Future;
@@ -64,25 +64,29 @@ impl Kill for StdChild {
6464
}
6565
}
6666

67-
static ORPHAN_QUEUE: Lazy<OrphanQueueImpl<StdChild>> = Lazy::new(OrphanQueueImpl::new);
67+
fn get_orphan_queue() -> &'static OrphanQueueImpl<StdChild> {
68+
static ORPHAN_QUEUE: OnceCell<OrphanQueueImpl<StdChild>> = OnceCell::new();
69+
70+
ORPHAN_QUEUE.get(OrphanQueueImpl::new)
71+
}
6872

6973
pub(crate) struct GlobalOrphanQueue;
7074

7175
impl fmt::Debug for GlobalOrphanQueue {
7276
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
73-
ORPHAN_QUEUE.fmt(fmt)
77+
get_orphan_queue().fmt(fmt)
7478
}
7579
}
7680

7781
impl GlobalOrphanQueue {
7882
fn reap_orphans(handle: &SignalHandle) {
79-
ORPHAN_QUEUE.reap_orphans(handle)
83+
get_orphan_queue().reap_orphans(handle)
8084
}
8185
}
8286

8387
impl OrphanQueue<StdChild> for GlobalOrphanQueue {
8488
fn push_orphan(&self, orphan: StdChild) {
85-
ORPHAN_QUEUE.push_orphan(orphan)
89+
get_orphan_queue().push_orphan(orphan)
8690
}
8791
}
8892

tokio/src/runtime/task/mod.rs

+9-3
Original file line numberDiff line numberDiff line change
@@ -500,11 +500,17 @@ impl Id {
500500

501501
cfg_not_has_atomic_u64! {
502502
pub(crate) fn next() -> Self {
503-
use once_cell::sync::Lazy;
503+
use crate::util::once_cell::OnceCell;
504504
use crate::loom::sync::Mutex;
505505

506-
static NEXT_ID: Lazy<Mutex<u64>> = Lazy::new(|| Mutex::new(1));
507-
let mut lock = NEXT_ID.lock();
506+
fn init_next_id() -> Mutex<u64> {
507+
Mutex::new(1)
508+
}
509+
510+
static NEXT_ID: OnceCell<Mutex<u64>> = OnceCell::new();
511+
512+
let next_id = NEXT_ID.get(init_next_id);
513+
let mut lock = next_id.lock();
508514
let id = *lock;
509515
*lock += 1;
510516
Self(id)

tokio/src/signal/registry.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
#![allow(clippy::unit_arg)]
22

33
use crate::signal::os::{OsExtraData, OsStorage};
4-
54
use crate::sync::watch;
5+
use crate::util::once_cell::OnceCell;
66

7-
use once_cell::sync::Lazy;
87
use std::ops;
98
use std::pin::Pin;
109
use std::sync::atomic::{AtomicBool, Ordering};
@@ -152,19 +151,25 @@ impl Globals {
152151
}
153152
}
154153

154+
fn globals_init() -> Globals
155+
where
156+
OsExtraData: 'static + Send + Sync + Init,
157+
OsStorage: 'static + Send + Sync + Init,
158+
{
159+
Globals {
160+
extra: OsExtraData::init(),
161+
registry: Registry::new(OsStorage::init()),
162+
}
163+
}
164+
155165
pub(crate) fn globals() -> Pin<&'static Globals>
156166
where
157167
OsExtraData: 'static + Send + Sync + Init,
158168
OsStorage: 'static + Send + Sync + Init,
159169
{
160-
static GLOBALS: Lazy<Pin<Box<Globals>>> = Lazy::new(|| {
161-
Box::pin(Globals {
162-
extra: OsExtraData::init(),
163-
registry: Registry::new(OsStorage::init()),
164-
})
165-
});
166-
167-
GLOBALS.as_ref()
170+
static GLOBALS: OnceCell<Globals> = OnceCell::new();
171+
172+
Pin::new(GLOBALS.get(globals_init))
168173
}
169174

170175
#[cfg(all(test, not(loom)))]

tokio/src/util/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ cfg_io_driver! {
66
#[cfg(feature = "rt")]
77
pub(crate) mod atomic_cell;
88

9+
cfg_has_atomic_u64! {
10+
#[cfg(any(feature = "signal", feature = "process"))]
11+
pub(crate) mod once_cell;
12+
}
13+
cfg_not_has_atomic_u64! {
14+
#[cfg(any(feature = "rt", feature = "signal", feature = "process"))]
15+
pub(crate) mod once_cell;
16+
}
17+
918
#[cfg(any(
1019
// io driver uses `WakeList` directly
1120
feature = "net",

tokio/src/util/once_cell.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#![cfg_attr(loom, allow(dead_code))]
2+
use std::cell::UnsafeCell;
3+
use std::mem::MaybeUninit;
4+
use std::sync::Once;
5+
6+
pub(crate) struct OnceCell<T> {
7+
once: Once,
8+
value: UnsafeCell<MaybeUninit<T>>,
9+
}
10+
11+
unsafe impl<T: Send + Sync> Send for OnceCell<T> {}
12+
unsafe impl<T: Send + Sync> Sync for OnceCell<T> {}
13+
14+
impl<T> OnceCell<T> {
15+
pub(crate) const fn new() -> Self {
16+
Self {
17+
once: Once::new(),
18+
value: UnsafeCell::new(MaybeUninit::uninit()),
19+
}
20+
}
21+
22+
/// Get the value inside this cell, intiailizing it using the provided
23+
/// function if necessary.
24+
///
25+
/// If the `init` closure panics, then the `OnceCell` is poisoned and all
26+
/// future calls to `get` will panic.
27+
#[inline]
28+
pub(crate) fn get(&self, init: fn() -> T) -> &T {
29+
if !self.once.is_completed() {
30+
self.do_init(init);
31+
}
32+
33+
// Safety: The `std::sync::Once` guarantees that we can only reach this
34+
// line if a `call_once` closure has been run exactly once and without
35+
// panicking. Thus, the value is not uninitialized.
36+
//
37+
// There is also no race because the only `&self` method that modifies
38+
// `value` is `do_init`, but if the `call_once` closure is still
39+
// running, then no thread has gotten past the `call_once`.
40+
unsafe { &*(self.value.get() as *const T) }
41+
}
42+
43+
#[cold]
44+
fn do_init(&self, init: fn() -> T) {
45+
let value_ptr = self.value.get() as *mut T;
46+
47+
self.once.call_once(|| {
48+
let set_to = init();
49+
50+
// Safety: The `std::sync::Once` guarantees that this initialization
51+
// will run at most once, and that no thread can get past the
52+
// `call_once` until it has run exactly once. Thus, we have
53+
// exclusive access to `value`.
54+
unsafe {
55+
std::ptr::write(value_ptr, set_to);
56+
}
57+
});
58+
}
59+
}
60+
61+
impl<T> Drop for OnceCell<T> {
62+
fn drop(&mut self) {
63+
if self.once.is_completed() {
64+
let value_ptr = self.value.get() as *mut T;
65+
unsafe {
66+
std::ptr::drop_in_place(value_ptr);
67+
}
68+
}
69+
}
70+
}

0 commit comments

Comments
 (0)