diff options
Diffstat (limited to 'crates/ra_lsp_server')
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/project_model.rs | 4 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/thread_worker.rs | 49 |
4 files changed, 52 insertions, 6 deletions
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index 4f834519c..eb4812633 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -15,9 +15,8 @@ log = "0.4.3" | |||
15 | lsp-types = { version = "0.60.0", features = ["proposed"] } | 15 | lsp-types = { version = "0.60.0", features = ["proposed"] } |
16 | rustc-hash = "1.0" | 16 | rustc-hash = "1.0" |
17 | parking_lot = "0.9.0" | 17 | parking_lot = "0.9.0" |
18 | 18 | jod-thread = "0.1.0" | |
19 | ra_vfs = "0.3.0" | 19 | ra_vfs = "0.3.0" |
20 | thread_worker = { path = "../thread_worker" } | ||
21 | ra_syntax = { path = "../ra_syntax" } | 20 | ra_syntax = { path = "../ra_syntax" } |
22 | ra_text_edit = { path = "../ra_text_edit" } | 21 | ra_text_edit = { path = "../ra_text_edit" } |
23 | ra_ide_api = { path = "../ra_ide_api" } | 22 | ra_ide_api = { path = "../ra_ide_api" } |
@@ -27,7 +26,6 @@ ra_prof = { path = "../ra_prof" } | |||
27 | ra_vfs_glob = { path = "../ra_vfs_glob" } | 26 | ra_vfs_glob = { path = "../ra_vfs_glob" } |
28 | 27 | ||
29 | [dev-dependencies] | 28 | [dev-dependencies] |
30 | jod-thread = "0.1.0" | ||
31 | tempfile = "3" | 29 | tempfile = "3" |
32 | test_utils = { path = "../test_utils" } | 30 | test_utils = { path = "../test_utils" } |
33 | 31 | ||
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs index 2c5d7c72d..69a577b3e 100644 --- a/crates/ra_lsp_server/src/lib.rs +++ b/crates/ra_lsp_server/src/lib.rs | |||
@@ -8,6 +8,7 @@ mod project_model; | |||
8 | pub mod req; | 8 | pub mod req; |
9 | pub mod config; | 9 | pub mod config; |
10 | mod world; | 10 | mod world; |
11 | mod thread_worker; | ||
11 | 12 | ||
12 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; | 13 | pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; |
13 | pub use crate::{ | 14 | pub use crate::{ |
diff --git a/crates/ra_lsp_server/src/project_model.rs b/crates/ra_lsp_server/src/project_model.rs index ad59cde64..6234563f2 100644 --- a/crates/ra_lsp_server/src/project_model.rs +++ b/crates/ra_lsp_server/src/project_model.rs | |||
@@ -1,8 +1,6 @@ | |||
1 | use std::path::PathBuf; | 1 | use std::path::PathBuf; |
2 | 2 | ||
3 | use thread_worker::Worker; | 3 | use crate::{thread_worker::Worker, Result}; |
4 | |||
5 | use crate::Result; | ||
6 | 4 | ||
7 | pub use ra_project_model::{ | 5 | pub use ra_project_model::{ |
8 | CargoWorkspace, Package, ProjectWorkspace, Sysroot, Target, TargetKind, | 6 | CargoWorkspace, Package, ProjectWorkspace, Sysroot, Target, TargetKind, |
diff --git a/crates/ra_lsp_server/src/thread_worker.rs b/crates/ra_lsp_server/src/thread_worker.rs new file mode 100644 index 000000000..68e5c124d --- /dev/null +++ b/crates/ra_lsp_server/src/thread_worker.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | //! Small utility to correctly spawn crossbeam-channel based worker threads. | ||
2 | |||
3 | use crossbeam_channel::{bounded, unbounded, Receiver, Sender}; | ||
4 | |||
5 | /// A wrapper around event-processing thread with automatic shutdown semantics. | ||
6 | pub struct Worker<I, O> { | ||
7 | // XXX: field order is significant here. | ||
8 | // | ||
9 | // In Rust, fields are dropped in the declaration order, and we rely on this | ||
10 | // here. We must close input first, so that the `thread` (who holds the | ||
11 | // opposite side of the channel) noticed shutdown. Then, we must join the | ||
12 | // thread, but we must keep out alive so that the thread does not panic. | ||
13 | // | ||
14 | // Note that a potential problem here is that we might drop some messages | ||
15 | // from receiver on the floor. This is ok for rust-analyzer: we have only a | ||
16 | // single client, so, if we are shutting down, nobody is interested in the | ||
17 | // unfinished work anyway! | ||
18 | sender: Sender<I>, | ||
19 | _thread: jod_thread::JoinHandle<()>, | ||
20 | receiver: Receiver<O>, | ||
21 | } | ||
22 | |||
23 | impl<I, O> Worker<I, O> { | ||
24 | pub fn spawn<F>(name: &'static str, buf: usize, f: F) -> Worker<I, O> | ||
25 | where | ||
26 | F: FnOnce(Receiver<I>, Sender<O>) + Send + 'static, | ||
27 | I: Send + 'static, | ||
28 | O: Send + 'static, | ||
29 | { | ||
30 | // Set up worker channels in a deadlock-avoiding way. If one sets both input | ||
31 | // and output buffers to a fixed size, a worker might get stuck. | ||
32 | let (sender, input_receiver) = bounded::<I>(buf); | ||
33 | let (output_sender, receiver) = unbounded::<O>(); | ||
34 | let _thread = jod_thread::Builder::new() | ||
35 | .name(name.to_string()) | ||
36 | .spawn(move || f(input_receiver, output_sender)) | ||
37 | .expect("failed to spawn a thread"); | ||
38 | Worker { sender, _thread, receiver } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | impl<I, O> Worker<I, O> { | ||
43 | pub fn sender(&self) -> &Sender<I> { | ||
44 | &self.sender | ||
45 | } | ||
46 | pub fn receiver(&self) -> &Receiver<O> { | ||
47 | &self.receiver | ||
48 | } | ||
49 | } | ||