From 31d3b4285709cb48310eb11bc2dd8ae4ebae518b Mon Sep 17 00:00:00 2001 From: Ross Sullivan Date: Fri, 20 Feb 2026 22:44:58 +0900 Subject: [PATCH] fix: Fix parallel locking when `-Zfine-grain-locking` is enabled This commit replaces a `Mutex` with an `RwLock` lock to avoid holding a mutex guard while waiting on a file lock. Instead we hold a read guard which allows multiple threads to access the `HashMap` inside of `LockManager`. --- src/cargo/core/compiler/locking.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/cargo/core/compiler/locking.rs b/src/cargo/core/compiler/locking.rs index 155a4dc36..ea9f98632 100644 --- a/src/cargo/core/compiler/locking.rs +++ b/src/cargo/core/compiler/locking.rs @@ -10,19 +10,19 @@ use std::{ collections::HashMap, fmt::{Display, Formatter}, path::PathBuf, - sync::Mutex, + sync::RwLock, }; use tracing::instrument; /// A struct to store the lock handles for build units during compilation. pub struct LockManager { - locks: Mutex>, + locks: RwLock>, } impl LockManager { pub fn new() -> Self { Self { - locks: Mutex::new(HashMap::new()), + locks: RwLock::new(HashMap::new()), } } @@ -41,7 +41,7 @@ impl LockManager { let key = LockKey::from_unit(build_runner, unit); tracing::Span::current().record("key", key.0.to_str()); - let mut locks = self.locks.lock().unwrap(); + let mut locks = self.locks.write().unwrap(); if let Some(lock) = locks.get_mut(&key) { lock.file().lock_shared()?; } else { @@ -60,8 +60,8 @@ impl LockManager { #[instrument(skip(self))] pub fn lock(&self, key: &LockKey) -> CargoResult<()> { - let mut locks = self.locks.lock().unwrap(); - if let Some(lock) = locks.get_mut(&key) { + let locks = self.locks.read().unwrap(); + if let Some(lock) = locks.get(&key) { lock.file().lock()?; } else { bail!("lock was not found in lock manager: {key}"); @@ -73,8 +73,8 @@ impl LockManager { /// Upgrades an existing exclusive lock into a shared lock. #[instrument(skip(self))] pub fn downgrade_to_shared(&self, key: &LockKey) -> CargoResult<()> { - let mut locks = self.locks.lock().unwrap(); - let Some(lock) = locks.get_mut(key) else { + let locks = self.locks.read().unwrap(); + let Some(lock) = locks.get(key) else { bail!("lock was not found in lock manager: {key}"); }; lock.file().lock_shared()?; @@ -83,8 +83,8 @@ impl LockManager { #[instrument(skip(self))] pub fn unlock(&self, key: &LockKey) -> CargoResult<()> { - let mut locks = self.locks.lock().unwrap(); - if let Some(lock) = locks.get_mut(key) { + let locks = self.locks.read().unwrap(); + if let Some(lock) = locks.get(key) { lock.file().unlock()?; };