diff options
-rw-r--r-- | crates/ra_cargo_watch/src/lib.rs | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs index 70afd7f8a..4af26ff8c 100644 --- a/crates/ra_cargo_watch/src/lib.rs +++ b/crates/ra_cargo_watch/src/lib.rs | |||
@@ -32,12 +32,13 @@ pub struct CheckOptions { | |||
32 | /// CheckWatcher wraps the shared state and communication machinery used for | 32 | /// CheckWatcher wraps the shared state and communication machinery used for |
33 | /// running `cargo check` (or other compatible command) and providing | 33 | /// running `cargo check` (or other compatible command) and providing |
34 | /// diagnostics based on the output. | 34 | /// diagnostics based on the output. |
35 | /// The spawned thread is shut down when this struct is dropped. | ||
35 | #[derive(Debug)] | 36 | #[derive(Debug)] |
36 | pub struct CheckWatcher { | 37 | pub struct CheckWatcher { |
37 | pub task_recv: Receiver<CheckTask>, | 38 | pub task_recv: Receiver<CheckTask>, |
38 | pub cmd_send: Sender<CheckCommand>, | 39 | pub cmd_send: Sender<CheckCommand>, |
39 | pub shared: Arc<RwLock<CheckWatcherSharedState>>, | 40 | pub shared: Arc<RwLock<CheckWatcherSharedState>>, |
40 | handle: JoinHandle<()>, | 41 | handle: Option<JoinHandle<()>>, |
41 | } | 42 | } |
42 | 43 | ||
43 | impl CheckWatcher { | 44 | impl CheckWatcher { |
@@ -52,8 +53,7 @@ impl CheckWatcher { | |||
52 | let mut check = CheckWatcherState::new(options, workspace_root, shared_); | 53 | let mut check = CheckWatcherState::new(options, workspace_root, shared_); |
53 | check.run(&task_send, &cmd_recv); | 54 | check.run(&task_send, &cmd_recv); |
54 | }); | 55 | }); |
55 | 56 | CheckWatcher { task_recv, cmd_send, handle: Some(handle), shared } | |
56 | CheckWatcher { task_recv, cmd_send, handle, shared } | ||
57 | } | 57 | } |
58 | 58 | ||
59 | /// Schedule a re-start of the cargo check worker. | 59 | /// Schedule a re-start of the cargo check worker. |
@@ -62,13 +62,21 @@ impl CheckWatcher { | |||
62 | } | 62 | } |
63 | } | 63 | } |
64 | 64 | ||
65 | pub struct CheckWatcherState { | 65 | impl std::ops::Drop for CheckWatcher { |
66 | options: CheckOptions, | 66 | fn drop(&mut self) { |
67 | workspace_root: PathBuf, | 67 | if let Some(handle) = self.handle.take() { |
68 | running: bool, | 68 | // Replace our reciever with dummy one, so we can drop and close the |
69 | watcher: WatchThread, | 69 | // one actually communicating with the thread |
70 | last_update_req: Option<Instant>, | 70 | let recv = std::mem::replace(&mut self.task_recv, crossbeam_channel::never()); |
71 | shared: Arc<RwLock<CheckWatcherSharedState>>, | 71 | |
72 | // Dropping the original reciever finishes the thread loop | ||
73 | drop(recv); | ||
74 | |||
75 | // Join the thread, it should finish shortly. We don't really care | ||
76 | // whether it panicked, so it is safe to ignore the result | ||
77 | let _ = handle.join(); | ||
78 | } | ||
79 | } | ||
72 | } | 80 | } |
73 | 81 | ||
74 | #[derive(Debug)] | 82 | #[derive(Debug)] |
@@ -153,6 +161,14 @@ pub enum CheckCommand { | |||
153 | Update, | 161 | Update, |
154 | } | 162 | } |
155 | 163 | ||
164 | struct CheckWatcherState { | ||
165 | options: CheckOptions, | ||
166 | workspace_root: PathBuf, | ||
167 | watcher: WatchThread, | ||
168 | last_update_req: Option<Instant>, | ||
169 | shared: Arc<RwLock<CheckWatcherSharedState>>, | ||
170 | } | ||
171 | |||
156 | impl CheckWatcherState { | 172 | impl CheckWatcherState { |
157 | pub fn new( | 173 | pub fn new( |
158 | options: CheckOptions, | 174 | options: CheckOptions, |
@@ -163,7 +179,6 @@ impl CheckWatcherState { | |||
163 | CheckWatcherState { | 179 | CheckWatcherState { |
164 | options, | 180 | options, |
165 | workspace_root, | 181 | workspace_root, |
166 | running: false, | ||
167 | watcher, | 182 | watcher, |
168 | last_update_req: None, | 183 | last_update_req: None, |
169 | shared, | 184 | shared, |
@@ -171,19 +186,21 @@ impl CheckWatcherState { | |||
171 | } | 186 | } |
172 | 187 | ||
173 | pub fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) { | 188 | pub fn run(&mut self, task_send: &Sender<CheckTask>, cmd_recv: &Receiver<CheckCommand>) { |
174 | self.running = true; | 189 | loop { |
175 | while self.running { | ||
176 | select! { | 190 | select! { |
177 | recv(&cmd_recv) -> cmd => match cmd { | 191 | recv(&cmd_recv) -> cmd => match cmd { |
178 | Ok(cmd) => self.handle_command(cmd), | 192 | Ok(cmd) => self.handle_command(cmd), |
179 | Err(RecvError) => { | 193 | Err(RecvError) => { |
180 | // Command channel has closed, so shut down | 194 | // Command channel has closed, so shut down |
181 | self.running = false; | 195 | break; |
182 | }, | 196 | }, |
183 | }, | 197 | }, |
184 | recv(self.watcher.message_recv) -> msg => match msg { | 198 | recv(self.watcher.message_recv) -> msg => match msg { |
185 | Ok(msg) => self.handle_message(msg, task_send), | 199 | Ok(msg) => self.handle_message(msg, task_send), |
186 | Err(RecvError) => {}, | 200 | Err(RecvError) => { |
201 | // Task channel has closed, so shut down | ||
202 | break; | ||
203 | }, | ||
187 | } | 204 | } |
188 | }; | 205 | }; |
189 | 206 | ||