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