Fix second audit findings and restore crash detection dialog

Address 29 issues found in comprehensive API/spec audit:
- Fix .desktop Exec key path escaping per Desktop Entry spec
- Fix update dialog double-dispatch with connect_response
- Fix version comparison total ordering with lexicographic fallback
- Use RETURNING id for reliable upsert in database
- Replace tilde-based path fallbacks with proper XDG helpers
- Fix backup create/restore path asymmetry for non-home paths
- HTML-escape severity class in security reports
- Use AppStream <custom> element instead of <metadata>
- Fix has_appimage_update_tool to check .is_ok() not .success()
- Use ListBoxRow instead of ActionRow::set_child in ExpanderRow
- Add ELF magic validation to architecture detection
- Add timeout to extract_update_info_runtime
- Skip symlinks in dir_size calculation
- Use Condvar instead of busy-wait in analysis thread pool
- Restore crash detection to single blocking call architecture
This commit is contained in:
lashman
2026-02-27 22:48:43 +02:00
parent e9343da249
commit 830c3cad9d
21 changed files with 228 additions and 181 deletions

View File

@@ -1,4 +1,5 @@
use std::path::PathBuf;
use std::sync::{Condvar, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use crate::core::database::Database;
@@ -14,17 +15,21 @@ const MAX_CONCURRENT_ANALYSES: usize = 2;
/// Counter for currently running analyses.
static RUNNING_ANALYSES: AtomicUsize = AtomicUsize::new(0);
/// Condvar to efficiently wait for a slot instead of busy-polling.
static SLOT_AVAILABLE: (Mutex<()>, Condvar) = (Mutex::new(()), Condvar::new());
/// Returns the number of currently running background analyses.
pub fn running_count() -> usize {
RUNNING_ANALYSES.load(Ordering::Relaxed)
}
/// RAII guard that decrements the analysis counter on drop.
/// RAII guard that decrements the analysis counter on drop and notifies waiters.
struct AnalysisGuard;
impl Drop for AnalysisGuard {
fn drop(&mut self) {
RUNNING_ANALYSES.fetch_sub(1, Ordering::Release);
SLOT_AVAILABLE.1.notify_one();
}
}
@@ -36,7 +41,7 @@ impl Drop for AnalysisGuard {
///
/// Blocks until a slot is available if the concurrency limit is reached.
pub fn run_background_analysis(id: i64, path: PathBuf, appimage_type: AppImageType, integrate: bool) {
// Wait for a slot to become available
// Wait for a slot to become available using condvar instead of busy-polling
loop {
let current = RUNNING_ANALYSES.load(Ordering::Acquire);
if current < MAX_CONCURRENT_ANALYSES {
@@ -44,7 +49,8 @@ pub fn run_background_analysis(id: i64, path: PathBuf, appimage_type: AppImageTy
break;
}
} else {
std::thread::sleep(std::time::Duration::from_millis(200));
let lock = SLOT_AVAILABLE.0.lock().unwrap();
let _ = SLOT_AVAILABLE.1.wait_timeout(lock, std::time::Duration::from_secs(1));
}
}
let _guard = AnalysisGuard;