cargo/core/compiler/
locking.rs1use crate::{
4 CargoResult,
5 core::compiler::{BuildRunner, Unit},
6 util::{FileLock, Filesystem},
7};
8use anyhow::bail;
9use std::{
10 collections::HashMap,
11 fmt::{Display, Formatter},
12 path::PathBuf,
13 sync::Mutex,
14};
15use tracing::instrument;
16
17pub struct LockManager {
19 locks: Mutex<HashMap<LockKey, FileLock>>,
20}
21
22impl LockManager {
23 pub fn new() -> Self {
24 Self {
25 locks: Mutex::new(HashMap::new()),
26 }
27 }
28
29 #[instrument(skip_all, fields(key))]
36 pub fn lock_shared(
37 &self,
38 build_runner: &BuildRunner<'_, '_>,
39 unit: &Unit,
40 ) -> CargoResult<LockKey> {
41 let key = LockKey::from_unit(build_runner, unit);
42 tracing::Span::current().record("key", key.0.to_str());
43
44 let mut locks = self.locks.lock().unwrap();
45 if let Some(lock) = locks.get_mut(&key) {
46 lock.file().lock_shared()?;
47 } else {
48 let fs = Filesystem::new(key.0.clone());
49 let lock_msg = format!(
50 "{} ({})",
51 unit.pkg.name(),
52 build_runner.files().unit_hash(unit)
53 );
54 let lock = fs.open_ro_shared_create(&key.0, build_runner.bcx.gctx, &lock_msg)?;
55 locks.insert(key.clone(), lock);
56 }
57
58 Ok(key)
59 }
60
61 #[instrument(skip(self))]
62 pub fn lock(&self, key: &LockKey) -> CargoResult<()> {
63 let mut locks = self.locks.lock().unwrap();
64 if let Some(lock) = locks.get_mut(&key) {
65 lock.file().lock()?;
66 } else {
67 bail!("lock was not found in lock manager: {key}");
68 }
69
70 Ok(())
71 }
72
73 #[instrument(skip(self))]
75 pub fn downgrade_to_shared(&self, key: &LockKey) -> CargoResult<()> {
76 let mut locks = self.locks.lock().unwrap();
77 let Some(lock) = locks.get_mut(key) else {
78 bail!("lock was not found in lock manager: {key}");
79 };
80 lock.file().lock_shared()?;
81 Ok(())
82 }
83
84 #[instrument(skip(self))]
85 pub fn unlock(&self, key: &LockKey) -> CargoResult<()> {
86 let mut locks = self.locks.lock().unwrap();
87 if let Some(lock) = locks.get_mut(key) {
88 lock.file().unlock()?;
89 };
90
91 Ok(())
92 }
93}
94
95#[derive(Debug, Clone, Hash, Eq, PartialEq)]
96pub struct LockKey(PathBuf);
97
98impl LockKey {
99 fn from_unit(build_runner: &BuildRunner<'_, '_>, unit: &Unit) -> Self {
100 Self(build_runner.files().build_unit_lock(unit))
101 }
102}
103
104impl Display for LockKey {
105 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106 write!(f, "{}", self.0.display())
107 }
108}