1
Fork 0
mirror of https://github.com/RGBCube/watt synced 2025-07-29 17:07:46 +00:00

Merge pull request #27 from NotAShelf/fix-auto-turbo

engine: fix race condition in turbo state init
This commit is contained in:
raf 2025-05-18 06:08:00 +03:00 committed by GitHub
commit 8050f91aa8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 46 deletions

View file

@ -3,6 +3,17 @@ use crate::core::TurboSetting;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
/// Defines constant-returning functions used for default values.
/// This hopefully reduces repetition since we have way too many default functions
/// that just return constants.
macro_rules! default_const {
($name:ident, $type:ty, $value:expr) => {
const fn $name() -> $type {
$value
}
};
}
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
pub struct BatteryChargeThresholds {
pub start: u8,
@ -186,18 +197,22 @@ pub const DEFAULT_LOAD_THRESHOLD_LOW: f32 = 30.0; // disable turbo if load is be
pub const DEFAULT_TEMP_THRESHOLD_HIGH: f32 = 75.0; // disable turbo if temperature is above this
pub const DEFAULT_INITIAL_TURBO_STATE: bool = false; // by default, start with turbo disabled
const fn default_load_threshold_high() -> f32 {
default_const!(
default_load_threshold_high,
f32,
DEFAULT_LOAD_THRESHOLD_HIGH
}
const fn default_load_threshold_low() -> f32 {
DEFAULT_LOAD_THRESHOLD_LOW
}
const fn default_temp_threshold_high() -> f32 {
);
default_const!(default_load_threshold_low, f32, DEFAULT_LOAD_THRESHOLD_LOW);
default_const!(
default_temp_threshold_high,
f32,
DEFAULT_TEMP_THRESHOLD_HIGH
}
const fn default_initial_turbo_state() -> bool {
);
default_const!(
default_initial_turbo_state,
bool,
DEFAULT_INITIAL_TURBO_STATE
}
);
impl Default for TurboAutoSettings {
fn default() -> Self {
@ -274,37 +289,14 @@ impl Default for DaemonConfig {
}
}
const fn default_poll_interval_sec() -> u64 {
5
}
const fn default_adaptive_interval() -> bool {
false
}
const fn default_min_poll_interval_sec() -> u64 {
1
}
const fn default_max_poll_interval_sec() -> u64 {
30
}
const fn default_throttle_on_battery() -> bool {
true
}
const fn default_log_level() -> LogLevel {
LogLevel::Info
}
const fn default_stats_file_path() -> Option<String> {
None
}
const fn default_enable_auto_turbo() -> bool {
true
}
default_const!(default_poll_interval_sec, u64, 5);
default_const!(default_adaptive_interval, bool, false);
default_const!(default_min_poll_interval_sec, u64, 1);
default_const!(default_max_poll_interval_sec, u64, 30);
default_const!(default_throttle_on_battery, bool, true);
default_const!(default_log_level, LogLevel, LogLevel::Info);
default_const!(default_stats_file_path, Option<String>, None);
default_const!(default_enable_auto_turbo, bool, true);
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct DaemonConfigToml {

View file

@ -69,11 +69,8 @@ impl TurboHysteresis {
/// Initialize the state with a specific value if not already initialized
/// Only one thread should be able to initialize the state
fn initialize_with(&self, initial_state: bool) -> bool {
// First store the initial state so that it's visible before initialized=true
self.previous_state.store(initial_state, Ordering::Release);
// Try to atomically change initialized from false to true
// Now, only one thread can win the initialization race
// First, try to atomically change initialized from false to true
// Only one thread can win the initialization race
match self.initialized.compare_exchange(
false, // expected: not initialized
true, // desired: mark as initialized
@ -82,11 +79,14 @@ impl TurboHysteresis {
) {
Ok(_) => {
// We won the race to initialize
// Now it's safe to set the initial state since we know we're the only
// thread that has successfully marked this as initialized
self.previous_state.store(initial_state, Ordering::Release);
initial_state
}
Err(_) => {
// Another thread already initialized it.
// Read the current state in bitter defeat
// Just read the current state value that was set by the winning thread
self.previous_state.load(Ordering::Acquire)
}
}