diff --git a/ci/evidence/provenance-audit.json b/ci/evidence/provenance-audit.json index a95a528..1d844b6 100644 --- a/ci/evidence/provenance-audit.json +++ b/ci/evidence/provenance-audit.json @@ -1,6 +1,6 @@ { "schema": 1, - "recorded_unix_seconds": 1786610180, + "recorded_unix_seconds": 1786611260, "upstream_commit": "2aa70bb68513b39795da5d13c88f31b86e85a3ba", "material_count": 27, "generated_output_count": 8, @@ -12,7 +12,7 @@ "dependency_manifest_sha256": "5f80b45ab18a45365673b55b52d68318bc31f602ce2f6559f573027cc446c58e", "third_party_notices_sha256": "c4d381944a9b57277963d2a5ee4e23a9a064c2ba93a676a49e023931b53a71d6", "native_notices_sha256": "b417ee7bf6b748cc86839e5354753c0f8c1f8309d13c0fea379c77f602e69fc0", - "distribution_manifest_sha256": "9dc77128962f410e5ff7ecee947d2726e537cc42d9ef57a18d639c9bdcd2406e", + "distribution_manifest_sha256": "95af81f60a3823cac35e6716d1500d052bc7e22127d84f705798414a085f6762", "unknown_materials": 0, "unknown_bundled_assets": 0, "status": "ok" diff --git a/crates/libremetaverse/src/threading_runtime.rs b/crates/libremetaverse/src/threading_runtime.rs index c4071c9..425204c 100644 --- a/crates/libremetaverse/src/threading_runtime.rs +++ b/crates/libremetaverse/src/threading_runtime.rs @@ -913,34 +913,50 @@ impl WaitHandleAsyncFactory { mod tests { use super::*; use std::sync::atomic::{AtomicBool, Ordering}; + use std::sync::{Barrier, mpsc}; #[test] fn auto_reset_releases_exactly_one_waiter_per_signal() { - let event = Arc::new(ManagedAutoResetEvent::new_with_constructor().unwrap()); - let first = Arc::clone(&event); - let second = Arc::clone(&event); - let first_done = Arc::new(AtomicBool::new(false)); - let second_done = Arc::new(AtomicBool::new(false)); - let first_flag = Arc::clone(&first_done); - let second_flag = Arc::clone(&second_done); - let a = std::thread::spawn(move || { - first.wait_one_with_method().unwrap(); - first_flag.store(true, Ordering::SeqCst); - }); - let b = std::thread::spawn(move || { - second.wait_one_with_method().unwrap(); - second_flag.store(true, Ordering::SeqCst); - }); - std::thread::sleep(Duration::from_millis(20)); - event.set().unwrap(); - std::thread::sleep(Duration::from_millis(20)); - assert_ne!( - first_done.load(Ordering::SeqCst), - second_done.load(Ordering::SeqCst) - ); - event.set().unwrap(); - a.join().unwrap(); - b.join().unwrap(); + for _ in 0..32 { + let event = Arc::new(ManagedAutoResetEvent::new_with_constructor().unwrap()); + let ready = Arc::new(Barrier::new(3)); + let (completed, completions) = mpsc::channel(); + let mut waiters = Vec::new(); + for id in 0..2 { + let event = Arc::clone(&event); + let ready = Arc::clone(&ready); + let completed = completed.clone(); + waiters.push(std::thread::spawn(move || { + ready.wait(); + event.wait_one_with_method().unwrap(); + completed.send(id).unwrap(); + })); + } + drop(completed); + + // Release both contenders together. The signal is deliberately + // allowed to race their actual wait calls: an auto-reset event + // must retain one signal even when no waiter has blocked yet. + ready.wait(); + event.set().unwrap(); + let first = completions + .recv_timeout(Duration::from_secs(2)) + .expect("one waiter must consume the first signal"); + assert_eq!( + completions.recv_timeout(Duration::from_millis(10)), + Err(mpsc::RecvTimeoutError::Timeout), + "one auto-reset signal released both waiters" + ); + + event.set().unwrap(); + let second = completions + .recv_timeout(Duration::from_secs(2)) + .expect("the second waiter must consume the second signal"); + assert_ne!(first, second); + for waiter in waiters { + waiter.join().unwrap(); + } + } } #[test] diff --git a/release/DISTRIBUTION-MANIFEST.json b/release/DISTRIBUTION-MANIFEST.json index 273b8ae..fcb58a7 100644 --- a/release/DISTRIBUTION-MANIFEST.json +++ b/release/DISTRIBUTION-MANIFEST.json @@ -1547,8 +1547,8 @@ }, { "path": "crates/libremetaverse/src/threading_runtime.rs", - "bytes": 30843, - "sha256": "2ab324af0ba240770e7fd0a6d12d3fc4e6972722d099d9e7914e11cac18bef0e" + "bytes": 31537, + "sha256": "f08e8055e56655e922b4806f13f003ea0cd3574ad9fb8bdac5d11e1697fc51ab" }, { "path": "crates/libremetaverse/src/transfers.rs",