From 7ea1f41286554b64d5fc70a039f18e13a8a6293d Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 23 Sep 2022 10:50:09 +1200 Subject: [PATCH] Convert chunk of daemon to use async mutex --- CHANGELOG.md | 5 +- Cargo.lock | 3 +- daemon/Cargo.toml | 3 +- daemon/src/ctrl_anime/mod.rs | 35 ++-- daemon/src/ctrl_anime/zbus.rs | 170 +++++++--------- daemon/src/ctrl_aura/controller.rs | 57 +++--- daemon/src/ctrl_aura/zbus.rs | 193 +++++++----------- daemon/src/ctrl_platform.rs | 17 +- daemon/src/ctrl_power.rs | 19 +- daemon/src/ctrl_profiles/controller.rs | 11 +- daemon/src/ctrl_profiles/zbus.rs | 267 +++++++++++-------------- daemon/src/ctrl_supported.rs | 2 +- daemon/src/daemon.rs | 15 +- daemon/src/lib.rs | 26 +-- design-patterns.md | 110 ++++++---- rog-platform/src/platform.rs | 2 +- 16 files changed, 435 insertions(+), 500 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecbca84c..aed342bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,10 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use loops to ensure that mutex is gained for LED changes. - asusctl now uses tokio for async runtime. This helps simplify some code. ### Breaking -- DBUS: all charge control methods renamed: +- DBUS: all charge control methods renamed to: - `ChargeControlEndThreshold` - `SetChargeControlEndThreshold` - `NotifyChargeControlEndThreshold` + - `PanelOd` (form PanelOverdrive) + - `SetPanelOd` + - `NotifyPanelOd` ## [v4.4.0] - 2022-08-29 ### Added diff --git a/Cargo.lock b/Cargo.lock index cb05ba50..87f21e71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,12 +572,11 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" [[package]] name = "daemon" -version = "4.4.0" +version = "4.5.0-rc1" dependencies = [ "async-trait", "concat-idents", "env_logger", - "inotify", "log", "logind-zbus", "rog_anime", diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 7098e423..ad498d8d 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "daemon" -version = "4.4.0" +version = "4.5.0-rc1" license = "MPL-2.0" readme = "README.md" authors = ["Luke "] @@ -44,5 +44,4 @@ toml = "^0.5.8" # Device control sysfs-class = "^0.1.2" # used for backlight control and baord ID -inotify = { version = "0.10.0", default-features = false } concat-idents = "1.1.3" \ No newline at end of file diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 221ee250..0de821d0 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -1,6 +1,7 @@ pub mod config; pub mod zbus; +use ::zbus::export::futures_util::lock::{Mutex, MutexGuard}; use ::zbus::SignalContext; use async_trait::async_trait; use log::{error, info, warn}; @@ -14,12 +15,7 @@ use rog_anime::{ }; use rog_platform::{hid_raw::HidRaw, supported::AnimeSupportedFunctions, usb_raw::USBRaw}; use std::sync::atomic::{AtomicBool, Ordering}; -use std::{ - convert::TryFrom, - error::Error, - sync::{Arc, Mutex, MutexGuard}, - thread::sleep, -}; +use std::{convert::TryFrom, error::Error, sync::Arc, thread::sleep}; use crate::{error::RogError, GetSupported}; @@ -85,6 +81,7 @@ impl CtrlAnime { // The only reason for this outer thread is to prevent blocking while waiting for the // next spawned thread to exit + // TODO: turn this in to async task (maybe? COuld still risk blocking main thread) std::thread::Builder::new() .name("AniMe system thread start".into()) .spawn(move || { @@ -95,7 +92,7 @@ impl CtrlAnime { let thread_running; let anime_type; loop { - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { thread_exit = lock.thread_exit.clone(); thread_running = lock.thread_running.clone(); anime_type = lock.anime_type; @@ -139,9 +136,10 @@ impl CtrlAnime { .ok(); false // Don't exit yet }) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - AnimeError::NoFrames + .map(|r| Ok(r)) + .unwrap_or_else(|| { + warn!("rog_anime::run_animation:callback failed"); + Err(AnimeError::NoFrames) }) }) { warn!("rog_anime::run_animation:Animation {}", err); @@ -150,7 +148,7 @@ impl CtrlAnime { } ActionData::Image(image) => { once = false; - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { lock.write_data_buffer(image.as_ref().clone()) .map_err(|e| error!("{}", e)) .ok(); @@ -171,7 +169,7 @@ impl CtrlAnime { } } // Clear the display on exit - if let Ok(lock) = inner.try_lock() { + if let Some(lock) = inner.try_lock() { if let Ok(data) = AnimeDataBuffer::from_vec(anime_type, vec![0u8; anime_type.data_length()]) .map_err(|e| error!("{}", e)) @@ -249,25 +247,25 @@ impl crate::CtrlTask for CtrlAnimeTask { // Loop is required to try an attempt to get the mutex *without* blocking // other threads - it is possible to end up with deadlocks otherwise. move || loop { - if let Ok(lock) = inner1.clone().try_lock() { + if let Some(lock) = inner1.try_lock() { run_action(true, lock, inner1.clone()); break; } }, move || loop { - if let Ok(lock) = inner2.clone().try_lock() { + if let Some(lock) = inner2.try_lock() { run_action(false, lock, inner2.clone()); break; } }, move || loop { - if let Ok(lock) = inner3.clone().try_lock() { + if let Some(lock) = inner3.try_lock() { run_action(true, lock, inner3.clone()); break; } }, move || loop { - if let Ok(lock) = inner4.clone().try_lock() { + if let Some(lock) = inner4.try_lock() { run_action(false, lock, inner4.clone()); break; } @@ -281,9 +279,10 @@ impl crate::CtrlTask for CtrlAnimeTask { pub struct CtrlAnimeReloader(pub Arc>); +#[async_trait] impl crate::Reloadable for CtrlAnimeReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(lock) = self.0.try_lock() { + async fn reload(&mut self) -> Result<(), RogError> { + if let Some(lock) = self.0.try_lock() { lock.node .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; lock.node.write_bytes(&pkt_for_apply())?; diff --git a/daemon/src/ctrl_anime/zbus.rs b/daemon/src/ctrl_anime/zbus.rs index a71c3600..a1210612 100644 --- a/daemon/src/ctrl_anime/zbus.rs +++ b/daemon/src/ctrl_anime/zbus.rs @@ -1,14 +1,12 @@ -use std::sync::{Arc, Mutex}; - use async_trait::async_trait; use log::warn; use rog_anime::{ usb::{pkt_for_apply, pkt_for_set_boot, pkt_for_set_on}, AnimeDataBuffer, AnimePowerStates, }; -use zbus::{dbus_interface, Connection, SignalContext}; +use zbus::{dbus_interface, export::futures_util::lock::Mutex, Connection, SignalContext}; -use std::sync::atomic::Ordering; +use std::sync::{atomic::Ordering, Arc}; use super::CtrlAnime; @@ -16,7 +14,7 @@ pub struct CtrlAnimeZbus(pub Arc>); /// The struct with the main dbus methods requires this trait #[async_trait] -impl crate::ZbusAdd for CtrlAnimeZbus { +impl crate::ZbusRun for CtrlAnimeZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Anime", server).await; } @@ -28,127 +26,105 @@ impl crate::ZbusAdd for CtrlAnimeZbus { #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlAnimeZbus { /// Writes a data stream of length. Will force system thread to exit until it is restarted - fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - lock.write_data_buffer(input).map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - err - })?; - break 'outer; - } - } + async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> { + let lock = self.0.lock().await; + lock.thread_exit.store(true, Ordering::SeqCst); + lock.write_data_buffer(input).map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + err + })?; Ok(()) } /// Set the global AniMe brightness - fn set_brightness(&self, bright: f32) { - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - let mut bright = bright; - if bright < 0.0 { - bright = 0.0 - } else if bright > 1.0 { - bright = 1.0; - } - lock.config.brightness = bright; - lock.config.write(); - break 'outer; - } + async fn set_brightness(&self, bright: f32) { + let mut lock = self.0.lock().await; + let mut bright = bright; + if bright < 0.0 { + bright = 0.0 + } else if bright > 1.0 { + bright = 1.0; } + lock.config.brightness = bright; + lock.config.write(); } /// Set whether the AniMe is displaying images/data async fn set_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, status: bool) { - let states; - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.node - .write_bytes(&pkt_for_set_on(status)) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.config.awake_enabled = status; - lock.config.write(); + let mut lock = self.0.lock().await; + lock.node + .write_bytes(&pkt_for_set_on(status)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.config.awake_enabled = status; + lock.config.write(); - states = Some(AnimePowerStates { - brightness: lock.config.brightness.floor() as u8, - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }); - break 'outer; - } - } - if let Some(state) = states { - Self::notify_power_states(&ctxt, state).await.ok(); - } + Self::notify_power_states( + &ctxt, + AnimePowerStates { + brightness: lock.config.brightness.floor() as u8, + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }, + ) + .await + .ok(); } /// Set whether the AniMe will show boot, suspend, or off animations async fn set_boot_on_off(&self, #[zbus(signal_context)] ctxt: SignalContext<'_>, on: bool) { - let states; - 'outer: loop { - if let Ok(mut lock) = self.0.try_lock() { - lock.node - .write_bytes(&pkt_for_set_boot(on)) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.node - .write_bytes(&pkt_for_apply()) - .map_err(|err| { - warn!("rog_anime::run_animation:callback {}", err); - }) - .ok(); - lock.config.boot_anim_enabled = on; - lock.config.write(); + let mut lock = self.0.lock().await; + lock.node + .write_bytes(&pkt_for_set_boot(on)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.node + .write_bytes(&pkt_for_apply()) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.config.boot_anim_enabled = on; + lock.config.write(); - states = Some(AnimePowerStates { - brightness: lock.config.brightness.floor() as u8, - enabled: lock.config.awake_enabled, - boot_anim_enabled: lock.config.boot_anim_enabled, - }); - break 'outer; - } - } - if let Some(state) = states { - Self::notify_power_states(&ctxt, state).await.ok(); - } + Self::notify_power_states( + &ctxt, + AnimePowerStates { + brightness: lock.config.brightness.floor() as u8, + enabled: lock.config.awake_enabled, + boot_anim_enabled: lock.config.boot_anim_enabled, + }, + ) + .await + .ok(); } /// The main loop is the base system set action if the user isn't running /// the user daemon - fn run_main_loop(&self, start: bool) { + async fn run_main_loop(&self, start: bool) { if start { - 'outer: loop { - if let Ok(lock) = self.0.try_lock() { - lock.thread_exit.store(true, Ordering::SeqCst); - CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); - break 'outer; - } - } + let lock = self.0.lock().await; + lock.thread_exit.store(true, Ordering::SeqCst); + CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false); } } /// Get status of if the AniMe LEDs are on/displaying while system is awake #[dbus_interface(property)] - fn awake_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.awake_enabled; - } - true + async fn awake_enabled(&self) -> bool { + let lock = self.0.lock().await; + return lock.config.awake_enabled; } /// Get the status of if factory system-status animations are enabled #[dbus_interface(property)] - fn boot_enabled(&self) -> bool { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.boot_anim_enabled; - } - true + async fn boot_enabled(&self) -> bool { + let lock = self.0.lock().await; + return lock.config.boot_anim_enabled; } /// Notify listeners of the status of AniMe LED power and factory system-status animations diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index fc4329de..e7c1833d 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -13,9 +13,13 @@ use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed, supported::LedSupportedFunctions}; use std::collections::BTreeMap; use std::sync::Arc; -use std::sync::Mutex; -use std::sync::MutexGuard; -use zbus::{export::futures_util::StreamExt, SignalContext}; +use zbus::{ + export::futures_util::{ + lock::{Mutex, MutexGuard}, + StreamExt, + }, + SignalContext, +}; use crate::GetSupported; @@ -121,25 +125,25 @@ impl CtrlTask for CtrlKbdLedTask { // Loop so that we do aquire the lock but also don't block other // threads (prevents potential deadlocks) move || loop { - if let Ok(lock) = inner1.clone().try_lock() { + if let Some(lock) = inner1.try_lock() { load_save(true, lock); break; } }, move || loop { - if let Ok(lock) = inner2.clone().try_lock() { + if let Some(lock) = inner2.try_lock() { load_save(false, lock); break; } }, move || loop { - if let Ok(lock) = inner3.clone().try_lock() { + if let Some(lock) = inner3.try_lock() { load_save(true, lock); break; } }, move || loop { - if let Ok(lock) = inner4.clone().try_lock() { + if let Some(lock) = inner4.try_lock() { load_save(false, lock); break; } @@ -148,21 +152,20 @@ impl CtrlTask for CtrlKbdLedTask { .await; let ctrl2 = self.inner.clone(); - if let Ok(ctrl) = self.inner.lock() { - let mut watch = ctrl.kd_brightness.monitor_brightness()?; - tokio::spawn(async move { - let mut buffer = [0; 32]; - watch - .event_stream(&mut buffer) - .unwrap() - .for_each(|_| async { - if let Ok(lock) = ctrl2.try_lock() { - load_save(true, lock); - } - }) - .await; - }); - } + let ctrl = self.inner.lock().await; + let mut watch = ctrl.kd_brightness.monitor_brightness()?; + tokio::spawn(async move { + let mut buffer = [0; 32]; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + if let Some(lock) = ctrl2.try_lock() { + load_save(true, lock); + } + }) + .await; + }); Ok(()) } @@ -170,12 +173,12 @@ impl CtrlTask for CtrlKbdLedTask { pub struct CtrlKbdLedReloader(pub Arc>); +#[async_trait] impl crate::Reloadable for CtrlKbdLedReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.write_current_config_mode()?; - ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); - } + async fn reload(&mut self) -> Result<(), RogError> { + let mut ctrl = self.0.lock().await; + ctrl.write_current_config_mode()?; + ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); Ok(()) } } diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index 5392ef08..2849b749 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -8,7 +8,7 @@ use zbus::{dbus_interface, Connection, SignalContext}; use super::controller::CtrlKbdLedZbus; #[async_trait] -impl crate::ZbusAdd for CtrlKbdLedZbus { +impl crate::ZbusRun for CtrlKbdLedZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Aura", server).await; } @@ -21,11 +21,10 @@ impl crate::ZbusAdd for CtrlKbdLedZbus { impl CtrlKbdLedZbus { /// Set the keyboard brightness level (0-3) async fn set_brightness(&mut self, brightness: LedBrightness) { - if let Ok(ctrl) = self.0.try_lock() { - ctrl.set_brightness(brightness) - .map_err(|err| warn!("{}", err)) - .ok(); - } + let ctrl = self.0.lock().await; + ctrl.set_brightness(brightness) + .map_err(|err| warn!("{}", err)) + .ok(); } /// Set a variety of states, input is array of enum. @@ -64,36 +63,27 @@ impl CtrlKbdLedZbus { options: AuraPowerDev, enabled: bool, ) -> zbus::fdo::Result<()> { - let mut states = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - for p in options.tuf { - ctrl.config.enabled.set_tuf(p, enabled); - } - for p in options.x1866 { - ctrl.config.enabled.set_0x1866(p, enabled); - } - for p in options.x19b6 { - ctrl.config.enabled.set_0x19b6(p, enabled); - } - - ctrl.config.write(); - - ctrl.set_power_states().map_err(|e| { - warn!("{}", e); - e - })?; - - states = Some(AuraPowerDev::from(&ctrl.config.enabled)); - } - break; + let mut ctrl = self.0.lock().await; + for p in options.tuf { + ctrl.config.enabled.set_tuf(p, enabled); } - // Need to pull state out like this due to MutexGuard - if let Some(states) = states { - Self::notify_power_states(&ctxt, &states) - .await - .unwrap_or_else(|err| warn!("{}", err)); + for p in options.x1866 { + ctrl.config.enabled.set_0x1866(p, enabled); } + for p in options.x19b6 { + ctrl.config.enabled.set_0x19b6(p, enabled); + } + + ctrl.config.write(); + + ctrl.set_power_states().map_err(|e| { + warn!("{}", e); + e + })?; + + Self::notify_power_states(&ctxt, &AuraPowerDev::from(&ctrl.config.enabled)) + .await + .unwrap_or_else(|err| warn!("{}", err)); Ok(()) } @@ -102,21 +92,15 @@ impl CtrlKbdLedZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, effect: AuraEffect, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.set_effect(effect).map_err(|e| { - warn!("{}", e); - e - })?; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + let mut ctrl = self.0.lock().await; + + ctrl.set_effect(effect).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } @@ -127,22 +111,15 @@ impl CtrlKbdLedZbus { &self, #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(false).map_err(|e| { - warn!("{}", e); - e - })?; + let mut ctrl = self.0.lock().await; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + ctrl.toggle_mode(false).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } @@ -154,100 +131,70 @@ impl CtrlKbdLedZbus { &self, #[zbus(signal_context)] ctxt: SignalContext<'_>, ) -> zbus::fdo::Result<()> { - let mut led = None; - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.toggle_mode(true).map_err(|e| { - warn!("{}", e); - e - })?; + let mut ctrl = self.0.lock().await; - if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { - led = Some(mode.clone()); - } - break; - } - } - if let Some(led) = led { - Self::notify_led(&ctxt, led) + ctrl.toggle_mode(true).map_err(|e| { + warn!("{}", e); + e + })?; + + if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) { + Self::notify_led(&ctxt, mode.clone()) .await .unwrap_or_else(|err| warn!("{}", err)); } + Ok(()) } async fn next_led_brightness(&self) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.next_brightness().map_err(|e| { - warn!("{}", e); - e - })?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.next_brightness().map_err(|e| { + warn!("{}", e); + e + })?; Ok(()) } async fn prev_led_brightness(&self) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.prev_brightness().map_err(|e| { - warn!("{}", e); - e - })?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.prev_brightness().map_err(|e| { + warn!("{}", e); + e + })?; Ok(()) } // As property doesn't work for AuraPowerDev (complexity of serialization?) // #[dbus_interface(property)] async fn leds_enabled(&self) -> AuraPowerDev { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return AuraPowerDev::from(&ctrl.config.enabled); - } - } + let ctrl = self.0.lock().await; + return AuraPowerDev::from(&ctrl.config.enabled); } /// Return the current mode data async fn led_mode(&self) -> AuraModeNum { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.current_mode; - } - } + let ctrl = self.0.lock().await; + return ctrl.config.current_mode; } /// Return a list of available modes async fn led_modes(&self) -> BTreeMap { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.config.builtins.clone(); - } - } + let ctrl = self.0.lock().await; + return ctrl.config.builtins.clone(); } async fn per_key_raw(&self, data: PerKeyRaw) -> zbus::fdo::Result<()> { - loop { - if let Ok(mut ctrl) = self.0.try_lock() { - ctrl.write_effect_block(&data)?; - break; - } - } + let mut ctrl = self.0.lock().await; + ctrl.write_effect_block(&data)?; Ok(()) } /// Return the current LED brightness #[dbus_interface(property)] async fn led_brightness(&self) -> i8 { - loop { - if let Ok(ctrl) = self.0.try_lock() { - return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1); - } - } + let ctrl = self.0.lock().await; + ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1) } #[dbus_interface(signal)] diff --git a/daemon/src/ctrl_platform.rs b/daemon/src/ctrl_platform.rs index b22b9167..7c89e158 100644 --- a/daemon/src/ctrl_platform.rs +++ b/daemon/src/ctrl_platform.rs @@ -9,7 +9,7 @@ use std::io::{Read, Write}; use std::path::Path; use std::process::Command; use std::sync::Arc; -use std::sync::Mutex; +use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::{dbus_interface, SignalContext}; @@ -210,7 +210,7 @@ impl CtrlRogBios { }) .is_ok() { - if let Ok(mut lock) = self.config.try_lock() { + if let Some(mut lock) = self.config.try_lock() { lock.panel_od = overdrive; lock.write(); } @@ -228,7 +228,7 @@ impl CtrlRogBios { err }) .unwrap_or(false); - if let Ok(mut lock) = self.config.try_lock() { + if let Some(mut lock) = self.config.try_lock() { lock.panel_od = od; lock.write(); } @@ -241,16 +241,17 @@ impl CtrlRogBios { } #[async_trait] -impl crate::ZbusAdd for CtrlRogBios { +impl crate::ZbusRun for CtrlRogBios { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Platform", server).await; } } +#[async_trait] impl crate::Reloadable for CtrlRogBios { - fn reload(&mut self) -> Result<(), RogError> { + async fn reload(&mut self) -> Result<(), RogError> { if self.platform.has_panel_od() { - let p = if let Ok(lock) = self.config.try_lock() { + let p = if let Some(lock) = self.config.try_lock() { lock.panel_od } else { false @@ -275,7 +276,7 @@ impl CtrlTask for CtrlRogBios { move || {}, move || { info!("CtrlRogBios reloading panel_od"); - if let Ok(lock) = platform1.config.try_lock() { + if let Some(lock) = platform1.config.try_lock() { if platform1.platform.has_panel_od() { platform1 .set_panel_overdrive(lock.panel_od) @@ -290,7 +291,7 @@ impl CtrlTask for CtrlRogBios { move || {}, move || { info!("CtrlRogBios reloading panel_od"); - if let Ok(lock) = platform2.config.try_lock() { + if let Some(lock) = platform2.config.try_lock() { if platform2.platform.has_panel_od() { platform2 .set_panel_overdrive(lock.panel_od) diff --git a/daemon/src/ctrl_power.rs b/daemon/src/ctrl_power.rs index 8a008898..aef69094 100644 --- a/daemon/src/ctrl_power.rs +++ b/daemon/src/ctrl_power.rs @@ -5,8 +5,8 @@ use log::{info, warn}; use rog_platform::power::AsusPower; use rog_platform::supported::ChargeSupportedFunctions; use std::sync::Arc; -use std::sync::Mutex; use zbus::dbus_interface; +use zbus::export::futures_util::lock::Mutex; use zbus::Connection; use zbus::SignalContext; @@ -52,7 +52,7 @@ impl CtrlPower { fn charge_control_end_threshold(&self) -> u8 { loop { - if let Ok(config) = self.config.try_lock() { + if let Some(config) = self.config.try_lock() { let limit = self .power .get_charge_control_end_threshold() @@ -61,7 +61,7 @@ impl CtrlPower { err }) .unwrap_or(100); - if let Ok(mut config) = self.config.try_lock() { + if let Some(mut config) = self.config.try_lock() { config.read(); config.bat_charge_limit = limit; config.write(); @@ -80,15 +80,16 @@ impl CtrlPower { } #[async_trait] -impl crate::ZbusAdd for CtrlPower { +impl crate::ZbusRun for CtrlPower { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Charge", server).await; } } +#[async_trait] impl crate::Reloadable for CtrlPower { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(mut config) = self.config.try_lock() { + async fn reload(&mut self) -> Result<(), RogError> { + if let Some(mut config) = self.config.try_lock() { config.read(); self.set(config.bat_charge_limit)?; } @@ -113,7 +114,7 @@ impl CtrlPower { info!("Battery charge limit: {}", limit); - if let Ok(mut config) = self.config.try_lock() { + if let Some(mut config) = self.config.try_lock() { config.read(); config.bat_charge_limit = limit; config.write(); @@ -134,7 +135,7 @@ impl CtrlTask for CtrlPower { move || {}, move || { info!("CtrlCharge reloading charge limit"); - if let Ok(lock) = power1.config.try_lock() { + if let Some(lock) = power1.config.try_lock() { power1 .set(lock.bat_charge_limit) .map_err(|err| { @@ -147,7 +148,7 @@ impl CtrlTask for CtrlPower { move || {}, move || { info!("CtrlCharge reloading charge limit"); - if let Ok(lock) = power2.config.try_lock() { + if let Some(lock) = power2.config.try_lock() { power2 .set(lock.bat_charge_limit) .map_err(|err| { diff --git a/daemon/src/ctrl_profiles/controller.rs b/daemon/src/ctrl_profiles/controller.rs index 4666bbfe..ae7a3f2f 100644 --- a/daemon/src/ctrl_profiles/controller.rs +++ b/daemon/src/ctrl_profiles/controller.rs @@ -1,6 +1,8 @@ use crate::error::RogError; use crate::GetSupported; +use async_trait::async_trait; use log::{info, warn}; +use rog_platform::platform::AsusPlatform; use rog_platform::supported::PlatformProfileFunctions; use rog_profiles::error::ProfileError; use rog_profiles::{FanCurveProfiles, Profile}; @@ -9,6 +11,7 @@ use super::config::ProfileConfig; pub struct CtrlPlatformProfile { pub config: ProfileConfig, + pub platform: AsusPlatform, } impl GetSupported for CtrlPlatformProfile { @@ -36,9 +39,10 @@ impl GetSupported for CtrlPlatformProfile { } } +#[async_trait] impl crate::Reloadable for CtrlPlatformProfile { /// Fetch the active profile and use that to set all related components up - fn reload(&mut self) -> Result<(), RogError> { + async fn reload(&mut self) -> Result<(), RogError> { if let Some(curves) = &mut self.config.fan_curves { if let Ok(mut device) = FanCurveProfiles::get_device() { // There is a possibility that the curve was default zeroed, so this call initialises @@ -53,10 +57,11 @@ impl crate::Reloadable for CtrlPlatformProfile { impl CtrlPlatformProfile { pub fn new(config: ProfileConfig) -> Result { - if Profile::is_platform_profile_supported() { + let platform = AsusPlatform::new()?; + if platform.has_platform_profile() || platform.has_throttle_thermal_policy() { info!("Device has profile control available"); - let mut controller = CtrlPlatformProfile { config }; + let mut controller = CtrlPlatformProfile { config, platform }; if FanCurveProfiles::get_device().is_ok() { info!("Device has fan curves available"); if controller.config.fan_curves.is_none() { diff --git a/daemon/src/ctrl_profiles/zbus.rs b/daemon/src/ctrl_profiles/zbus.rs index 97039b64..ab8b44bf 100644 --- a/daemon/src/ctrl_profiles/zbus.rs +++ b/daemon/src/ctrl_profiles/zbus.rs @@ -1,17 +1,14 @@ use async_trait::async_trait; -use inotify::Inotify; -use inotify::WatchMask; use log::warn; use rog_profiles::fan_curve_set::CurveData; use rog_profiles::fan_curve_set::FanCurveSet; use rog_profiles::Profile; -use rog_profiles::PLATFORM_PROFILE; +use zbus::export::futures_util::lock::Mutex; use zbus::export::futures_util::StreamExt; use zbus::Connection; use zbus::SignalContext; use std::sync::Arc; -use std::sync::Mutex; use zbus::{dbus_interface, fdo::Error}; use crate::error::RogError; @@ -47,27 +44,21 @@ impl ProfileZbus { /// Toggle to next platform_profile. Names provided by `Profiles`. /// If fan-curves are supported will also activate a fan curve for profile. async fn next_profile(&mut self, #[zbus(signal_context)] ctxt: SignalContext<'_>) { - let mut profile = None; - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.set_next_profile() - .unwrap_or_else(|err| warn!("{}", err)); - ctrl.save_config(); - profile = Some(ctrl.config.active_profile); - } - if let Some(profile) = profile { - Self::notify_profile(&ctxt, profile).await.ok(); - } + let mut ctrl = self.inner.lock().await; + ctrl.set_next_profile() + .unwrap_or_else(|err| warn!("{}", err)); + ctrl.save_config(); + + Self::notify_profile(&ctxt, ctrl.config.active_profile) + .await + .ok(); } /// Fetch the active profile name - fn active_profile(&mut self) -> zbus::fdo::Result { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - return Ok(ctrl.config.active_profile); - } - Err(Error::Failed( - "Failed to get active profile name".to_string(), - )) + async fn active_profile(&mut self) -> zbus::fdo::Result { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + Ok(ctrl.config.active_profile) } /// Set this platform_profile name as active @@ -76,93 +67,85 @@ impl ProfileZbus { #[zbus(signal_context)] ctxt: SignalContext<'_>, profile: Profile, ) { - let mut tmp = None; - if let Ok(mut ctrl) = self.inner.try_lock() { - // Read first just incase the user has modified the config before calling this - ctrl.config.read(); - Profile::set_profile(profile) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.config.active_profile = profile; + let mut ctrl = self.inner.lock().await; + // Read first just incase the user has modified the config before calling this + ctrl.config.read(); + Profile::set_profile(profile) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.config.active_profile = profile; + ctrl.write_profile_curve_to_platform() + .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) + .ok(); + + ctrl.save_config(); + + Self::notify_profile(&ctxt, ctrl.config.active_profile) + .await + .ok(); + } + + /// Get a list of profiles that have fan-curves enabled. + async fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + if let Some(curves) = &ctrl.config.fan_curves { + return Ok(curves.get_enabled_curve_profiles().to_vec()); + } + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); + } + + /// Set a profile fan curve enabled status. Will also activate a fan curve if in the + /// same profile mode + async fn set_fan_curve_enabled( + &mut self, + profile: Profile, + enabled: bool, + ) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + return if let Some(curves) = &mut ctrl.config.fan_curves { + curves.set_profile_curve_enabled(profile, enabled); + ctrl.write_profile_curve_to_platform() .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) .ok(); ctrl.save_config(); - tmp = Some(ctrl.config.active_profile); - } - if let Some(profile) = tmp { - Self::notify_profile(&ctxt, profile).await.ok(); - } - } - - /// Get a list of profiles that have fan-curves enabled. - fn enabled_fan_profiles(&mut self) -> zbus::fdo::Result> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - if let Some(curves) = &ctrl.config.fan_curves { - return Ok(curves.get_enabled_curve_profiles().to_vec()); - } - return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); - } - Err(Error::Failed( - "Failed to get enabled fan curve names".to_string(), - )) - } - - /// Set a profile fan curve enabled status. Will also activate a fan curve if in the - /// same profile mode - fn set_fan_curve_enabled(&mut self, profile: Profile, enabled: bool) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - return if let Some(curves) = &mut ctrl.config.fan_curves { - curves.set_profile_curve_enabled(profile, enabled); - - ctrl.write_profile_curve_to_platform() - .map_err(|e| warn!("write_profile_curve_to_platform, {}", e)) - .ok(); - - ctrl.save_config(); - Ok(()) - } else { - Err(Error::Failed(UNSUPPORTED_MSG.to_string())) - }; - } - Err(Error::Failed( - "Failed to get enabled fan curve names".to_string(), - )) + Ok(()) + } else { + Err(Error::Failed(UNSUPPORTED_MSG.to_string())) + }; } /// Get the fan-curve data for the currently active Profile - fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - if let Some(curves) = &ctrl.config.fan_curves { - let curve = curves.get_fan_curves_for(profile); - return Ok(curve.clone()); - } - return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); + async fn fan_curve_data(&mut self, profile: Profile) -> zbus::fdo::Result { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + if let Some(curves) = &ctrl.config.fan_curves { + let curve = curves.get_fan_curves_for(profile); + return Ok(curve.clone()); } - Err(Error::Failed("Failed to get fan curve data".to_string())) + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } /// Set the fan curve for the specified profile. /// Will also activate the fan curve if the user is in the same mode. - fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - if let Some(curves) = &mut ctrl.config.fan_curves { - curves - .save_fan_curve(curve, profile) - .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; - } else { - return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); - } - ctrl.write_profile_curve_to_platform() - .map_err(|e| warn!("Profile::set_profile, {}", e)) - .ok(); - ctrl.save_config(); + async fn set_fan_curve(&self, profile: Profile, curve: CurveData) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + if let Some(curves) = &mut ctrl.config.fan_curves { + curves + .save_fan_curve(curve, profile) + .map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?; + } else { + return Err(Error::Failed(UNSUPPORTED_MSG.to_string())); } + ctrl.write_profile_curve_to_platform() + .map_err(|e| warn!("Profile::set_profile, {}", e)) + .ok(); + ctrl.save_config(); + Ok(()) } @@ -170,14 +153,13 @@ impl ProfileZbus { /// /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. - fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - ctrl.set_active_curve_to_defaults() - .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) - .ok(); - ctrl.save_config(); - } + async fn set_active_curve_to_defaults(&self) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + ctrl.set_active_curve_to_defaults() + .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) + .ok(); + ctrl.save_config(); Ok(()) } @@ -185,23 +167,22 @@ impl ProfileZbus { /// /// Each platform_profile has a different default and the defualt can be read /// only for the currently active profile. - fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { - if let Ok(mut ctrl) = self.inner.try_lock() { - ctrl.config.read(); - let active = Profile::get_active_profile().unwrap_or(Profile::Balanced); + async fn reset_profile_curves(&self, profile: Profile) -> zbus::fdo::Result<()> { + let mut ctrl = self.inner.lock().await; + ctrl.config.read(); + let active = Profile::get_active_profile().unwrap_or(Profile::Balanced); - Profile::set_profile(profile) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.set_active_curve_to_defaults() - .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) - .ok(); + Profile::set_profile(profile) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.set_active_curve_to_defaults() + .map_err(|e| warn!("Profile::set_active_curve_to_defaults, {}", e)) + .ok(); - Profile::set_profile(active) - .map_err(|e| warn!("set_profile, {}", e)) - .ok(); - ctrl.save_config(); - } + Profile::set_profile(active) + .map_err(|e| warn!("set_profile, {}", e)) + .ok(); + ctrl.save_config(); Ok(()) } @@ -211,7 +192,7 @@ impl ProfileZbus { } #[async_trait] -impl crate::ZbusAdd for ProfileZbus { +impl crate::ZbusRun for ProfileZbus { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Profile", server).await; } @@ -221,36 +202,32 @@ impl crate::ZbusAdd for ProfileZbus { impl CtrlTask for ProfileZbus { async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { let ctrl = self.inner.clone(); - let mut watch = Inotify::init()?; - watch.add_watch(PLATFORM_PROFILE, WatchMask::CLOSE_WRITE)?; + let mut watch = self + .inner + .lock() + .await + .platform + .monitor_platform_profile()?; tokio::spawn(async move { let mut buffer = [0; 32]; - loop { - watch - .event_stream(&mut buffer) - .unwrap() - .for_each(|_| async { - let mut active_profile = None; + watch + .event_stream(&mut buffer) + .unwrap() + .for_each(|_| async { + let mut lock = ctrl.lock().await; + let new_profile = Profile::get_active_profile().unwrap(); + if new_profile != lock.config.active_profile { + lock.config.active_profile = new_profile; + lock.write_profile_curve_to_platform().unwrap(); + lock.save_config(); + } - if let Ok(ref mut lock) = ctrl.try_lock() { - let new_profile = Profile::get_active_profile().unwrap(); - if new_profile != lock.config.active_profile { - lock.config.active_profile = new_profile; - lock.write_profile_curve_to_platform().unwrap(); - lock.save_config(); - active_profile = Some(lock.config.active_profile); - } - } - - if let Some(active_profile) = active_profile { - Self::notify_profile(&signal_ctxt.clone(), active_profile) - .await - .ok(); - } - }) - .await; - } + Self::notify_profile(&signal_ctxt.clone(), lock.config.active_profile) + .await + .ok(); + }) + .await; }); Ok(()) diff --git a/daemon/src/ctrl_supported.rs b/daemon/src/ctrl_supported.rs index 4c4bec3d..9fe99a15 100644 --- a/daemon/src/ctrl_supported.rs +++ b/daemon/src/ctrl_supported.rs @@ -28,7 +28,7 @@ impl SupportedFunctions { } #[async_trait] -impl crate::ZbusAdd for SupportedFunctions { +impl crate::ZbusRun for SupportedFunctions { async fn add_to_server(self, server: &mut Connection) { Self::add_to_server_helper(self, "/org/asuslinux/Supported", server).await; } diff --git a/daemon/src/daemon.rs b/daemon/src/daemon.rs index df608762..9796f7d3 100644 --- a/daemon/src/daemon.rs +++ b/daemon/src/daemon.rs @@ -1,9 +1,10 @@ use std::env; use std::error::Error; use std::io::Write; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::time::Duration; +use ::zbus::export::futures_util::lock::Mutex; use ::zbus::{Connection, SignalContext}; use log::LevelFilter; use log::{error, info, warn}; @@ -26,7 +27,7 @@ use daemon::{ ctrl_profiles::{controller::CtrlPlatformProfile, zbus::ProfileZbus}, laptops::LaptopLedData, }; -use daemon::{CtrlTask, Reloadable, ZbusAdd}; +use daemon::{CtrlTask, Reloadable, ZbusRun}; use rog_dbus::DBUS_NAME; use rog_profiles::Profile; @@ -84,6 +85,7 @@ async fn start_daemon() -> Result<(), Box> { Ok(mut ctrl) => { // Do a reload of any settings ctrl.reload() + .await .unwrap_or_else(|err| warn!("CtrlRogBios: {}", err)); // Then register to dbus server ctrl.add_to_server(&mut connection).await; @@ -101,6 +103,7 @@ async fn start_daemon() -> Result<(), Box> { Ok(mut ctrl) => { // Do a reload of any settings ctrl.reload() + .await .unwrap_or_else(|err| warn!("CtrlPower: {}", err)); // Then register to dbus server ctrl.add_to_server(&mut connection).await; @@ -119,14 +122,12 @@ async fn start_daemon() -> Result<(), Box> { match CtrlPlatformProfile::new(profile_config) { Ok(mut ctrl) => { ctrl.reload() + .await .unwrap_or_else(|err| warn!("Profile control: {}", err)); - let tmp = Arc::new(Mutex::new(ctrl)); - //let task = CtrlProfileTask::new(tmp.clone()); - //task.create_tasks(executor).await.ok(); let sig = SignalContext::new(&connection, "/org/asuslinux/Profile")?; - let task = ProfileZbus::new(tmp.clone()); + let task = ProfileZbus::new(Arc::new(Mutex::new(ctrl))); task.create_tasks(sig).await.ok(); task.add_to_server(&mut connection).await; } @@ -145,6 +146,7 @@ async fn start_daemon() -> Result<(), Box> { let mut reload = CtrlAnimeReloader(inner.clone()); reload .reload() + .await .unwrap_or_else(|err| warn!("AniMe: {}", err)); let zbus = CtrlAnimeZbus(inner.clone()); @@ -168,6 +170,7 @@ async fn start_daemon() -> Result<(), Box> { let mut reload = CtrlKbdLedReloader(inner.clone()); reload .reload() + .await .unwrap_or_else(|err| warn!("Keyboard LED control: {}", err)); CtrlKbdLedZbus::new(inner.clone()) diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 6fda88ed..bb6c41c1 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -19,24 +19,22 @@ pub mod ctrl_supported; pub mod error; -use std::time::Duration; - use crate::error::RogError; use async_trait::async_trait; use log::warn; use logind_zbus::manager::ManagerProxy; -use tokio::time; use zbus::{export::futures_util::StreamExt, Connection, SignalContext}; use zvariant::ObjectPath; pub const VERSION: &str = env!("CARGO_PKG_VERSION"); +#[async_trait] pub trait Reloadable { - fn reload(&mut self) -> Result<(), RogError>; + async fn reload(&mut self) -> Result<(), RogError>; } #[async_trait] -pub trait ZbusAdd { +pub trait ZbusRun { async fn add_to_server(self, server: &mut Connection); async fn add_to_server_helper( @@ -110,14 +108,16 @@ pub trait CtrlTask { /// No blocking loops are allowed, or they must be run on a separate thread. async fn create_tasks(&self, signal: SignalContext<'static>) -> Result<(), RogError>; - /// Create a timed repeating task - async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { - let mut timer = time::interval(Duration::from_millis(millis)); - tokio::spawn(async move { - timer.tick().await; - task(); - }); - } + // /// Create a timed repeating task + // async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send + 'static) { + // use std::time::Duration; + // use tokio::time; + // let mut timer = time::interval(Duration::from_millis(millis)); + // tokio::spawn(async move { + // timer.tick().await; + // task(); + // }); + // } /// Free helper method to create tasks to run on: sleep, wake, shutdown, boot /// diff --git a/design-patterns.md b/design-patterns.md index 25b59b52..8b21e1bf 100644 --- a/design-patterns.md +++ b/design-patterns.md @@ -19,80 +19,103 @@ Then for each trait that is required a new struct is required that can have the Main controller: ```rust +/// For a very simple controller that doesn't need exclusive access you can clone across threads +#[derive(Clone)] +pub struct CtrlAnime { + + config: Arc>, +} + +impl crate::CtrlTask for CtrlAnime {} +impl crate::ZbusAdd for CtrlAnime {} + +impl CtrlAnime {} +``` + +```rust +/// Otherwise, you will need to share the controller via mutex pub struct CtrlAnime { } +// Like this +#[derive(Clone)] +pub struct CtrlAnimeTask(Arc>); +#[derive(Clone)] +pub struct CtrlAnimeZbus(Arc>); -impl CtrlAnime { - -} +impl CtrlAnime {} ``` The task trait. There are three ways to implement this: ```rust +// Mutex should always be async mutex pub struct CtrlAnimeTask(Arc>); impl crate::CtrlTask for CtrlAnimeTask { // This will run once only - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { + let lock self.inner.lock().await; + Ok(()) } // This will run until the notification stream closes (which in most cases will be never) - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - let connection = Connection::system().await.unwrap(); - let manager = ManagerProxy::new(&connection).await.unwrap(); - - let inner = self.inner.clone(); - executor - .spawn(async move { - // A notification from logind dbus interface - if let Ok(p) = manager.receive_prepare_for_sleep().await { - // A stream that will continuously output events - p.for_each(|_| { - if let Ok(lock) = inner.try_lock() { - // Do stuff here - } - }) - .await; + async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> { + let inner1 = self.inner.clone(); + let inner2 = self.inner.clone(); + let inner3 = self.inner.clone(); + let inner4 = self.inner.clone(); + // This is a free method on CtrlTask trait + self.create_sys_event_tasks( + // Loop is required to try an attempt to get the mutex *without* blocking + // other threads - it is possible to end up with deadlocks otherwise. + move || loop { + if let Some(lock) = inner1.try_lock() { + run_action(true, lock, inner1.clone()); + break; } - }) - .detach(); - } - - // This task will run every 500 milliseconds - fn create_tasks(&self, executor: &mut Executor) -> Result<(), RogError> { - let inner = self.inner.clone(); - // This is a provided free trait to help set up a repeating task - self.repeating_task(500, executor, move || { - if let Ok(lock) = inner.try_lock() { - // Do stuff here - } - }) + }, + move || loop { + if let Some(lock) = inner2.try_lock() { + run_action(false, lock, inner2.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner3.try_lock() { + run_action(true, lock, inner3.clone()); + break; + } + }, + move || loop { + if let Some(lock) = inner4.try_lock() { + run_action(false, lock, inner4.clone()); + break; + } + }, + ) .await; } } ``` The reloader trait + ```rust pub struct CtrlAnimeReloader(Arc>); impl crate::Reloadable for CtrlAnimeReloader { - fn reload(&mut self) -> Result<(), RogError> { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn reload(&mut self) -> Result<(), RogError> { + let lock = self.inner.lock().await; + Ok(()) } } ``` The Zbus requirements: + ```rust pub struct CtrlAnimeZbus(Arc>); @@ -106,10 +129,9 @@ impl crate::ZbusAdd for CtrlAnimeZbus { #[dbus_interface(name = "org.asuslinux.Daemon")] impl CtrlAnimeZbus { - fn () { - if let Ok(lock) = self.inner.try_lock() { - - } + async fn () { + let lock = self.inner.lock().await; + } } ``` diff --git a/rog-platform/src/platform.rs b/rog-platform/src/platform.rs index 580ac83b..8658a28b 100644 --- a/rog-platform/src/platform.rs +++ b/rog-platform/src/platform.rs @@ -57,8 +57,8 @@ impl AsusPlatform { attr_bool!("egpu_enable", path); attr_bool!("panel_od", path); attr_u8!("gpu_mux_mode", path); + // This is technically the same as `platform_profile` since both are tied in-kernel attr_u8!("throttle_thermal_policy", path); - // The acpi platform_profile support attr_u8!("platform_profile", pp_path); }