fix(threading): make auto-reset regression deterministic
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m54s
CI / required (push) Failing after 13m14s

This commit is contained in:
2026-08-13 08:54:53 +00:00
parent 2ec65d0e8a
commit 6f67568f47
3 changed files with 45 additions and 29 deletions

View File

@@ -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"

View File

@@ -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() {
for _ in 0..32 {
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));
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();
std::thread::sleep(Duration::from_millis(20));
assert_ne!(
first_done.load(Ordering::SeqCst),
second_done.load(Ordering::SeqCst)
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();
a.join().unwrap();
b.join().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]

View File

@@ -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",