Harden concurrency and resource lifecycle (#101)
Some checks failed
Native code generation / deterministic (push) Failing after 2m4s
Concurrency and resource soak audit / soak (push) Failing after 6m31s
Imaging and meshing gate / native (push) Failing after 2m52s
JPEG 2000 feature / linux (push) Successful in 2m45s
Release platform and feature matrix / audit (push) Successful in 35s
Native Rust workspace compile / compile (push) Failing after 54s
Release platform and feature matrix / matrix (false, linux-stable-minimal, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, macos-stable-portable, x86_64-apple-darwin, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (false, windows-stable-portable, x86_64-pc-windows-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-msrv-portable, x86_64-unknown-linux-gnu, 1.96.0) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-default, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-features, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Release platform and feature matrix / matrix (true, linux-stable-release-surface, x86_64-unknown-linux-gnu, stable) (push) Has been cancelled
Dependency and supply-chain audit / audit (push) Has been cancelled
Skia feature / linux (push) Has been cancelled

This commit is contained in:
2026-08-11 23:39:05 +00:00
parent 9e3b532a7e
commit 3db144da63
17 changed files with 1217 additions and 23 deletions

View File

@@ -30,6 +30,7 @@ use libremetaverse_types::compat::{
use libremetaverse_types::{AssetType, UUID, Utils};
use serde_json::Value;
use std::collections::{BTreeMap, HashMap};
use std::panic::{AssertUnwindSafe, catch_unwind};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};
@@ -87,11 +88,43 @@ impl<T: Clone + 'static> EventSlot<T> {
fn emit(&self, value: T) {
let handlers: Vec<_> = mutex(&self.handlers).values().cloned().collect();
for handler in handlers {
handler(value.clone());
let argument = value.clone();
let _ = catch_unwind(AssertUnwindSafe(|| handler(argument)));
}
}
}
#[cfg(test)]
mod event_slot_tests {
use super::*;
#[test]
fn dispatch_isolates_panics_and_does_not_retain_dropped_handlers() {
let slot = Arc::new(EventSlot::<usize>::default());
let released = Arc::new(());
let released_probe = Arc::downgrade(&released);
let panicking = slot.subscribe(Arc::new(|_| panic!("subscriber failure")));
let delivered = Arc::new(AtomicU64::new(0));
let delivered_handler = Arc::clone(&delivered);
let releasing = Arc::clone(&released);
let healthy = slot.subscribe(Arc::new(move |value| {
let _keep_alive = &releasing;
delivered_handler.fetch_add(value as u64, Ordering::AcqRel);
}));
drop(released);
slot.emit(1);
assert_eq!(delivered.load(Ordering::Acquire), 1);
assert!(released_probe.upgrade().is_some());
drop(panicking);
drop(healthy);
assert!(released_probe.upgrade().is_none());
slot.emit(1);
assert_eq!(delivered.load(Ordering::Acquire), 1);
}
}
struct UploadState {
asset_id: UUID,
data: Vec<u8>,