refactor: replace lock unwraps with poison-aware helpers

Add SoulseekRs::LockPoisoned variant and a small RwLockExt/MutexExt
helper module exposing read_safe/write_safe/lock_safe that map
PoisonError to that variant. Walk every non-test lock acquisition
across client, peer/server actors, peer registry, listener and the
thread pool: propagate via ? where the function returns Result, log
and degrade to a sensible default (return early, false, None, empty)
where it does not. Client::connect now returns Result so the CLI can
surface the failure instead of panicking.
This commit is contained in:
michel
2026-04-26 12:32:46 +02:00
parent e1ee3ac493
commit 2722552e35
10 changed files with 473 additions and 164 deletions
+28
View File
@@ -0,0 +1,28 @@
use std::sync::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard};
use crate::error::{Result, SoulseekRs};
pub trait RwLockExt<T> {
fn read_safe(&self) -> Result<RwLockReadGuard<'_, T>>;
fn write_safe(&self) -> Result<RwLockWriteGuard<'_, T>>;
}
impl<T> RwLockExt<T> for RwLock<T> {
fn read_safe(&self) -> Result<RwLockReadGuard<'_, T>> {
self.read().map_err(|_| SoulseekRs::LockPoisoned)
}
fn write_safe(&self) -> Result<RwLockWriteGuard<'_, T>> {
self.write().map_err(|_| SoulseekRs::LockPoisoned)
}
}
pub trait MutexExt<T> {
fn lock_safe(&self) -> Result<MutexGuard<'_, T>>;
}
impl<T> MutexExt<T> for Mutex<T> {
fn lock_safe(&self) -> Result<MutexGuard<'_, T>> {
self.lock().map_err(|_| SoulseekRs::LockPoisoned)
}
}
+1
View File
@@ -1,5 +1,6 @@
#[macro_use]
pub mod logger;
pub mod lock;
pub mod md5;
pub mod thread_pool;
pub mod zlib;
+6 -1
View File
@@ -2,6 +2,8 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, mpsc};
use std::thread;
use crate::utils::lock::MutexExt;
type Job = Box<dyn FnOnce() + Send + 'static>;
enum Message {
@@ -91,7 +93,10 @@ impl Worker {
) -> Worker {
let thread = thread::spawn(move || {
loop {
let message = receiver.lock().unwrap().recv();
let message = match receiver.lock_safe() {
Ok(rx) => rx.recv(),
Err(_) => break,
};
match message {
Ok(Message::NewJob(job)) => {
// let active =