aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_cargo_watch/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_cargo_watch/src')
-rw-r--r--crates/ra_cargo_watch/src/lib.rs61
1 files changed, 11 insertions, 50 deletions
diff --git a/crates/ra_cargo_watch/src/lib.rs b/crates/ra_cargo_watch/src/lib.rs
index 7c525c430..c67ec39d4 100644
--- a/crates/ra_cargo_watch/src/lib.rs
+++ b/crates/ra_cargo_watch/src/lib.rs
@@ -12,7 +12,6 @@ use std::{
12 io::{BufRead, BufReader}, 12 io::{BufRead, BufReader},
13 path::{Path, PathBuf}, 13 path::{Path, PathBuf},
14 process::{Command, Stdio}, 14 process::{Command, Stdio},
15 thread::JoinHandle,
16 time::Instant, 15 time::Instant,
17}; 16};
18 17
@@ -36,9 +35,10 @@ pub struct CheckOptions {
36/// The spawned thread is shut down when this struct is dropped. 35/// The spawned thread is shut down when this struct is dropped.
37#[derive(Debug)] 36#[derive(Debug)]
38pub struct CheckWatcher { 37pub struct CheckWatcher {
38 // XXX: drop order is significant
39 cmd_send: Sender<CheckCommand>,
40 handle: Option<jod_thread::JoinHandle<()>>,
39 pub task_recv: Receiver<CheckTask>, 41 pub task_recv: Receiver<CheckTask>,
40 cmd_send: Option<Sender<CheckCommand>>,
41 handle: Option<JoinHandle<()>>,
42} 42}
43 43
44impl CheckWatcher { 44impl CheckWatcher {
@@ -47,39 +47,16 @@ impl CheckWatcher {
47 47
48 let (task_send, task_recv) = unbounded::<CheckTask>(); 48 let (task_send, task_recv) = unbounded::<CheckTask>();
49 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>(); 49 let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
50 let handle = std::thread::spawn(move || { 50 let handle = jod_thread::spawn(move || {
51 let mut check = CheckWatcherThread::new(options, workspace_root); 51 let mut check = CheckWatcherThread::new(options, workspace_root);
52 check.run(&task_send, &cmd_recv); 52 check.run(&task_send, &cmd_recv);
53 }); 53 });
54 CheckWatcher { task_recv, cmd_send: Some(cmd_send), handle: Some(handle) } 54 CheckWatcher { task_recv, cmd_send, handle: Some(handle) }
55 }
56
57 /// Returns a CheckWatcher that doesn't actually do anything
58 pub fn dummy() -> CheckWatcher {
59 CheckWatcher { task_recv: never(), cmd_send: None, handle: None }
60 } 55 }
61 56
62 /// Schedule a re-start of the cargo check worker. 57 /// Schedule a re-start of the cargo check worker.
63 pub fn update(&self) { 58 pub fn update(&self) {
64 if let Some(cmd_send) = &self.cmd_send { 59 self.cmd_send.send(CheckCommand::Update).unwrap();
65 cmd_send.send(CheckCommand::Update).unwrap();
66 }
67 }
68}
69
70impl std::ops::Drop for CheckWatcher {
71 fn drop(&mut self) {
72 if let Some(handle) = self.handle.take() {
73 // Take the sender out of the option
74 let cmd_send = self.cmd_send.take();
75
76 // Dropping the sender finishes the thread loop
77 drop(cmd_send);
78
79 // Join the thread, it should finish shortly. We don't really care
80 // whether it panicked, so it is safe to ignore the result
81 let _ = handle.join();
82 }
83 } 60 }
84} 61}
85 62
@@ -237,8 +214,9 @@ pub struct DiagnosticWithFixes {
237/// The correct way to dispose of the thread is to drop it, on which the 214/// The correct way to dispose of the thread is to drop it, on which the
238/// sub-process will be killed, and the thread will be joined. 215/// sub-process will be killed, and the thread will be joined.
239struct WatchThread { 216struct WatchThread {
240 handle: Option<JoinHandle<()>>, 217 // XXX: drop order is significant
241 message_recv: Receiver<CheckEvent>, 218 message_recv: Receiver<CheckEvent>,
219 _handle: Option<jod_thread::JoinHandle<()>>,
242} 220}
243 221
244enum CheckEvent { 222enum CheckEvent {
@@ -333,7 +311,7 @@ pub fn run_cargo(
333 311
334impl WatchThread { 312impl WatchThread {
335 fn dummy() -> WatchThread { 313 fn dummy() -> WatchThread {
336 WatchThread { handle: None, message_recv: never() } 314 WatchThread { message_recv: never(), _handle: None }
337 } 315 }
338 316
339 fn new(options: &CheckOptions, workspace_root: &Path) -> WatchThread { 317 fn new(options: &CheckOptions, workspace_root: &Path) -> WatchThread {
@@ -352,7 +330,7 @@ impl WatchThread {
352 let (message_send, message_recv) = unbounded(); 330 let (message_send, message_recv) = unbounded();
353 let workspace_root = workspace_root.to_owned(); 331 let workspace_root = workspace_root.to_owned();
354 let handle = if options.enable { 332 let handle = if options.enable {
355 Some(std::thread::spawn(move || { 333 Some(jod_thread::spawn(move || {
356 // If we trigger an error here, we will do so in the loop instead, 334 // If we trigger an error here, we will do so in the loop instead,
357 // which will break out of the loop, and continue the shutdown 335 // which will break out of the loop, and continue the shutdown
358 let _ = message_send.send(CheckEvent::Begin); 336 let _ = message_send.send(CheckEvent::Begin);
@@ -383,23 +361,6 @@ impl WatchThread {
383 } else { 361 } else {
384 None 362 None
385 }; 363 };
386 WatchThread { handle, message_recv } 364 WatchThread { message_recv, _handle: handle }
387 }
388}
389
390impl std::ops::Drop for WatchThread {
391 fn drop(&mut self) {
392 if let Some(handle) = self.handle.take() {
393 // Replace our reciever with dummy one, so we can drop and close the
394 // one actually communicating with the thread
395 let recv = std::mem::replace(&mut self.message_recv, never());
396
397 // Dropping the original reciever initiates thread sub-process shutdown
398 drop(recv);
399
400 // Join the thread, it should finish shortly. We don't really care
401 // whether it panicked, so it is safe to ignore the result
402 let _ = handle.join();
403 }
404 } 365 }
405} 366}