mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
asusd: fixing a blocking op
This commit is contained in:
@@ -1,6 +1,3 @@
|
||||
use crate::systemd::{
|
||||
do_systemd_unit_action, is_systemd_unit_enabled, SystemdUnitAction, SystemdUnitState,
|
||||
};
|
||||
use crate::{config::Config, error::RogError, GetSupported};
|
||||
use crate::{task_watch_item, CtrlTask};
|
||||
use async_trait::async_trait;
|
||||
@@ -10,6 +7,7 @@ use rog_platform::supported::ChargeSupportedFunctions;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use systemd_zbus::{ManagerProxy as SystemdProxy, Mode, UnitFileState};
|
||||
use tokio::time::sleep;
|
||||
use zbus::dbus_interface;
|
||||
use zbus::export::futures_util::lock::Mutex;
|
||||
@@ -155,16 +153,22 @@ impl CtrlTask for CtrlPower {
|
||||
}
|
||||
|
||||
async fn create_tasks(&self, signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
|
||||
let conn = zbus::Connection::system().await?;
|
||||
let sysd1 = SystemdProxy::new(&conn).await?;
|
||||
let sysd2 = sysd1.clone();
|
||||
let sysd3 = sysd1.clone();
|
||||
|
||||
let power1 = self.clone();
|
||||
let power2 = self.clone();
|
||||
self.create_sys_event_tasks(
|
||||
move || async {},
|
||||
move || {
|
||||
let power1 = power1.clone();
|
||||
let power = power1.clone();
|
||||
let sysd = sysd1.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power1.config.lock().await;
|
||||
power1
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
@@ -172,18 +176,19 @@ impl CtrlTask for CtrlPower {
|
||||
})
|
||||
.ok();
|
||||
|
||||
if let Ok(value) = power1.power.get_online() {
|
||||
do_nvidia_powerd_action(value == 1);
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
move || async {},
|
||||
move || {
|
||||
let power2 = power2.clone();
|
||||
let power = power2.clone();
|
||||
let sysd = sysd2.clone();
|
||||
async move {
|
||||
info!("CtrlCharge reloading charge limit");
|
||||
let lock = power2.config.lock().await;
|
||||
power2
|
||||
let lock = power.config.lock().await;
|
||||
power
|
||||
.set(lock.bat_charge_limit)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlCharge: set_limit {}", err);
|
||||
@@ -191,8 +196,8 @@ impl CtrlTask for CtrlPower {
|
||||
})
|
||||
.ok();
|
||||
|
||||
if let Ok(value) = power2.power.get_online() {
|
||||
do_nvidia_powerd_action(value == 1);
|
||||
if let Ok(value) = power.power.get_online() {
|
||||
do_nvidia_powerd_action(&sysd, value == 1).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -210,7 +215,7 @@ impl CtrlTask for CtrlPower {
|
||||
if let Ok(value) = ctrl.power.get_online() {
|
||||
if online != value {
|
||||
online = value;
|
||||
do_nvidia_powerd_action(value == 1);
|
||||
do_nvidia_powerd_action(&sysd3, value == 1).await;
|
||||
|
||||
Self::notify_mains_online(&signal_ctxt, value == 1)
|
||||
.await
|
||||
@@ -252,16 +257,22 @@ impl CtrlTask for CtrlPower {
|
||||
}
|
||||
}
|
||||
|
||||
fn do_nvidia_powerd_action(ac_on: bool) {
|
||||
let action = if ac_on {
|
||||
SystemdUnitAction::Restart
|
||||
} else {
|
||||
SystemdUnitAction::Stop
|
||||
};
|
||||
|
||||
if let Ok(res) = is_systemd_unit_enabled(SystemdUnitState::Enabled, NVIDIA_POWERD) {
|
||||
if res && do_systemd_unit_action(action, NVIDIA_POWERD).is_ok() {
|
||||
info!("CtrlPower task: did {action:?} on {NVIDIA_POWERD}");
|
||||
async fn do_nvidia_powerd_action(proxy: &SystemdProxy<'_>, ac_on: bool) {
|
||||
if let Ok(res) = proxy.get_unit_file_state(NVIDIA_POWERD).await {
|
||||
if res == UnitFileState::Enabled {
|
||||
if ac_on {
|
||||
proxy
|
||||
.stop_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
} else {
|
||||
proxy
|
||||
.start_unit(NVIDIA_POWERD, Mode::Replace)
|
||||
.await
|
||||
.map_err(|e| error!("Error stopping {NVIDIA_POWERD}, {e:?}"))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ pub mod ctrl_profiles;
|
||||
/// Laptop matching to determine capabilities
|
||||
pub mod laptops;
|
||||
|
||||
pub mod systemd;
|
||||
|
||||
/// Fetch all supported functions for the laptop
|
||||
pub mod ctrl_supported;
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
use std::process::Command;
|
||||
|
||||
use crate::error::RogError;
|
||||
|
||||
/// An action for `systemctl`
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SystemdUnitAction {
|
||||
Stop,
|
||||
Start,
|
||||
Restart,
|
||||
}
|
||||
|
||||
impl From<SystemdUnitAction> for &str {
|
||||
fn from(s: SystemdUnitAction) -> Self {
|
||||
match s {
|
||||
SystemdUnitAction::Stop => "stop",
|
||||
SystemdUnitAction::Start => "start",
|
||||
SystemdUnitAction::Restart => "restart",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SystemdUnitState {
|
||||
Active,
|
||||
Inactive,
|
||||
Masked,
|
||||
Disabled,
|
||||
Enabled,
|
||||
}
|
||||
|
||||
impl From<SystemdUnitState> for &str {
|
||||
fn from(s: SystemdUnitState) -> Self {
|
||||
match s {
|
||||
SystemdUnitState::Active => "active",
|
||||
SystemdUnitState::Inactive => "inactive",
|
||||
SystemdUnitState::Masked => "masked",
|
||||
SystemdUnitState::Disabled => "disabled",
|
||||
SystemdUnitState::Enabled => "enabled",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Change the state of a systemd unit. Blocks while running command.
|
||||
pub fn do_systemd_unit_action(action: SystemdUnitAction, unit: &str) -> Result<(), RogError> {
|
||||
let mut cmd = Command::new("systemctl");
|
||||
cmd.arg(<&str>::from(action));
|
||||
cmd.arg(unit);
|
||||
|
||||
let status = cmd
|
||||
.status()
|
||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||
if !status.success() {
|
||||
let msg = format!("systemctl {action:?} {unit} failed: {status:?}",);
|
||||
return Err(RogError::SystemdUnitAction(msg));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get systemd unit state. Blocks while command is run.
|
||||
pub fn is_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<bool, RogError> {
|
||||
let mut cmd = Command::new("systemctl");
|
||||
cmd.arg("is-active");
|
||||
cmd.arg(unit);
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Get systemd unit state. Blocks while command is run.
|
||||
pub fn is_systemd_unit_enabled(state: SystemdUnitState, unit: &str) -> Result<bool, RogError> {
|
||||
let mut cmd = Command::new("systemctl");
|
||||
cmd.arg("is-enabled");
|
||||
cmd.arg(unit);
|
||||
|
||||
let output = cmd
|
||||
.output()
|
||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Wait for a systemd unit to change to `state`. Checks state every 250ms for 3 seconds. Blocks while running wait.
|
||||
pub fn wait_systemd_unit_state(state: SystemdUnitState, unit: &str) -> Result<(), RogError> {
|
||||
let mut cmd = Command::new("systemctl");
|
||||
cmd.arg("is-active");
|
||||
cmd.arg(unit);
|
||||
|
||||
let mut count = 0;
|
||||
|
||||
while count <= (4 * 3) {
|
||||
// 3 seconds max
|
||||
let output = cmd
|
||||
.output()
|
||||
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
|
||||
if output.stdout.starts_with(<&str>::from(state).as_bytes()) {
|
||||
return Ok(());
|
||||
}
|
||||
// fine to block here, nobody doing shit now
|
||||
std::thread::sleep(std::time::Duration::from_millis(250));
|
||||
count += 1;
|
||||
}
|
||||
Err(RogError::SystemdUnitWaitTimeout(<&str>::from(state).into()))
|
||||
}
|
||||
Reference in New Issue
Block a user