Resource manager now keeps the values in an RwLock instead of Mutex.

This commit is contained in:
Filipe Rodrigues 2025-09-14 10:35:21 +01:00
parent 7a2835f6d1
commit 04c7a31c81
Signed by: zenithsiz
SSH Key Fingerprint: SHA256:Mb5ppb3Sh7IarBO/sBTXLHbYEOz37hJAlslLQPPAPaU
9 changed files with 23 additions and 23 deletions

View File

@ -8,13 +8,13 @@ use {
futures::TryStreamExt,
serde::{Serialize, de::DeserializeOwned},
std::{collections::HashMap, ffi::OsStr, hash::Hash, path::PathBuf, sync::Arc},
tokio::sync::{Mutex, OnceCell},
tokio::sync::{Mutex, OnceCell, RwLock},
tokio_stream::{StreamExt, wrappers::ReadDirStream},
zutil_cloned::cloned,
};
/// Resource storage
type ResourceStorage<V> = Arc<OnceCell<Arc<Mutex<V>>>>;
type ResourceStorage<V> = Arc<OnceCell<Arc<RwLock<V>>>>;
/// Resource manager
#[derive(Debug)]
@ -48,7 +48,7 @@ impl<N, V, S> ResourceManager<N, V, S> {
pub async fn load_all(self: &Arc<Self>) -> Result<(), AppError>
where
N: Eq + Hash + Clone + From<String> + AsRef<str> + Send + 'static,
V: FromSerialized<N, S> + Send + 'static,
V: FromSerialized<N, S> + Send + Sync + 'static,
S: DeserializeOwned + 'static,
{
tokio::fs::read_dir(&self.root)
@ -92,11 +92,11 @@ impl<N, V, S> ResourceManager<N, V, S> {
}
/// Adds a new value
pub async fn add(&self, name: N, value: V) -> Arc<Mutex<V>>
pub async fn add(&self, name: N, value: V) -> Arc<RwLock<V>>
where
N: Eq + Hash,
{
let value = Arc::new(Mutex::new(value));
let value = Arc::new(RwLock::new(value));
_ = self
.values
.lock()
@ -107,7 +107,7 @@ impl<N, V, S> ResourceManager<N, V, S> {
}
/// Loads a value by name
pub async fn load(&self, name: N) -> Result<Arc<Mutex<V>>, AppError>
pub async fn load(&self, name: N) -> Result<Arc<RwLock<V>>, AppError>
where
N: Eq + Hash + Clone + AsRef<str>,
V: FromSerialized<N, S>,
@ -131,7 +131,7 @@ impl<N, V, S> ResourceManager<N, V, S> {
let value = toml::from_str::<S>(&toml).context("Unable to parse value")?;
let value = V::from_serialized(name, value);
Ok(Arc::new(Mutex::new(value)))
Ok(Arc::new(RwLock::new(value)))
})
.await
.map(Arc::clone)
@ -157,7 +157,7 @@ impl<N, V, S> ResourceManager<N, V, S> {
Arc::clone(value)
};
let value = value.lock().await;
let value = value.read().await;
let value = value.to_serialized(name);
let value = toml::to_string_pretty(&value).context("Unable to serialize value")?;
@ -169,7 +169,7 @@ impl<N, V, S> ResourceManager<N, V, S> {
}
/// Returns all values
pub async fn get_all(&self) -> Vec<Arc<Mutex<V>>> {
pub async fn get_all(&self) -> Vec<Arc<RwLock<V>>> {
self.values
.lock()
.await

View File

@ -392,7 +392,7 @@ async fn paint_egui(
};
let cursor_pos = Point2::new(cursor_pos.x as i32, cursor_pos.y as i32);
for panel in &mut *shared.panels.get_all().await {
let display = panel.display.lock().await;
let display = panel.display.read().await;
// If we're over an egui area, or none of the geometries are underneath the cursor, skip the panel
if ctx.is_pointer_over_area() ||

View File

@ -20,14 +20,14 @@ pub use self::{
use {
crate::{display::Display, playlist::PlaylistPlayer},
std::sync::Arc,
tokio::sync::Mutex,
tokio::sync::RwLock,
};
/// Panel
#[derive(Debug)]
pub struct Panel {
/// Display
pub display: Arc<Mutex<Display>>,
pub display: Arc<RwLock<Display>>,
/// Geometries
pub geometries: Vec<PanelGeometry>,
@ -38,7 +38,7 @@ pub struct Panel {
impl Panel {
/// Creates a new panel
pub fn new(display: Arc<Mutex<Display>>, state: PanelState) -> Self {
pub fn new(display: Arc<RwLock<Display>>, state: PanelState) -> Self {
Self {
display,
geometries: vec![],

View File

@ -22,7 +22,7 @@ use {
std::sync::Arc,
tokio::{
fs,
sync::{Mutex, MutexGuard},
sync::{Mutex, MutexGuard, RwLock},
},
zsw_util::{AppError, UnwrapOrReturnExt, WalkDir},
zutil_cloned::cloned,
@ -32,7 +32,7 @@ use {
#[derive(Debug)]
struct Inner {
/// Profile
profile: Option<Arc<Mutex<Profile>>>,
profile: Option<Arc<RwLock<Profile>>>,
/// Panels
panels: Vec<Panel>,
@ -81,7 +81,7 @@ impl Panels {
{
let mut inner = self.inner.lock().await;
if let Some(old_profile) = &inner.profile {
tracing::info!("Dropping previous profile: {:?}", old_profile.lock().await.name);
tracing::info!("Dropping previous profile: {:?}", old_profile.read().await.name);
inner.panels.clear();
}
inner.profile = Some(Arc::clone(&profile));
@ -91,7 +91,7 @@ impl Panels {
// Then load it's panels
profile
.lock()
.read()
.await
.panels
.iter()
@ -163,7 +163,7 @@ async fn load_playlist(
.load(playlist_name.clone())
.await
.context("Unable to load playlist")?
.lock()
.read()
.await
.items
.iter()

View File

@ -250,7 +250,7 @@ impl PanelsRenderer {
// The display might have changed asynchronously from the panel geometries,
// so resize it to ensure we have a panel geometry for each display geometry.
let display = panel.display.lock().await;
let display = panel.display.read().await;
panel
.geometries
.resize_with(display.geometries.len(), PanelGeometry::new);

View File

@ -11,7 +11,7 @@ use {
/// Draws the displays tab
pub fn draw_displays_tab(ui: &mut egui::Ui, displays: &Arc<Displays>) {
for display in displays.get_all().block_on() {
let mut display = display.lock().block_on();
let mut display = display.write().block_on();
ui.collapsing(display.name.to_string(), |ui| {
self::draw_display_geometries(ui, &mut display.geometries);

View File

@ -37,7 +37,7 @@ fn draw_panels_editor(ui: &mut egui::Ui, wgpu: &Wgpu, panels: &Panels, window_ge
}
for panel in &mut *panels {
let mut display = panel.display.lock().block_on();
let mut display = panel.display.write().block_on();
let mut name = egui::WidgetText::from(display.name.to_string());
if display

View File

@ -6,7 +6,7 @@ use {crate::playlist::Playlists, std::sync::Arc, zsw_util::TokioTaskBlockOn, zut
/// Draws the playlists tab
pub fn draw_playlists_tab(ui: &mut egui::Ui, playlists: &Arc<Playlists>) {
for playlist in playlists.get_all().block_on() {
let playlist = playlist.lock().block_on();
let playlist = playlist.read().block_on();
ui.collapsing(playlist.name.to_string(), |ui| {
if ui.button("Save").clicked() {

View File

@ -17,7 +17,7 @@ pub fn draw_profiles_tab(
panels: &Arc<Panels>,
) {
for profile in profiles.get_all().block_on() {
let profile = profile.lock().block_on();
let profile = profile.read().block_on();
ui.collapsing(profile.name.to_string(), |ui| {
if ui.button("Set active").clicked() {