#![cfg(any(target_os="linux", target_os="l4re", target_os="android", windows))]
#![cfg(not(feature="tokio"))]
use {
core::{
sync::atomic::{AtomicUsize, Ordering},
time::Duration,
},
std::{
sync::Arc,
thread,
time::Instant,
},
blackhole::{BlackHole, OneTime},
namaste::Result,
zeros::keccak::Hash,
};
const HALF_THREAD_COUNT: usize = 5;
const THREAD_COUNT: usize = HALF_THREAD_COUNT * 2;
const TIMEOUT: Duration = Duration::from_millis(500);
const DELAY: Duration = Duration::from_millis(100);
const SMALL_DELAY: Duration = Duration::from_millis(50);
const ORDERING: Ordering = Ordering::Relaxed;
#[test]
fn tests() -> Result<()> {
assert!(SMALL_DELAY < DELAY);
let ids = (0..THREAD_COUNT).into_iter().map(|i| Hash::Sha3_512.hash([
namaste::ID.as_bytes(),
&[
0xa2, 0x56, 0x0c, 0xcd, 0x5f, 0xb3, 0x9d, 0x93, 0xd4, 0x1c, 0xe2, 0x0a, 0x5d, 0x12, 0xeb, 0xaf, 0xe8, 0x3f, 0x34, 0x0e, 0x8f, 0x74,
0x93, 0x20, 0x76, 0xb6, 0xaa, 0x7b, 0x54, 0x8f, 0x93, 0x34, 0xe4, 0x8d, 0x85, 0xc1, 0x25, 0x64, 0xdb, 0xfd, 0x0f, 0x93, 0x53, 0x10,
0x28, 0x7e, 0xfd, 0x4d, 0x1e, 0x23, 0xd7, 0x9b, 0xa1, 0xe7, 0x13, 0x30, 0xcb, 0x9c, 0x16, 0xdb, 0x85, 0x85, 0x83, 0x7b,
],
&(i % HALF_THREAD_COUNT).to_be_bytes(),
]));
let counter = Arc::new(AtomicUsize::new(usize::min_value()));
let blackhole = BlackHole::make(THREAD_COUNT)?;
let start = Instant::now();
for (index, id) in ids.enumerate() {
let counter = counter.clone();
assert!(blackhole.throw(OneTime::new(move || {
if index < HALF_THREAD_COUNT {
let _namaste = namaste::make(id).unwrap();
thread::sleep(DELAY);
} else {
thread::sleep(SMALL_DELAY);
let _namaste = namaste::make_wait(id, TIMEOUT).unwrap();
}
counter.fetch_add(1, ORDERING);
}))?.is_none());
}
blackhole.escape_on_idle()?;
let duration = Instant::now().duration_since(start).as_millis();
assert_eq!(counter.load(ORDERING), THREAD_COUNT);
assert!(duration >= DELAY.as_millis() && duration <= DELAY.as_millis().checked_mul(HALF_THREAD_COUNT.try_into().unwrap()).unwrap());
Ok(())
}