Skip to content

Commit d567091

Browse files
committed
Auto merge of rust-lang#15028 - Veykril:rustfmt-thread, r=Veykril
internal: Give rustfmt jobs a separate thread Some light testing suggests that this fixes the waiting on formatting popup in vscode when the project is still building (which is usually the way for me to encounter it, as r-a is either waiting or getting little resources causing the tasks to block formatting)
2 parents b7497fc + 179b8d7 commit d567091

File tree

4 files changed

+54
-29
lines changed

4 files changed

+54
-29
lines changed

crates/rust-analyzer/src/dispatch.rs

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<'a> RequestDispatcher<'a> {
135135
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
136136
R::Result: Serialize,
137137
{
138-
self.on_with_thread_intent::<R>(ThreadIntent::Worker, f)
138+
self.on_with_thread_intent::<true, R>(ThreadIntent::Worker, f)
139139
}
140140

141141
/// Dispatches a latency-sensitive request onto the thread pool.
@@ -148,7 +148,22 @@ impl<'a> RequestDispatcher<'a> {
148148
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
149149
R::Result: Serialize,
150150
{
151-
self.on_with_thread_intent::<R>(ThreadIntent::LatencySensitive, f)
151+
self.on_with_thread_intent::<true, R>(ThreadIntent::LatencySensitive, f)
152+
}
153+
154+
/// Formatting requests should never block on waiting a for task thread to open up, editors will wait
155+
/// on the response and a late formatting update might mess with the document and user.
156+
/// We can't run this on the main thread though as we invoke rustfmt which may take arbitrary time to complete!
157+
pub(crate) fn on_fmt_thread<R>(
158+
&mut self,
159+
f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
160+
) -> &mut Self
161+
where
162+
R: lsp_types::request::Request + 'static,
163+
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
164+
R::Result: Serialize,
165+
{
166+
self.on_with_thread_intent::<false, R>(ThreadIntent::LatencySensitive, f)
152167
}
153168

154169
pub(crate) fn finish(&mut self) {
@@ -163,7 +178,7 @@ impl<'a> RequestDispatcher<'a> {
163178
}
164179
}
165180

166-
fn on_with_thread_intent<R>(
181+
fn on_with_thread_intent<const MAIN_POOL: bool, R>(
167182
&mut self,
168183
intent: ThreadIntent,
169184
f: fn(GlobalStateSnapshot, R::Params) -> Result<R::Result>,
@@ -178,17 +193,20 @@ impl<'a> RequestDispatcher<'a> {
178193
None => return self,
179194
};
180195

181-
self.global_state.task_pool.handle.spawn(intent, {
182-
let world = self.global_state.snapshot();
183-
move || {
184-
let result = panic::catch_unwind(move || {
185-
let _pctx = stdx::panic_context::enter(panic_context);
186-
f(world, params)
187-
});
188-
match thread_result_to_response::<R>(req.id.clone(), result) {
189-
Ok(response) => Task::Response(response),
190-
Err(_) => Task::Retry(req),
191-
}
196+
let world = self.global_state.snapshot();
197+
if MAIN_POOL {
198+
&mut self.global_state.task_pool.handle
199+
} else {
200+
&mut self.global_state.fmt_pool.handle
201+
}
202+
.spawn(intent, move || {
203+
let result = panic::catch_unwind(move || {
204+
let _pctx = stdx::panic_context::enter(panic_context);
205+
f(world, params)
206+
});
207+
match thread_result_to_response::<R>(req.id.clone(), result) {
208+
Ok(response) => Task::Response(response),
209+
Err(_) => Task::Retry(req),
192210
}
193211
});
194212

crates/rust-analyzer/src/global_state.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ pub(crate) struct GlobalState {
5454
req_queue: ReqQueue,
5555

5656
pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
57+
pub(crate) fmt_pool: Handle<TaskPool<Task>, Receiver<Task>>,
5758

5859
pub(crate) config: Arc<Config>,
5960
pub(crate) config_errors: Option<ConfigError>,
@@ -151,6 +152,11 @@ impl GlobalState {
151152
let handle = TaskPool::new_with_threads(sender, config.main_loop_num_threads());
152153
Handle { handle, receiver }
153154
};
155+
let fmt_pool = {
156+
let (sender, receiver) = unbounded();
157+
let handle = TaskPool::new_with_threads(sender, 1);
158+
Handle { handle, receiver }
159+
};
154160

155161
let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity());
156162
if let Some(capacities) = config.lru_query_capacities() {
@@ -161,6 +167,7 @@ impl GlobalState {
161167
sender,
162168
req_queue: ReqQueue::default(),
163169
task_pool,
170+
fmt_pool,
164171
loader,
165172
config: Arc::new(config.clone()),
166173
analysis_host,

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ use lsp_server::ErrorCode;
1818
use lsp_types::{
1919
CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
2020
CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
21-
CodeLens, CompletionItem, DocumentFormattingParams, FoldingRange, FoldingRangeParams,
22-
HoverContents, InlayHint, InlayHintParams, Location, LocationLink, Position,
23-
PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams,
24-
SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams,
25-
SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation, SymbolTag,
26-
TextDocumentIdentifier, Url, WorkspaceEdit,
21+
CodeLens, CompletionItem, FoldingRange, FoldingRangeParams, HoverContents, InlayHint,
22+
InlayHintParams, Location, LocationLink, Position, PrepareRenameResponse, Range, RenameParams,
23+
SemanticTokensDeltaParams, SemanticTokensFullDeltaResult, SemanticTokensParams,
24+
SemanticTokensRangeParams, SemanticTokensRangeResult, SemanticTokensResult, SymbolInformation,
25+
SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
2726
};
2827
use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
2928
use serde_json::json;
@@ -1077,7 +1076,7 @@ pub(crate) fn handle_references(
10771076

10781077
pub(crate) fn handle_formatting(
10791078
snap: GlobalStateSnapshot,
1080-
params: DocumentFormattingParams,
1079+
params: lsp_types::DocumentFormattingParams,
10811080
) -> Result<Option<Vec<lsp_types::TextEdit>>> {
10821081
let _p = profile::span("handle_formatting");
10831082

crates/rust-analyzer/src/main_loop.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ impl GlobalState {
177177
recv(self.task_pool.receiver) -> task =>
178178
Some(Event::Task(task.unwrap())),
179179

180+
recv(self.fmt_pool.receiver) -> task =>
181+
Some(Event::Task(task.unwrap())),
182+
180183
recv(self.loader.receiver) -> task =>
181184
Some(Event::Vfs(task.unwrap())),
182185

@@ -678,6 +681,12 @@ impl GlobalState {
678681
.on_sync::<lsp_types::request::SelectionRangeRequest>(handlers::handle_selection_range)
679682
.on_sync::<lsp_ext::MatchingBrace>(handlers::handle_matching_brace)
680683
.on_sync::<lsp_ext::OnTypeFormatting>(handlers::handle_on_type_formatting)
684+
// Formatting should be done immediately as the editor might wait on it, but we can't
685+
// put it on the main thread as we do not want the main thread to block on rustfmt.
686+
// So we have an extra thread just for formatting requests to make sure it gets handled
687+
// as fast as possible.
688+
.on_fmt_thread::<lsp_types::request::Formatting>(handlers::handle_formatting)
689+
.on_fmt_thread::<lsp_types::request::RangeFormatting>(handlers::handle_range_formatting)
681690
// We can’t run latency-sensitive request handlers which do semantic
682691
// analysis on the main thread because that would block other
683692
// requests. Instead, we run these request handlers on higher priority
@@ -695,14 +704,6 @@ impl GlobalState {
695704
.on_latency_sensitive::<lsp_types::request::SemanticTokensRangeRequest>(
696705
handlers::handle_semantic_tokens_range,
697706
)
698-
// Formatting is not caused by the user typing,
699-
// but it does qualify as latency-sensitive
700-
// because a delay before formatting is applied
701-
// can be confusing for the user.
702-
.on_latency_sensitive::<lsp_types::request::Formatting>(handlers::handle_formatting)
703-
.on_latency_sensitive::<lsp_types::request::RangeFormatting>(
704-
handlers::handle_range_formatting,
705-
)
706707
// All other request handlers
707708
.on::<lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
708709
.on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)

0 commit comments

Comments
 (0)