Skip to content

Commit 60182f7

Browse files
committed
Auto merge of #15544 - Veykril:locks, r=Veykril
Shuffle some locking around The main thread is still occasionally blocking on something and I am unsure what the cause might be. This will hopefully help somewhat
2 parents 074c668 + c193909 commit 60182f7

File tree

4 files changed

+70
-50
lines changed

4 files changed

+70
-50
lines changed

crates/rust-analyzer/src/global_state.rs

+23-7
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
1212
use load_cargo::SourceRootConfig;
1313
use lsp_types::{SemanticTokens, Url};
1414
use nohash_hasher::IntMap;
15-
use parking_lot::{Mutex, RwLock};
15+
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
1616
use proc_macro_api::ProcMacroServer;
1717
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
1818
use rustc_hash::{FxHashMap, FxHashSet};
1919
use triomphe::Arc;
20-
use vfs::AnchoredPathBuf;
20+
use vfs::{AnchoredPathBuf, Vfs};
2121

2222
use crate::{
2323
config::{Config, ConfigError},
@@ -216,12 +216,15 @@ impl GlobalState {
216216
let mut file_changes = FxHashMap::default();
217217
let (change, changed_files, workspace_structure_change) = {
218218
let mut change = Change::new();
219-
let (vfs, line_endings_map) = &mut *self.vfs.write();
220-
let changed_files = vfs.take_changes();
219+
let mut guard = self.vfs.write();
220+
let changed_files = guard.0.take_changes();
221221
if changed_files.is_empty() {
222222
return false;
223223
}
224224

225+
// downgrade to read lock to allow more readers while we are normalizing text
226+
let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
227+
let vfs: &Vfs = &guard.0;
225228
// We need to fix up the changed events a bit. If we have a create or modify for a file
226229
// id that is followed by a delete we actually skip observing the file text from the
227230
// earlier event, to avoid problems later on.
@@ -272,6 +275,7 @@ impl GlobalState {
272275
let mut workspace_structure_change = None;
273276
// A file was added or deleted
274277
let mut has_structure_changes = false;
278+
let mut bytes = vec![];
275279
for file in &changed_files {
276280
let vfs_path = &vfs.file_path(file.file_id);
277281
if let Some(path) = vfs_path.as_path() {
@@ -293,16 +297,28 @@ impl GlobalState {
293297

294298
let text = if file.exists() {
295299
let bytes = vfs.file_contents(file.file_id).to_vec();
300+
296301
String::from_utf8(bytes).ok().and_then(|text| {
302+
// FIXME: Consider doing normalization in the `vfs` instead? That allows
303+
// getting rid of some locking
297304
let (text, line_endings) = LineEndings::normalize(text);
298-
line_endings_map.insert(file.file_id, line_endings);
299-
Some(Arc::from(text))
305+
Some((Arc::from(text), line_endings))
300306
})
301307
} else {
302308
None
303309
};
304-
change.change_file(file.file_id, text);
310+
// delay `line_endings_map` changes until we are done normalizing the text
311+
// this allows delaying the re-acquisition of the write lock
312+
bytes.push((file.file_id, text));
305313
}
314+
let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
315+
bytes.into_iter().for_each(|(file_id, text)| match text {
316+
None => change.change_file(file_id, None),
317+
Some((text, line_endings)) => {
318+
line_endings_map.insert(file_id, line_endings);
319+
change.change_file(file_id, Some(text));
320+
}
321+
});
306322
if has_structure_changes {
307323
let roots = self.source_root_config.partition(vfs);
308324
change.set_roots(roots);

crates/rust-analyzer/src/handlers/notification.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,16 @@ pub(crate) fn handle_did_change_text_document(
8484
}
8585
};
8686

87-
let vfs = &mut state.vfs.write().0;
88-
let file_id = vfs.file_id(&path).unwrap();
8987
let text = apply_document_changes(
9088
state.config.position_encoding(),
91-
|| std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(),
89+
|| {
90+
let vfs = &state.vfs.read().0;
91+
let file_id = vfs.file_id(&path).unwrap();
92+
std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
93+
},
9294
params.content_changes,
9395
);
94-
95-
vfs.set_file_contents(path, Some(text.into_bytes()));
96+
state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
9697
}
9798
Ok(())
9899
}

crates/rust-analyzer/src/handlers/request.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -1569,18 +1569,21 @@ pub(crate) fn handle_semantic_tokens_full_delta(
15691569
snap.config.highlighting_non_standard_tokens(),
15701570
);
15711571

1572-
let mut cache = snap.semantic_tokens_cache.lock();
1573-
let cached_tokens = cache.entry(params.text_document.uri).or_default();
1572+
let cached_tokens = snap.semantic_tokens_cache.lock().remove(&params.text_document.uri);
15741573

1575-
if let Some(prev_id) = &cached_tokens.result_id {
1574+
if let Some(cached_tokens @ lsp_types::SemanticTokens { result_id: Some(prev_id), .. }) =
1575+
&cached_tokens
1576+
{
15761577
if *prev_id == params.previous_result_id {
15771578
let delta = to_proto::semantic_token_delta(cached_tokens, &semantic_tokens);
1578-
*cached_tokens = semantic_tokens;
1579+
snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens);
15791580
return Ok(Some(delta.into()));
15801581
}
15811582
}
15821583

1583-
*cached_tokens = semantic_tokens.clone();
1584+
// Clone first to keep the lock short
1585+
let semantic_tokens_clone = semantic_tokens.clone();
1586+
snap.semantic_tokens_cache.lock().insert(params.text_document.uri, semantic_tokens_clone);
15841587

15851588
Ok(Some(semantic_tokens.into()))
15861589
}
@@ -1879,12 +1882,15 @@ fn run_rustfmt(
18791882

18801883
// Determine the edition of the crate the file belongs to (if there's multiple, we pick the
18811884
// highest edition).
1882-
let editions = snap
1885+
let Ok(editions) = snap
18831886
.analysis
18841887
.relevant_crates_for(file_id)?
18851888
.into_iter()
18861889
.map(|crate_id| snap.analysis.crate_edition(crate_id))
1887-
.collect::<Result<Vec<_>, _>>()?;
1890+
.collect::<Result<Vec<_>, _>>()
1891+
else {
1892+
return Ok(None);
1893+
};
18881894
let edition = editions.iter().copied().max();
18891895

18901896
let line_index = snap.file_line_index(file_id)?;

crates/rust-analyzer/src/main_loop.rs

+28-31
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,7 @@ impl GlobalState {
670670
}
671671

672672
use crate::handlers::request as handlers;
673+
use lsp_types::request as lsp_request;
673674

674675
dispatcher
675676
// Request handlers that must run on the main thread
@@ -682,30 +683,30 @@ impl GlobalState {
682683
// are run on the main thread to reduce latency:
683684
.on_sync::<lsp_ext::JoinLines>(handlers::handle_join_lines)
684685
.on_sync::<lsp_ext::OnEnter>(handlers::handle_on_enter)
685-
.on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
686+
.on_sync::<lsp_request::SelectionRangeRequest>(handlers::handle_selection_range)
686687
.on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
687688
.on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
688689
// Formatting should be done immediately as the editor might wait on it, but we can't
689690
// put it on the main thread as we do not want the main thread to block on rustfmt.
690691
// So we have an extra thread just for formatting requests to make sure it gets handled
691692
// as fast as possible.
692-
.on_fmt_thread::<lsp_types::request::Formatting>(handlers::handle_formatting)
693-
.on_fmt_thread::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting)
693+
.on_fmt_thread::<lsp_request::Formatting>(handlers::handle_formatting)
694+
.on_fmt_thread::<lsp_request::RangeFormatting>(handlers::handle_range_formatting)
694695
// We can’t run latency-sensitive request handlers which do semantic
695696
// analysis on the main thread because that would block other
696697
// requests. Instead, we run these request handlers on higher priority
697698
// threads in the threadpool.
698-
.on_latency_sensitive::<lsp_types::request::Completion>(handlers::handle_completion)
699-
.on_latency_sensitive::<lsp_types::request::ResolveCompletionItem>(
699+
.on_latency_sensitive::<lsp_request::Completion>(handlers::handle_completion)
700+
.on_latency_sensitive::<lsp_request::ResolveCompletionItem>(
700701
handlers::handle_completion_resolve,
701702
)
702-
.on_latency_sensitive::<lsp_types::request::SemanticTokensFullRequest>(
703+
.on_latency_sensitive::<lsp_request::SemanticTokensFullRequest>(
703704
handlers::handle_semantic_tokens_full,
704705
)
705-
.on_latency_sensitive::<lsp_types::request::SemanticTokensFullDeltaRequest>(
706+
.on_latency_sensitive::<lsp_request::SemanticTokensFullDeltaRequest>(
706707
handlers::handle_semantic_tokens_full_delta,
707708
)
708-
.on_latency_sensitive::<lsp_types::request::SemanticTokensRangeRequest>(
709+
.on_latency_sensitive::<lsp_request::SemanticTokensRangeRequest>(
709710
handlers::handle_semantic_tokens_range,
710711
)
711712
// All other request handlers
@@ -729,29 +730,25 @@ impl GlobalState {
729730
.on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
730731
.on::<lsp_ext::MoveItem>(handlers::handle_move_item)
731732
.on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
732-
.on::<lsp_types::request::DocumentSymbolRequest>(handlers::handle_document_symbol)
733-
.on::<lsp_types::request::GotoDefinition>(handlers::handle_goto_definition)
734-
.on::<lsp_types::request::GotoDeclaration>(handlers::handle_goto_declaration)
735-
.on::<lsp_types::request::GotoImplementation>(handlers::handle_goto_implementation)
736-
.on::<lsp_types::request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
737-
.on_no_retry::<lsp_types::request::InlayHintRequest>(handlers::handle_inlay_hints)
738-
.on::<lsp_types::request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
739-
.on::<lsp_types::request::CodeLensRequest>(handlers::handle_code_lens)
740-
.on::<lsp_types::request::CodeLensResolve>(handlers::handle_code_lens_resolve)
741-
.on::<lsp_types::request::FoldingRangeRequest>(handlers::handle_folding_range)
742-
.on::<lsp_types::request::SignatureHelpRequest>(handlers::handle_signature_help)
743-
.on::<lsp_types::request::PrepareRenameRequest>(handlers::handle_prepare_rename)
744-
.on::<lsp_types::request::Rename>(handlers::handle_rename)
745-
.on::<lsp_types::request::References>(handlers::handle_references)
746-
.on::<lsp_types::request::DocumentHighlightRequest>(handlers::handle_document_highlight)
747-
.on::<lsp_types::request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
748-
.on::<lsp_types::request::CallHierarchyIncomingCalls>(
749-
handlers::handle_call_hierarchy_incoming,
750-
)
751-
.on::<lsp_types::request::CallHierarchyOutgoingCalls>(
752-
handlers::handle_call_hierarchy_outgoing,
753-
)
754-
.on::<lsp_types::request::WillRenameFiles>(handlers::handle_will_rename_files)
733+
.on::<lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
734+
.on::<lsp_request::GotoDefinition>(handlers::handle_goto_definition)
735+
.on::<lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
736+
.on::<lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
737+
.on::<lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
738+
.on_no_retry::<lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
739+
.on::<lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
740+
.on::<lsp_request::CodeLensRequest>(handlers::handle_code_lens)
741+
.on::<lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
742+
.on::<lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
743+
.on::<lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
744+
.on::<lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
745+
.on::<lsp_request::Rename>(handlers::handle_rename)
746+
.on::<lsp_request::References>(handlers::handle_references)
747+
.on::<lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
748+
.on::<lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
749+
.on::<lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
750+
.on::<lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
751+
.on::<lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
755752
.on::<lsp_ext::Ssr>(handlers::handle_ssr)
756753
.on::<lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
757754
.finish();

0 commit comments

Comments
 (0)