commit 24940929b64b27b5f7970e23792819449ae3aa7c
parent 89a7457aab9f8d5c44d110f988cbf2e76b048a59
Author: MTRNord <mtrnord1@gmail.com>
Date: Thu, 5 Aug 2021 11:27:27 +0200
make sure that we not violate the fact that xplane plugins are not threadsafe
Diffstat:
5 files changed, 73 insertions(+), 107 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -14,7 +14,6 @@ crate-type = ["cdylib"]
xplm = "0.3.1"
anyhow = "1.0.42"
thiserror = "1.0.26"
-tokio = { version = "1", features = ["full"] }
[profile.release]
lto = true
\ No newline at end of file
diff --git a/src/energy.rs b/src/energy.rs
@@ -1,7 +1,4 @@
-use std::{
- fmt::Display,
- sync::{Arc, RwLock},
-};
+use std::{fmt::Display, rc::Rc};
use xplm::data::{borrowed::DataRef, ArrayRead, DataRead, ReadWrite};
@@ -12,47 +9,37 @@ pub(crate) struct EnergyRefs {
pub(crate) battery: DataRef<[i32], ReadWrite>,
}
-unsafe impl Send for EnergyRefs {}
-unsafe impl Sync for EnergyRefs {}
-
#[derive(Clone)]
pub(crate) struct Energy {
- inner: Arc<RwLock<EnergyRefs>>,
+ inner: Rc<EnergyRefs>,
}
impl Energy {
pub(crate) fn new() -> Result<Self, Error> {
Ok(Self {
- inner: Arc::new(RwLock::new(EnergyRefs {
+ inner: Rc::new(EnergyRefs {
gpu_on: DataRef::find("sim/cockpit/electrical/gpu_on")?.writeable()?,
battery: DataRef::find("sim/cockpit2/electrical/battery_on")?.writeable()?,
- })),
+ }),
})
}
- pub(crate) fn gpu_on(&self) -> Result<bool, Error> {
- let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
- Ok(lock.gpu_on.get())
+ pub(crate) fn gpu_on(&self) -> bool {
+ self.inner.gpu_on.get()
}
- pub(crate) fn battery_on(&self) -> Result<bool, Error> {
- let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
- Ok(lock.battery.as_vec().contains(&1))
+ pub(crate) fn battery_on(&self) -> bool {
+ self.inner.battery.as_vec().contains(&1)
}
}
impl Display for Energy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let lock = self.inner.read();
- if let Ok(lock) = lock {
- write!(
- f,
- "GPU enabled: {}, Battery enabled: {}",
- lock.gpu_on.get(),
- lock.battery.as_vec().contains(&1),
- )
- } else {
- Ok(())
- }
+ write!(
+ f,
+ "GPU enabled: {}, Battery enabled: {}",
+ self.inner.gpu_on.get(),
+ self.inner.battery.as_vec().contains(&1),
+ )
}
}
diff --git a/src/error.rs b/src/error.rs
@@ -4,6 +4,4 @@ use thiserror::Error as ThisError;
pub(crate) enum Error {
#[error(transparent)]
FindError(#[from] xplm::data::borrowed::FindError),
- #[error("Unable to get lock")]
- UnableToGetLock,
}
diff --git a/src/lib.rs b/src/lib.rs
@@ -1,16 +1,10 @@
-use std::{
- sync::{
- atomic::{AtomicBool, Ordering},
- Arc, RwLock,
- },
- thread::JoinHandle,
-};
#[deny(unused_imports)]
#[deny(missing_docs)]
-use std::{thread, time};
-use tokio::runtime::Runtime;
+use std::thread;
+use std::time::{Duration, SystemTime};
use xplm::{
debug,
+ flight_loop::{FlightLoop, FlightLoopCallback},
plugin::{Plugin, PluginInfo},
xplane_plugin,
};
@@ -22,44 +16,48 @@ mod energy;
mod error;
mod location;
-#[derive(Clone)]
struct DataMonitorPlugin {
+ loophandler: LoopHandler,
+ flightloop: Option<FlightLoop>,
+}
+
+#[derive(Clone)]
+struct LoopHandler {
location: Location,
energy: Energy,
- thread: Arc<RwLock<Option<JoinHandle<()>>>>,
- stopped: Arc<AtomicBool>,
+ last_run: SystemTime,
}
-impl DataMonitorPlugin {
- pub(crate) fn start(&self) {
- debug("[DATAMONITOR] starting\n");
- let self_clone = self.clone();
- let thread = thread::spawn(move || {
- let delay = time::Duration::from_secs(5);
- {
- debug(format!("[DATAMONITOR] {}\n", self_clone.location));
- };
- let rt = Runtime::new().unwrap();
- loop {
- // Do stuff
- if self_clone.stopped.load(Ordering::Relaxed) {
- break;
+impl FlightLoopCallback for LoopHandler {
+ fn flight_loop(&mut self, state: &mut xplm::flight_loop::LoopState) {
+ if self.last_run.elapsed().unwrap() >= Duration::from_secs(5) {
+ let battery_on = self.energy.battery_on();
+ let gpu_on = self.energy.gpu_on();
+ let location = self.location.to_string();
+ let energy = self.energy.to_string();
+ let thread = thread::spawn(move || {
+ // Do stuff with location
+ if battery_on || gpu_on {
+ debug(format!("[DATAMONITOR] {}\n", location));
+ debug(format!("[DATAMONITOR] {}\n", energy));
}
-
- let current_location = self_clone.location.clone();
- let current_energy = self_clone.energy.clone();
- rt.spawn(async move {
- // Do stuff with location
- if current_energy.battery_on().unwrap() || current_energy.gpu_on().unwrap() {
- debug(format!("[DATAMONITOR] {}\n", current_location));
- debug(format!("[DATAMONITOR] {}\n", current_energy));
- }
- });
- thread::sleep(delay);
+ });
+ if let Err(e) = thread.join() {
+ debug(format!("[DATAMONITOR][ERROR] {:?}\n", e));
}
- });
- let mut lock = self.thread.write().unwrap();
- *lock = Some(thread);
+ self.last_run = SystemTime::now();
+ }
+ state.call_next_loop()
+ }
+}
+
+impl DataMonitorPlugin {
+ pub(crate) fn start(&mut self) {
+ debug("[DATAMONITOR] starting\n");
+ let mut flight_loop = FlightLoop::new(self.loophandler.clone());
+ flight_loop.schedule_immediate();
+ self.flightloop = Some(flight_loop);
+ debug("[DATAMONITOR] started\n");
}
}
@@ -75,11 +73,15 @@ impl Plugin for DataMonitorPlugin {
if let Err(ref e) = energy {
debug(format!("[DATAMONITOR][ERROR] Energy init: {:?}\n", e));
}
- let plugin = DataMonitorPlugin {
+
+ let loophandler = LoopHandler {
location: location.unwrap(),
energy: energy.unwrap(),
- thread: Arc::new(RwLock::new(None)),
- stopped: Arc::new(AtomicBool::new(false)),
+ last_run: SystemTime::now(),
+ };
+ let plugin = DataMonitorPlugin {
+ loophandler,
+ flightloop: None,
};
Ok(plugin)
}
@@ -89,13 +91,6 @@ impl Plugin for DataMonitorPlugin {
}
fn disable(&mut self) {
debug("[DATAMONITOR][INFO] Stopping threads\n");
- self.stopped.swap(true, Ordering::Release);
- let mut lock = self.thread.write().unwrap();
- let thread = std::mem::replace(&mut *lock, None);
- if let Some(thread) = thread {
- thread.join().unwrap();
- debug("[DATAMONITOR][INFO] Stopped threads\n");
- }
}
fn info(&self) -> xplm::plugin::PluginInfo {
diff --git a/src/location.rs b/src/location.rs
@@ -1,7 +1,4 @@
-use std::{
- fmt::Display,
- sync::{Arc, RwLock},
-};
+use std::{fmt::Display, rc::Rc};
use xplm::data::{borrowed::DataRef, DataRead, ReadOnly};
@@ -12,46 +9,36 @@ pub(crate) struct LocationRefs {
pub(crate) longitude: DataRef<f64, ReadOnly>,
}
-unsafe impl Send for LocationRefs {}
-unsafe impl Sync for LocationRefs {}
-
#[derive(Clone)]
pub(crate) struct Location {
- inner: Arc<RwLock<LocationRefs>>,
+ inner: Rc<LocationRefs>,
}
impl Location {
pub(crate) fn new() -> Result<Self, Error> {
Ok(Self {
- inner: Arc::new(RwLock::new(LocationRefs {
+ inner: Rc::new(LocationRefs {
latitude: DataRef::find("sim/flightmodel/position/latitude")?,
longitude: DataRef::find("sim/flightmodel/position/longitude")?,
- })),
+ }),
})
}
- pub(crate) fn lat(&self) -> Result<f64, Error> {
- let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
- Ok(lock.latitude.get())
+ pub(crate) fn lat(&self) -> f64 {
+ self.inner.latitude.get()
}
- pub(crate) fn lon(&self) -> Result<f64, Error> {
- let lock = self.inner.read().or(Err(Error::UnableToGetLock))?;
- Ok(lock.longitude.get())
+ pub(crate) fn lon(&self) -> f64 {
+ self.inner.longitude.get()
}
}
impl Display for Location {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- let lock = self.inner.read();
- if let Ok(lock) = lock {
- write!(
- f,
- "Latitude: {}, Longitude: {}",
- lock.latitude.get(),
- lock.longitude.get()
- )
- } else {
- Ok(())
- }
+ write!(
+ f,
+ "Latitude: {}, Longitude: {}",
+ self.inner.latitude.get(),
+ self.inner.longitude.get()
+ )
}
}