Skip to content

Commit af4c928

Browse files
authored
Fix cyclic compilation: Use vendored once_cell (#1154)
1 parent 1f82ef0 commit af4c928

File tree

5 files changed

+64
-14
lines changed

5 files changed

+64
-14
lines changed

Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,14 @@ rust-version = "1.63"
2121

2222
[dependencies]
2323
jobserver = { version = "0.1.30", default-features = false, optional = true }
24-
once_cell = { version = "1.19", optional = true }
2524

2625
[target.'cfg(unix)'.dependencies]
2726
# Don't turn on the feature "std" for this, see https://github.com/rust-lang/cargo/issues/4866
2827
# which is still an issue with `resolver = "1"`.
2928
libc = { version = "0.2.62", default-features = false, optional = true }
3029

3130
[features]
32-
parallel = ["dep:libc", "dep:jobserver", "dep:once_cell"]
31+
parallel = ["dep:libc", "dep:jobserver"]
3332
# This is a placeholder feature for people who incorrectly used `cc` with `features = ["jobserver"]`
3433
# so that they aren't broken. This has never enabled `parallel`, so we won't do that.
3534
jobserver = []

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ impl Build {
15021502
}
15031503

15041504
// Limit our parallelism globally with a jobserver.
1505-
let tokens = parallel::job_token::ActiveJobTokenServer::new();
1505+
let mut tokens = parallel::job_token::ActiveJobTokenServer::new();
15061506

15071507
// When compiling objects in parallel we do a few dirty tricks to speed
15081508
// things up:

src/parallel/job_token.rs

+14-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::marker::PhantomData;
22

33
use crate::Error;
44

5-
use once_cell::sync::OnceCell;
5+
use super::once_lock::OnceLock;
66

77
pub(crate) struct JobToken(PhantomData<()>);
88

@@ -37,7 +37,7 @@ impl JobTokenServer {
3737
/// compilation.
3838
fn new() -> &'static Self {
3939
// TODO: Replace with a OnceLock once MSRV is 1.70
40-
static JOBSERVER: OnceCell<JobTokenServer> = OnceCell::new();
40+
static JOBSERVER: OnceLock<JobTokenServer> = OnceLock::new();
4141

4242
JOBSERVER.get_or_init(|| {
4343
unsafe { inherited_jobserver::JobServer::from_env() }
@@ -62,16 +62,16 @@ impl ActiveJobTokenServer {
6262
}
6363
}
6464

65-
pub(crate) async fn acquire(&self) -> Result<JobToken, Error> {
66-
match &self {
65+
pub(crate) async fn acquire(&mut self) -> Result<JobToken, Error> {
66+
match self {
6767
Self::Inherited(jobserver) => jobserver.acquire().await,
6868
Self::InProcess(jobserver) => Ok(jobserver.acquire().await),
6969
}
7070
}
7171
}
7272

7373
mod inherited_jobserver {
74-
use super::{JobToken, OnceCell};
74+
use super::JobToken;
7575

7676
use crate::{parallel::async_executor::YieldOnce, Error, ErrorKind};
7777

@@ -137,7 +137,7 @@ mod inherited_jobserver {
137137
pub(super) fn enter_active(&self) -> ActiveJobServer<'_> {
138138
ActiveJobServer {
139139
jobserver: self,
140-
helper_thread: OnceCell::new(),
140+
helper_thread: None,
141141
}
142142
}
143143
}
@@ -163,11 +163,11 @@ mod inherited_jobserver {
163163

164164
pub(crate) struct ActiveJobServer<'a> {
165165
jobserver: &'a JobServer,
166-
helper_thread: OnceCell<HelperThread>,
166+
helper_thread: Option<HelperThread>,
167167
}
168168

169169
impl<'a> ActiveJobServer<'a> {
170-
pub(super) async fn acquire(&self) -> Result<JobToken, Error> {
170+
pub(super) async fn acquire(&mut self) -> Result<JobToken, Error> {
171171
let mut has_requested_token = false;
172172

173173
loop {
@@ -184,9 +184,12 @@ mod inherited_jobserver {
184184
Ok(None) => YieldOnce::default().await,
185185
Err(err) if err.kind() == io::ErrorKind::Unsupported => {
186186
// Fallback to creating a help thread with blocking acquire
187-
let helper_thread = self
188-
.helper_thread
189-
.get_or_try_init(|| HelperThread::new(self.jobserver))?;
187+
let helper_thread = if let Some(thread) = self.helper_thread.as_ref() {
188+
thread
189+
} else {
190+
self.helper_thread
191+
.insert(HelperThread::new(self.jobserver)?)
192+
};
190193

191194
match helper_thread.rx.try_recv() {
192195
Ok(res) => {

src/parallel/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
pub(crate) mod async_executor;
22
pub(crate) mod job_token;
3+
pub(crate) mod once_lock;
34
pub(crate) mod stderr;

src/parallel/once_lock.rs

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::{
2+
cell::UnsafeCell,
3+
marker::PhantomData,
4+
mem::MaybeUninit,
5+
panic::{RefUnwindSafe, UnwindSafe},
6+
sync::Once,
7+
};
8+
9+
pub(crate) struct OnceLock<T> {
10+
once: Once,
11+
value: UnsafeCell<MaybeUninit<T>>,
12+
_marker: PhantomData<T>,
13+
}
14+
15+
impl<T> OnceLock<T> {
16+
pub(crate) const fn new() -> Self {
17+
Self {
18+
once: Once::new(),
19+
value: UnsafeCell::new(MaybeUninit::uninit()),
20+
_marker: PhantomData,
21+
}
22+
}
23+
24+
pub(crate) fn get_or_init(&self, f: impl FnOnce() -> T) -> &T {
25+
self.once.call_once(|| {
26+
unsafe { &mut *self.value.get() }.write(f());
27+
});
28+
unsafe { (&*self.value.get()).assume_init_ref() }
29+
}
30+
}
31+
32+
unsafe impl<T: Sync + Send> Sync for OnceLock<T> {}
33+
unsafe impl<T: Send> Send for OnceLock<T> {}
34+
35+
impl<T: RefUnwindSafe + UnwindSafe> RefUnwindSafe for OnceLock<T> {}
36+
impl<T: UnwindSafe> UnwindSafe for OnceLock<T> {}
37+
38+
impl<T> Drop for OnceLock<T> {
39+
#[inline]
40+
fn drop(&mut self) {
41+
if self.once.is_completed() {
42+
// SAFETY: The cell is initialized and being dropped, so it can't
43+
// be accessed again.
44+
unsafe { self.value.get_mut().assume_init_drop() };
45+
}
46+
}
47+
}

0 commit comments

Comments
 (0)