use std::sync::mpsc;
use std::thread;
#[global_allocator]
static ALLOC: kevy_alloc::KevyAlloc = kevy_alloc::KevyAlloc;
fn mapping_available() -> bool {
kevy_alloc::os::available()
}
#[test]
fn the_standard_library_runs_on_it() {
if !mapping_available() {
eprintln!("skipped: no anonymous mapping on this target");
return;
}
let mut v: Vec<u64> = Vec::new();
for i in 0..100_000u64 {
v.push(i * 3);
}
assert_eq!(v.len(), 100_000);
assert_eq!(v[99_999], 299_997);
v.retain(|x| x % 7 == 0);
assert!(!v.is_empty());
let mut kept = Vec::new();
for n in [1usize, 17, 400, 8192, 8193, 70_000] {
let s = "x".repeat(n);
assert_eq!(s.len(), n);
kept.push(s);
}
assert_eq!(kept.iter().map(String::len).sum::<usize>(), 86_803);
let boxed: Box<Aligned64> = Box::new(Aligned64([7u8; 64]));
assert_eq!(boxed.0[63], 7);
assert_eq!(core::ptr::from_ref(&*boxed) as usize % 64, 0);
}
#[repr(align(64))]
struct Aligned64([u8; 64]);
#[test]
fn over_aligned_blocks_survive_a_round_trip() {
if !mapping_available() {
return;
}
let mut held: Vec<Box<Aligned64>> = Vec::new();
for i in 0..500usize {
held.push(Box::new(Aligned64([i as u8; 64])));
}
for (i, b) in held.iter().enumerate() {
assert_eq!(core::ptr::from_ref(&**b) as usize % 64, 0, "block {i} lost its alignment");
assert_eq!(b.0[0], i as u8, "block {i} was corrupted");
assert_eq!(b.0[63], i as u8, "block {i} was corrupted at its end");
}
}
fn make(seed: u64) -> Vec<u64> {
let len = 4 + (seed as usize % 900);
let mut v = Vec::with_capacity(len);
for i in 0..len as u64 {
v.push(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15).wrapping_add(i));
}
v
}
fn check(seed: u64, v: &[u64]) {
let len = 4 + (seed as usize % 900);
assert_eq!(v.len(), len, "length changed under seed {seed}");
for (i, got) in v.iter().enumerate() {
let want = seed.wrapping_mul(0x9E37_79B9_7F4A_7C15).wrapping_add(i as u64);
assert_eq!(*got, want, "seed {seed} element {i} was corrupted");
}
}
#[test]
fn m5_allocations_freed_on_a_foreign_thread_survive_intact() {
if !mapping_available() {
return;
}
const PRODUCERS: u64 = 4;
const EACH: u64 = 5_000;
let (tx, rx) = mpsc::channel::<(u64, Vec<u64>)>();
let producers: Vec<_> = (0..PRODUCERS)
.map(|p| {
let tx = tx.clone();
thread::spawn(move || {
for i in 0..EACH {
let seed = p * EACH + i + 1;
tx.send((seed, make(seed))).expect("consumer alive");
}
})
})
.collect();
drop(tx);
let mut seen = 0u64;
for (seed, payload) in rx {
check(seed, &payload);
seen += 1;
}
for p in producers {
p.join().expect("producer finished");
}
assert_eq!(seen, PRODUCERS * EACH, "payloads went missing in transit");
}
#[test]
fn m5_threads_may_exit_while_their_memory_is_still_held() {
if !mapping_available() {
return;
}
let mut survivors: Vec<Vec<u64>> = Vec::new();
for round in 0..8u64 {
let handle = thread::spawn(move || {
let mut out = Vec::new();
for i in 0..2_000u64 {
out.push(make(round * 10_000 + i + 1));
}
out
});
let batch = handle.join().expect("worker finished");
for (i, v) in batch.iter().enumerate() {
check(round * 10_000 + i as u64 + 1, v);
}
survivors.extend(batch);
}
assert_eq!(survivors.len(), 16_000);
for (i, v) in survivors.iter().enumerate() {
let round = i as u64 / 2_000;
let seed = round * 10_000 + (i as u64 % 2_000) + 1;
check(seed, v);
}
}
#[test]
fn thread_stats_balance_under_the_standard_library() {
if !mapping_available() {
return;
}
let mut ballast: Vec<Vec<u8>> = (0..2_000).map(|i| vec![i as u8; 300]).collect();
let st = kevy_alloc::thread_stats().expect("thread-local heap is reachable");
assert!(st.balanced(), "identity broken under real workload: {st:?}");
assert!(st.live > 0, "the harness itself should be holding memory");
ballast.clear();
ballast.shrink_to_fit();
kevy_alloc::thread_reclaim();
let after = kevy_alloc::thread_stats().expect("still reachable");
assert!(after.balanced(), "identity broken after reclaim: {after:?}");
}