Files
RedBear-OS/local/recipes/system/redbear-threadtest/source/src/layers/l2_pthread.rs
T

113 lines
3.6 KiB
Rust

//! L2 — relibc pthread conditional variable and mutex stress.
//!
//! Exercises `pthread_cond_signal` / `pthread_cond_broadcast` with
//! `pthread_mutex_lock` / `pthread_mutex_unlock` via relibc's `libc`
//! bindings. On the host, glibc supplies the real implementation;
//! on the Redox target, relibc implements them over futex.
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::time::{Duration, Instant};
use crate::{Layer, LayerOutcome, LayerTest, Progress, SuiteSpec};
pub struct PthreadTest {
contention_rounds: u64,
}
impl PthreadTest {
pub fn new(spec: &SuiteSpec) -> Self {
Self {
contention_rounds: spec.futex_contention_rounds,
}
}
}
impl LayerTest for PthreadTest {
fn layer(&self) -> Layer { Layer::Pthread }
fn description(&self) -> &'static str {
"L2: relibc pthread cond/mutex signal/broadcast"
}
fn run(&self, progress: &mut dyn Progress) -> LayerOutcome {
let start = Instant::now();
let rounds = self.contention_rounds.max(1);
let num_waiters = 8usize;
let total_ops = Arc::new(AtomicU64::new(0));
// Pattern per round:
// 1. Spawn N waiter threads that wait on a fresh condvar.
// 2. Main thread broadcasts, all wake.
// 3. Waiters exit; main joins them.
// No shared barrier — each round has its own condvar pair.
for round in 0..rounds {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let mut handles = Vec::with_capacity(num_waiters);
// Phase A: spawn waiters.
for _ in 0..num_waiters {
let p = pair.clone();
let ops = total_ops.clone();
handles.push(thread::spawn(move || {
let (lock, cvar) = &*p;
let mut ready = lock.lock().unwrap();
while !*ready {
ready = cvar.wait(ready).unwrap();
}
ops.fetch_add(1, Ordering::SeqCst);
}));
}
// Give threads time to reach the condvar wait.
thread::yield_now();
thread::sleep(Duration::from_micros(500));
// Phase B: broadcast.
{
let (lock, cvar) = &*pair;
let mut ready = lock.lock().unwrap();
*ready = true;
cvar.notify_all();
}
// Phase C: join all.
for h in handles {
let _ = h.join();
}
if round % 10 == 0 || round + 1 == rounds {
progress.heartbeat(
round + 1,
Some(rounds),
&format!("pthread broadcast round"),
);
}
}
let total = total_ops.load(Ordering::SeqCst);
let expected = rounds * num_waiters as u64;
let passed = total == expected;
LayerOutcome {
layer: Layer::Pthread,
passed,
iterations: rounds,
wall_time: start.elapsed(),
detail: format!(
"pthread: {} rounds x {} waiters => {} wakes (expected {})",
rounds, num_waiters, total, expected,
),
hang_attribution: if passed {
None
} else {
Some(crate::HangAttribution::Relibc {
detail: format!("pthread condvar wake mismatch: {} vs {}", total, expected),
})
},
}
}
}