xplane-datamonitor

A WIP tool to show data inside grafana
git clone git://archive.git.mtrnord.blog/MTRNord/xplane-datamonitor.git
Log | Files | Refs

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:
MCargo.toml | 1-
Msrc/energy.rs | 41++++++++++++++---------------------------
Msrc/error.rs | 2--
Msrc/lib.rs | 95+++++++++++++++++++++++++++++++++++++------------------------------------------
Msrc/location.rs | 41++++++++++++++---------------------------
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() + ) } }