aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_lsp_server/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_lsp_server/src')
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs133
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs5
-rw-r--r--crates/ra_lsp_server/src/world.rs4
3 files changed, 89 insertions, 53 deletions
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 7822be2e2..d850ded37 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -5,11 +5,18 @@ mod handlers;
5mod subscriptions; 5mod subscriptions;
6pub(crate) mod pending_requests; 6pub(crate) mod pending_requests;
7 7
8use std::{error::Error, fmt, panic, path::PathBuf, sync::Arc, time::Instant}; 8use std::{
9 env,
10 error::Error,
11 fmt, panic,
12 path::PathBuf,
13 sync::Arc,
14 time::{Duration, Instant},
15};
9 16
10use crossbeam_channel::{select, unbounded, RecvError, Sender}; 17use crossbeam_channel::{select, unbounded, RecvError, Sender};
11use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response}; 18use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
12use lsp_types::{ClientCapabilities, NumberOrString, Url}; 19use lsp_types::{ClientCapabilities, NumberOrString};
13use ra_cargo_watch::{CheckOptions, CheckTask}; 20use ra_cargo_watch::{CheckOptions, CheckTask};
14use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; 21use ra_ide::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
15use ra_prof::profile; 22use ra_prof::profile;
@@ -29,9 +36,6 @@ use crate::{
29 Result, ServerConfig, 36 Result, ServerConfig,
30}; 37};
31 38
32const THREADPOOL_SIZE: usize = 8;
33const MAX_IN_FLIGHT_LIBS: usize = THREADPOOL_SIZE - 3;
34
35#[derive(Debug)] 39#[derive(Debug)]
36pub struct LspError { 40pub struct LspError {
37 pub code: i32, 41 pub code: i32,
@@ -60,6 +64,25 @@ pub fn main_loop(
60) -> Result<()> { 64) -> Result<()> {
61 log::info!("server_config: {:#?}", config); 65 log::info!("server_config: {:#?}", config);
62 66
67 // Windows scheduler implements priority boosts: if thread waits for an
68 // event (like a condvar), and event fires, priority of the thread is
69 // temporary bumped. This optimization backfires in our case: each time the
70 // `main_loop` schedules a task to run on a threadpool, the worker threads
71 // gets a higher priority, and (on a machine with fewer cores) displaces the
72 // main loop! We work-around this by marking the main loop as a
73 // higher-priority thread.
74 //
75 // https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling-priorities
76 // https://docs.microsoft.com/en-us/windows/win32/procthread/priority-boosts
77 // https://github.com/rust-analyzer/rust-analyzer/issues/2835
78 #[cfg(windows)]
79 unsafe {
80 use winapi::um::processthreadsapi::*;
81 let thread = GetCurrentThread();
82 let thread_priority_above_normal = 1;
83 SetThreadPriority(thread, thread_priority_above_normal);
84 }
85
63 let mut loop_state = LoopState::default(); 86 let mut loop_state = LoopState::default();
64 let mut world_state = { 87 let mut world_state = {
65 let feature_flags = { 88 let feature_flags = {
@@ -168,7 +191,7 @@ pub fn main_loop(
168 ) 191 )
169 }; 192 };
170 193
171 let pool = ThreadPool::new(THREADPOOL_SIZE); 194 let pool = ThreadPool::default();
172 let (task_sender, task_receiver) = unbounded::<Task>(); 195 let (task_sender, task_receiver) = unbounded::<Task>();
173 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>(); 196 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
174 197
@@ -210,7 +233,7 @@ pub fn main_loop(
210 )?; 233 )?;
211 } 234 }
212 } 235 }
213 236 world_state.analysis_host.request_cancellation();
214 log::info!("waiting for tasks to finish..."); 237 log::info!("waiting for tasks to finish...");
215 task_receiver.into_iter().for_each(|task| { 238 task_receiver.into_iter().for_each(|task| {
216 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state) 239 on_task(task, &connection.sender, &mut loop_state.pending_requests, &mut world_state)
@@ -336,7 +359,7 @@ fn loop_turn(
336 world_state.maybe_collect_garbage(); 359 world_state.maybe_collect_garbage();
337 loop_state.in_flight_libraries -= 1; 360 loop_state.in_flight_libraries -= 1;
338 } 361 }
339 Event::CheckWatcher(task) => on_check_task(task, world_state, task_sender)?, 362 Event::CheckWatcher(task) => on_check_task(pool, task, world_state, task_sender)?,
340 Event::Msg(msg) => match msg { 363 Event::Msg(msg) => match msg {
341 Message::Request(req) => on_request( 364 Message::Request(req) => on_request(
342 world_state, 365 world_state,
@@ -371,7 +394,8 @@ fn loop_turn(
371 loop_state.pending_libraries.extend(changes); 394 loop_state.pending_libraries.extend(changes);
372 } 395 }
373 396
374 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS 397 let max_in_flight_libs = pool.max_count().saturating_sub(2).max(1);
398 while loop_state.in_flight_libraries < max_in_flight_libs
375 && !loop_state.pending_libraries.is_empty() 399 && !loop_state.pending_libraries.is_empty()
376 { 400 {
377 let (root, files) = loop_state.pending_libraries.pop().unwrap(); 401 let (root, files) = loop_state.pending_libraries.pop().unwrap();
@@ -408,6 +432,19 @@ fn loop_turn(
408 loop_state.subscriptions.subscriptions(), 432 loop_state.subscriptions.subscriptions(),
409 ) 433 )
410 } 434 }
435
436 let loop_duration = loop_start.elapsed();
437 if loop_duration > Duration::from_millis(100) {
438 log::error!("overly long loop turn: {:?}", loop_duration);
439 if env::var("RA_PROFILE").is_ok() {
440 show_message(
441 req::MessageType::Error,
442 format!("overly long loop turn: {:?}", loop_duration),
443 &connection.sender,
444 );
445 }
446 }
447
411 Ok(()) 448 Ok(())
412} 449}
413 450
@@ -435,7 +472,7 @@ fn on_request(
435 world: &mut WorldState, 472 world: &mut WorldState,
436 pending_requests: &mut PendingRequests, 473 pending_requests: &mut PendingRequests,
437 pool: &ThreadPool, 474 pool: &ThreadPool,
438 sender: &Sender<Task>, 475 task_sender: &Sender<Task>,
439 msg_sender: &Sender<Message>, 476 msg_sender: &Sender<Message>,
440 request_received: Instant, 477 request_received: Instant,
441 req: Request, 478 req: Request,
@@ -444,7 +481,7 @@ fn on_request(
444 req: Some(req), 481 req: Some(req),
445 pool, 482 pool,
446 world, 483 world,
447 sender, 484 task_sender,
448 msg_sender, 485 msg_sender,
449 pending_requests, 486 pending_requests,
450 request_received, 487 request_received,
@@ -585,31 +622,23 @@ fn on_notification(
585} 622}
586 623
587fn on_check_task( 624fn on_check_task(
625 pool: &ThreadPool,
588 task: CheckTask, 626 task: CheckTask,
589 world_state: &WorldState, 627 world_state: &mut WorldState,
590 task_sender: &Sender<Task>, 628 task_sender: &Sender<Task>,
591) -> Result<()> { 629) -> Result<()> {
592 match task { 630 let urls = match task {
593 CheckTask::ClearDiagnostics => { 631 CheckTask::ClearDiagnostics => {
594 let cleared_files = world_state.check_watcher.state.write().clear(); 632 let state = Arc::get_mut(&mut world_state.check_watcher.state)
595 633 .expect("couldn't get check watcher state as mutable");
596 // Send updated diagnostics for each cleared file 634 state.clear()
597 for url in cleared_files {
598 publish_diagnostics_for_url(&url, world_state, task_sender)?;
599 }
600 } 635 }
601 636
602 CheckTask::AddDiagnostic(url, diagnostic) => { 637 CheckTask::AddDiagnostic(url, diagnostic) => {
603 world_state 638 let state = Arc::get_mut(&mut world_state.check_watcher.state)
604 .check_watcher 639 .expect("couldn't get check watcher state as mutable");
605 .state 640 state.add_diagnostic_with_fixes(url.clone(), diagnostic);
606 .write() 641 vec![url]
607 .add_diagnostic_with_fixes(url.clone(), diagnostic);
608
609 // We manually send a diagnostic update when the watcher asks
610 // us to, to avoid the issue of having to change the file to
611 // receive updated diagnostics.
612 publish_diagnostics_for_url(&url, world_state, task_sender)?;
613 } 642 }
614 643
615 CheckTask::Status(progress) => { 644 CheckTask::Status(progress) => {
@@ -619,22 +648,30 @@ fn on_check_task(
619 }; 648 };
620 let not = notification_new::<req::Progress>(params); 649 let not = notification_new::<req::Progress>(params);
621 task_sender.send(Task::Notify(not)).unwrap(); 650 task_sender.send(Task::Notify(not)).unwrap();
651 Vec::new()
622 } 652 }
623 } 653 };
624 Ok(()) 654
625} 655 let subscriptions = urls
656 .into_iter()
657 .map(|url| {
658 let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?;
659 Ok(world_state.vfs.read().path2file(&path).map(|it| FileId(it.0)))
660 })
661 .filter_map(|res| res.transpose())
662 .collect::<Result<Vec<_>>>()?;
663
664 // We manually send a diagnostic update when the watcher asks
665 // us to, to avoid the issue of having to change the file to
666 // receive updated diagnostics.
667 update_file_notifications_on_threadpool(
668 pool,
669 world_state.snapshot(),
670 false,
671 task_sender.clone(),
672 subscriptions,
673 );
626 674
627fn publish_diagnostics_for_url(
628 url: &Url,
629 world_state: &WorldState,
630 task_sender: &Sender<Task>,
631) -> Result<()> {
632 let path = url.to_file_path().map_err(|()| format!("invalid uri: {}", url))?;
633 if let Some(file_id) = world_state.vfs.read().path2file(&path) {
634 let params = handlers::publish_diagnostics(&world_state.snapshot(), FileId(file_id.0))?;
635 let not = notification_new::<req::PublishDiagnostics>(params);
636 task_sender.send(Task::Notify(not)).unwrap();
637 }
638 Ok(()) 675 Ok(())
639} 676}
640 677
@@ -644,7 +681,7 @@ struct PoolDispatcher<'a> {
644 world: &'a mut WorldState, 681 world: &'a mut WorldState,
645 pending_requests: &'a mut PendingRequests, 682 pending_requests: &'a mut PendingRequests,
646 msg_sender: &'a Sender<Message>, 683 msg_sender: &'a Sender<Message>,
647 sender: &'a Sender<Task>, 684 task_sender: &'a Sender<Task>,
648 request_received: Instant, 685 request_received: Instant,
649} 686}
650 687
@@ -691,7 +728,7 @@ impl<'a> PoolDispatcher<'a> {
691 728
692 self.pool.execute({ 729 self.pool.execute({
693 let world = self.world.snapshot(); 730 let world = self.world.snapshot();
694 let sender = self.sender.clone(); 731 let sender = self.task_sender.clone();
695 move || { 732 move || {
696 let result = f(world, params); 733 let result = f(world, params);
697 let task = result_to_task::<R>(id, result); 734 let task = result_to_task::<R>(id, result);
@@ -769,7 +806,7 @@ fn update_file_notifications_on_threadpool(
769 pool: &ThreadPool, 806 pool: &ThreadPool,
770 world: WorldSnapshot, 807 world: WorldSnapshot,
771 publish_decorations: bool, 808 publish_decorations: bool,
772 sender: Sender<Task>, 809 task_sender: Sender<Task>,
773 subscriptions: Vec<FileId>, 810 subscriptions: Vec<FileId>,
774) { 811) {
775 log::trace!("updating notifications for {:?}", subscriptions); 812 log::trace!("updating notifications for {:?}", subscriptions);
@@ -785,7 +822,7 @@ fn update_file_notifications_on_threadpool(
785 } 822 }
786 Ok(params) => { 823 Ok(params) => {
787 let not = notification_new::<req::PublishDiagnostics>(params); 824 let not = notification_new::<req::PublishDiagnostics>(params);
788 sender.send(Task::Notify(not)).unwrap(); 825 task_sender.send(Task::Notify(not)).unwrap();
789 } 826 }
790 } 827 }
791 } 828 }
@@ -798,7 +835,7 @@ fn update_file_notifications_on_threadpool(
798 } 835 }
799 Ok(params) => { 836 Ok(params) => {
800 let not = notification_new::<req::PublishDecorations>(params); 837 let not = notification_new::<req::PublishDecorations>(params);
801 sender.send(Task::Notify(not)).unwrap(); 838 task_sender.send(Task::Notify(not)).unwrap();
802 } 839 }
803 } 840 }
804 } 841 }
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 8e43f0575..666f2ee29 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -674,8 +674,7 @@ pub fn handle_code_action(
674 res.push(action.into()); 674 res.push(action.into());
675 } 675 }
676 676
677 for fix in world.check_watcher.read().fixes_for(&params.text_document.uri).into_iter().flatten() 677 for fix in world.check_watcher.fixes_for(&params.text_document.uri).into_iter().flatten() {
678 {
679 let fix_range = fix.location.range.conv_with(&line_index); 678 let fix_range = fix.location.range.conv_with(&line_index);
680 if fix_range.intersection(&range).is_none() { 679 if fix_range.intersection(&range).is_none() {
681 continue; 680 continue;
@@ -895,7 +894,7 @@ pub fn publish_diagnostics(
895 tags: None, 894 tags: None,
896 }) 895 })
897 .collect(); 896 .collect();
898 if let Some(check_diags) = world.check_watcher.read().diagnostics_for(&uri) { 897 if let Some(check_diags) = world.check_watcher.diagnostics_for(&uri) {
899 diagnostics.extend(check_diags.iter().cloned()); 898 diagnostics.extend(check_diags.iter().cloned());
900 } 899 }
901 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None }) 900 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index e7a0acfc7..3059ef9ec 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -63,7 +63,7 @@ pub struct WorldSnapshot {
63 pub workspaces: Arc<Vec<ProjectWorkspace>>, 63 pub workspaces: Arc<Vec<ProjectWorkspace>>,
64 pub analysis: Analysis, 64 pub analysis: Analysis,
65 pub latest_requests: Arc<RwLock<LatestRequests>>, 65 pub latest_requests: Arc<RwLock<LatestRequests>>,
66 pub check_watcher: Arc<RwLock<CheckState>>, 66 pub check_watcher: CheckState,
67 vfs: Arc<RwLock<Vfs>>, 67 vfs: Arc<RwLock<Vfs>>,
68} 68}
69 69
@@ -220,7 +220,7 @@ impl WorldState {
220 analysis: self.analysis_host.analysis(), 220 analysis: self.analysis_host.analysis(),
221 vfs: Arc::clone(&self.vfs), 221 vfs: Arc::clone(&self.vfs),
222 latest_requests: Arc::clone(&self.latest_requests), 222 latest_requests: Arc::clone(&self.latest_requests),
223 check_watcher: self.check_watcher.state.clone(), 223 check_watcher: (*self.check_watcher.state).clone(),
224 } 224 }
225 } 225 }
226 226