Skip to content

Commit 64e5bf3

Browse files
committed
wip: locking
1 parent 81c3f77 commit 64e5bf3

File tree

4 files changed

+93
-3
lines changed

4 files changed

+93
-3
lines changed

src/cargo/core/compiler/build_runner/compilation_files.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,11 @@ impl<'a, 'gctx: 'a> CompilationFiles<'a, 'gctx> {
277277
self.layout(unit.kind).fingerprint(&dir)
278278
}
279279

280+
pub fn build_unit_lock(&self, unit: &Unit) -> PathBuf {
281+
let dir = self.pkg_dir(unit);
282+
self.layout(unit.kind).build_unit_lock(&dir)
283+
}
284+
280285
/// Directory where incremental output for the given unit should go.
281286
pub fn incremental_dir(&self, unit: &Unit) -> &Path {
282287
self.layout(unit.kind).incremental()

src/cargo/core/compiler/layout.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ pub struct Layout {
136136
tmp: PathBuf,
137137
/// The lockfile for a build (`.cargo-lock`). Will be unlocked when this
138138
/// struct is `drop`ped.
139-
_lock: FileLock,
139+
_lock: Option<FileLock>,
140140
/// Same as `_lock` but for the build directory.
141141
///
142142
/// Will be `None` when the build-dir and target-dir are the same path as we cannot
@@ -182,9 +182,13 @@ impl Layout {
182182
// For now we don't do any more finer-grained locking on the artifact
183183
// directory, so just lock the entire thing for the duration of this
184184
// compile.
185-
let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?;
185+
let lock = if !is_new_layout {
186+
Some(dest.open_rw_exclusive_create(".cargo-lock", ws.gctx(), "build directory")?)
187+
} else {
188+
None
189+
};
186190

187-
let build_lock = if root != build_root {
191+
let build_lock = if root != build_root && !is_new_layout {
188192
Some(build_dest.open_rw_exclusive_create(
189193
".cargo-lock",
190194
ws.gctx(),
@@ -300,6 +304,9 @@ impl Layout {
300304
self.build().join(pkg_dir)
301305
}
302306
}
307+
pub fn build_unit_lock(&self, pkg_dir: &str) -> PathBuf {
308+
self.build_unit(pkg_dir).join("lock")
309+
}
303310
/// Fetch the artifact path.
304311
pub fn artifact(&self) -> &Path {
305312
&self.artifact

src/cargo/core/compiler/locking.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
use std::{
2+
fs::{File, OpenOptions},
3+
path::PathBuf,
4+
};
5+
6+
use itertools::Itertools;
7+
8+
use crate::core::compiler::{BuildRunner, Unit};
9+
10+
pub struct CompilationLock {
11+
/// The path to the lock file of the unit to compile
12+
unit: PathBuf,
13+
/// The paths to lock files of the unit's dependencies
14+
dependency_units: Vec<PathBuf>,
15+
}
16+
17+
impl CompilationLock {
18+
pub fn new(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Self {
19+
let unit_path = build_runner.files().build_unit_lock(unit);
20+
21+
let dependency_units = build_runner
22+
.unit_deps(unit)
23+
.into_iter()
24+
.map(|unit| build_runner.files().build_unit_lock(&unit.unit))
25+
.collect_vec();
26+
27+
Self {
28+
unit: unit_path,
29+
dependency_units,
30+
}
31+
}
32+
33+
pub fn lock(self) -> CompilationLockGuard {
34+
let unit_lock = OpenOptions::new()
35+
.create(true)
36+
.write(true)
37+
.append(true)
38+
.open(self.unit)
39+
.unwrap();
40+
unit_lock.lock().unwrap();
41+
42+
let dependency_locks = self
43+
.dependency_units
44+
.into_iter()
45+
.map(|d| {
46+
let f = OpenOptions::new()
47+
.create(true)
48+
.write(true)
49+
.append(true)
50+
.open(d)
51+
.unwrap();
52+
f.lock_shared().unwrap();
53+
f
54+
})
55+
.collect::<Vec<_>>();
56+
57+
CompilationLockGuard {
58+
_lock: unit_lock,
59+
_dependency_locks: dependency_locks,
60+
}
61+
}
62+
}
63+
64+
pub struct CompilationLockGuard {
65+
_lock: File,
66+
_dependency_locks: Vec<File>,
67+
}

src/cargo/core/compiler/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub mod future_incompat;
4545
pub(crate) mod job_queue;
4646
pub(crate) mod layout;
4747
mod links;
48+
mod locking;
4849
mod lto;
4950
mod output_depinfo;
5051
mod output_sbom;
@@ -95,6 +96,7 @@ use self::output_depinfo::output_depinfo;
9596
use self::output_sbom::build_sbom;
9697
use self::unit_graph::UnitDep;
9798
use crate::core::compiler::future_incompat::FutureIncompatReport;
99+
use crate::core::compiler::locking::CompilationLock;
98100
use crate::core::compiler::timings::SectionTiming;
99101
pub use crate::core::compiler::unit::{Unit, UnitInterner};
100102
use crate::core::manifest::TargetSourcePath;
@@ -351,7 +353,16 @@ fn rustc(
351353
output_options.show_diagnostics = false;
352354
}
353355
let env_config = Arc::clone(build_runner.bcx.gctx.env_config()?);
356+
357+
let lock = if build_runner.bcx.gctx.cli_unstable().build_dir_new_layout {
358+
Some(CompilationLock::new(build_runner, unit))
359+
} else {
360+
None
361+
};
362+
354363
return Ok(Work::new(move |state| {
364+
let _guard = lock.map(|v| v.lock());
365+
355366
// Artifacts are in a different location than typical units,
356367
// hence we must assure the crate- and target-dependent
357368
// directory is present.

0 commit comments

Comments
 (0)