diff options
author | Aleksey Kladov <[email protected]> | 2019-08-30 18:23:28 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-08-30 18:32:59 +0100 |
commit | 983de30a567f2cb4d9e28e12702e509ca713da62 (patch) | |
tree | 9bdd597701e1b150492a78b6c85ff856f0fc51bd /crates/ra_lsp_server/src/thread_worker.rs | |
parent | 7cc14a759699dd2503199116521e9ba65e3f1aa8 (diff) |
inline thread-worker
Diffstat (limited to 'crates/ra_lsp_server/src/thread_worker.rs')
-rw-r--r-- | crates/ra_lsp_server/src/thread_worker.rs | 49 |
1 files changed, 49 insertions, 0 deletions
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 | } | ||