From 1bdb46168c67b6fc08873eb299d598b1953025fc Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 1 Nov 2022 15:01:27 +0100 Subject: [PATCH 1/2] Add explicit type to make channel purpose clearer --- crates/fj-host/src/evaluator.rs | 9 ++++++--- crates/fj-host/src/watcher.rs | 10 +++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/fj-host/src/evaluator.rs b/crates/fj-host/src/evaluator.rs index 1ba7eeb5e..74bae4038 100644 --- a/crates/fj-host/src/evaluator.rs +++ b/crates/fj-host/src/evaluator.rs @@ -6,7 +6,7 @@ use crate::{Error, Evaluation, Model}; /// Evaluates a model in a background thread pub struct Evaluator { - trigger_tx: Sender<()>, + trigger_tx: Sender, event_rx: Receiver, } @@ -17,7 +17,7 @@ impl Evaluator { let (trigger_tx, trigger_rx) = crossbeam_channel::bounded(0); thread::spawn(move || loop { - let () = trigger_rx + let TriggerEvaluation = trigger_rx .recv() .expect("Expected channel to never disconnect"); @@ -43,7 +43,7 @@ impl Evaluator { } /// Access a channel for triggering evaluations - pub fn trigger(&self) -> Sender<()> { + pub fn trigger(&self) -> Sender { self.trigger_tx.clone() } @@ -53,6 +53,9 @@ impl Evaluator { } } +/// Command received by [`Evaluator`] through its channel +pub struct TriggerEvaluation; + /// An event emitted by [`Evaluator`] pub enum ModelEvent { /// The model has been evaluated diff --git a/crates/fj-host/src/watcher.rs b/crates/fj-host/src/watcher.rs index bbc421089..9d0374841 100644 --- a/crates/fj-host/src/watcher.rs +++ b/crates/fj-host/src/watcher.rs @@ -2,7 +2,7 @@ use std::{collections::HashSet, ffi::OsStr, path::Path, thread}; use notify::Watcher as _; -use crate::{Error, Evaluator}; +use crate::{evaluator::TriggerEvaluation, Error, Evaluator}; /// Watches a model for changes, reloading it continually pub struct Watcher { @@ -65,7 +65,9 @@ impl Watcher { // application is being shut down. // // Either way, not much we can do about it here. - watch_tx.send(()).expect("Channel is disconnected"); + watch_tx + .send(TriggerEvaluation) + .expect("Channel is disconnected"); } }, )?; @@ -82,7 +84,9 @@ impl Watcher { // Will panic, if the receiving end has panicked. Not much we can do // about that, if it happened. thread::spawn(move || { - watch_tx_2.send(()).expect("Channel is disconnected") + watch_tx_2 + .send(TriggerEvaluation) + .expect("Channel is disconnected") }); Ok(Self { From d5ee6ff926b70f24c54cd43e93b0a9c4338cf9fd Mon Sep 17 00:00:00 2001 From: Hanno Braun Date: Tue, 1 Nov 2022 15:06:10 +0100 Subject: [PATCH 2/2] Fix panic when quitting application This is the panic this commit fixes: ``` thread '' panicked at 'Expected channel to never disconnect: RecvError', crates/fj-host/src/evaluator.rs:22:18 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace ``` --- crates/fj-host/src/evaluator.rs | 34 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/crates/fj-host/src/evaluator.rs b/crates/fj-host/src/evaluator.rs index 74bae4038..9e1a65fba 100644 --- a/crates/fj-host/src/evaluator.rs +++ b/crates/fj-host/src/evaluator.rs @@ -16,24 +16,26 @@ impl Evaluator { let (event_tx, event_rx) = crossbeam_channel::bounded(0); let (trigger_tx, trigger_rx) = crossbeam_channel::bounded(0); - thread::spawn(move || loop { - let TriggerEvaluation = trigger_rx - .recv() - .expect("Expected channel to never disconnect"); + thread::spawn(move || { + while let Ok(TriggerEvaluation) = trigger_rx.recv() { + let evaluation = match model.evaluate() { + Ok(evaluation) => evaluation, + Err(err) => { + event_tx + .send(ModelEvent::Error(err)) + .expect("Expected channel to never disconnect"); + continue; + } + }; - let evaluation = match model.evaluate() { - Ok(evaluation) => evaluation, - Err(err) => { - event_tx - .send(ModelEvent::Error(err)) - .expect("Expected channel to never disconnect"); - continue; - } - }; + event_tx + .send(ModelEvent::Evaluation(evaluation)) + .expect("Expected channel to never disconnect"); + } - event_tx - .send(ModelEvent::Evaluation(evaluation)) - .expect("Expected channel to never disconnect"); + // The channel is disconnected, which means this instance of + // `Evaluator`, as well as all `Sender`s created from it, have been + // dropped. We're done. }); Self {