use super::super::*;
use crate::LocalAllocatorSelector;
use core::ptr::NonNull;
use mnemosyne_arena::{allocate_segment, deallocate_segment};
use mnemosyne_core::constants::{PAGE_SHIFT, PAGES_PER_SEGMENT};
use mnemosyne_core::policy::StandardPolicy;
#[test]
fn test_snmalloc_message_passing() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use std::thread;
unsafe {
mnemosyne_arena::purge_segment_pool::<DefaultBackend>();
mnemosyne_arena::purge_segment_pool::<mnemosyne_backend::MemoryBackendWrapper>();
}
let mut alloc_a = ThreadAllocator::<DefaultBackend>::new();
let ptr = unsafe { alloc_a.alloc::<StandardPolicy>(32) };
assert!(
!ptr.is_null(),
"producer allocation for cross-thread free failed"
);
let ptr_usize = ptr as usize;
let handle = thread::spawn(move || {
unsafe {
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(
ptr_usize as *mut u8,
);
}
});
handle.join().expect("cross-thread free worker panicked");
let mut reclaimed_remote_free = false;
let ptr_val = ptr as usize;
let segment_addr = ptr_val & !(mnemosyne_core::constants::SEGMENT_SIZE - 1);
let segment = segment_addr as *mut Segment;
let page_index = (ptr_val >> PAGE_SHIFT) & (PAGES_PER_SEGMENT - 1);
let max_blocks = unsafe { (*segment).pages[page_index].max_blocks() };
for _ in 0..max_blocks {
let ptr2 = unsafe { alloc_a.alloc::<StandardPolicy>(32) };
assert!(
!ptr2.is_null(),
"reclaim probe allocation failed before reclaiming remote free"
);
if ptr2 == ptr {
reclaimed_remote_free = true;
break;
}
}
assert!(
reclaimed_remote_free,
"cross-thread freed block was not reclaimed after {} small allocations",
max_blocks
);
}
#[test]
fn cross_thread_free_does_not_charge_non_owner_defrag_counter() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use std::thread;
let mut owner = ThreadAllocator::<DefaultBackend>::new();
let ptr = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(
!ptr.is_null(),
"producer allocation for cross-thread free failed"
);
let ptr_usize = ptr as usize;
let handle = thread::spawn(move || {
DefaultBackend::with_allocator(|alloc| {
assert_eq!(alloc.defrag_counter, 0);
})
.expect("worker allocator slot unavailable before remote free");
unsafe {
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(
ptr_usize as *mut u8,
);
}
DefaultBackend::with_allocator(|alloc| {
assert_eq!(
alloc.defrag_counter, 0,
"remote free charged defrag work to the non-owner allocator"
);
})
.expect("worker allocator slot unavailable after remote free");
});
handle.join().expect("cross-thread free worker panicked");
let mut reclaimed_remote_free = false;
let ptr_val = ptr as usize;
let segment_addr = ptr_val & !(mnemosyne_core::constants::SEGMENT_SIZE - 1);
let segment = segment_addr as *mut Segment;
let page_index = (ptr_val >> PAGE_SHIFT) & (PAGES_PER_SEGMENT - 1);
let max_blocks = unsafe { (*segment).pages[page_index].max_blocks() };
for _ in 0..max_blocks {
let ptr2 = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(
!ptr2.is_null(),
"reclaim probe allocation failed before reclaiming remote free"
);
if ptr2 == ptr {
reclaimed_remote_free = true;
break;
}
}
assert!(
reclaimed_remote_free,
"cross-thread freed block was not reclaimed after {} small allocations",
max_blocks
);
}
#[test]
fn test_orphan_segment_reuse() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use std::sync::mpsc;
use std::thread;
unsafe {
mnemosyne_arena::purge_segment_pool::<DefaultBackend>();
mnemosyne_arena::purge_segment_pool::<mnemosyne_backend::MemoryBackendWrapper>();
}
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut alloc_a = ThreadAllocator::<DefaultBackend>::new();
let ptr = unsafe { alloc_a.alloc::<StandardPolicy>(32) };
assert!(!ptr.is_null(), "orphan producer allocation failed");
tx.send(ptr as usize)
.expect("orphan producer failed to send live allocation pointer");
})
.join()
.expect("orphan producer thread panicked");
let live_ptr =
rx.recv()
.expect("orphan producer did not send live allocation pointer") as *mut u8;
let mut alloc_b = ThreadAllocator::<DefaultBackend>::new();
let ptr_b = unsafe { alloc_b.alloc::<StandardPolicy>(64) };
assert!(!ptr_b.is_null(), "orphan consumer allocation failed");
assert_eq!(alloc_b.stats().current_thread_owned_segments, 1);
unsafe {
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(live_ptr);
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(ptr_b);
}
}
unsafe fn drain_orphan_pools_for_test() {
use mnemosyne_arena::HasSegmentPool;
unsafe {
while let Some(seg) = <DefaultBackend as HasSegmentPool>::global_orphan_pool().pop() {
deallocate_segment::<DefaultBackend>(seg);
}
while let Some(seg) =
<mnemosyne_backend::MemoryBackendWrapper as HasSegmentPool>::global_orphan_pool().pop()
{
deallocate_segment::<mnemosyne_backend::MemoryBackendWrapper>(seg);
}
mnemosyne_arena::purge_segment_pool::<DefaultBackend>();
mnemosyne_arena::purge_segment_pool::<mnemosyne_backend::MemoryBackendWrapper>();
}
}
#[test]
fn test_hardened_orphan_adoption_preserves_encoded_chains() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use mnemosyne_core::policy::HardenedPolicy;
use std::sync::mpsc;
use std::thread;
use std::vec::Vec;
unsafe { drain_orphan_pools_for_test() };
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut alloc_a = ThreadAllocator::<DefaultBackend>::new();
let ptrs: Vec<*mut u8> = (0..4)
.map(|_| unsafe { alloc_a.alloc::<HardenedPolicy>(32) })
.collect();
assert!(
ptrs.iter().all(|p| !p.is_null()),
"hardened orphan producer allocation failed"
);
unsafe {
crate::thread_free::<HardenedPolicy, DefaultBackend>(ptrs[1]);
crate::thread_free::<HardenedPolicy, DefaultBackend>(ptrs[3]);
}
tx.send((
[ptrs[0] as usize, ptrs[2] as usize],
[ptrs[1] as usize, ptrs[3] as usize],
))
.expect("hardened orphan producer failed to send pointers");
})
.join()
.expect("hardened orphan producer thread panicked");
let (live, freed) = rx
.recv()
.expect("hardened orphan producer did not send pointers");
let mut alloc_b = ThreadAllocator::<DefaultBackend>::new();
let first = unsafe { alloc_b.alloc::<HardenedPolicy>(32) };
assert!(
!first.is_null(),
"hardened orphan consumer allocation failed"
);
let stats = alloc_b.stats();
assert_eq!(
stats.current_thread_owned_segments, 1,
"consumer must adopt the compatible hardened orphan, not map a fresh segment"
);
assert_eq!(stats.orphan_segments_adopted, 1);
let cap = 3 * (mnemosyne_core::constants::PAGE_SIZE / 32);
let mut reused = 0usize;
let mut consumer_ptrs = Vec::with_capacity(cap + 1);
consumer_ptrs.push(first);
for _ in 0..cap {
let p = unsafe { alloc_b.alloc::<HardenedPolicy>(32) };
assert!(
!p.is_null(),
"hardened consumer allocation failed mid-sweep"
);
consumer_ptrs.push(p);
if freed.contains(&(p as usize)) {
unsafe {
core::ptr::write_bytes(p, 0xAB, 32);
assert_eq!(*p, 0xAB);
assert_eq!(*p.add(31), 0xAB);
}
reused += 1;
if reused == freed.len() {
break;
}
}
}
assert_eq!(
reused,
freed.len(),
"adopted encoded free chain was not fully popped within {cap} allocations"
);
unsafe {
for p in consumer_ptrs {
crate::thread_free::<HardenedPolicy, DefaultBackend>(p);
}
for addr in live {
crate::thread_free::<HardenedPolicy, DefaultBackend>(addr as *mut u8);
}
}
}
#[test]
fn test_orphan_adoption_skips_policy_mismatched_segment() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use mnemosyne_core::policy::HardenedPolicy;
use std::sync::mpsc;
use std::thread;
unsafe { drain_orphan_pools_for_test() };
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let mut alloc_a = ThreadAllocator::<DefaultBackend>::new();
let ptr = unsafe { alloc_a.alloc::<StandardPolicy>(32) };
assert!(!ptr.is_null(), "standard orphan producer allocation failed");
tx.send(ptr as usize)
.expect("standard orphan producer failed to send pointer");
})
.join()
.expect("standard orphan producer thread panicked");
let live_ptr = rx
.recv()
.expect("standard orphan producer did not send pointer") as *mut u8;
let mut alloc_hardened = ThreadAllocator::<DefaultBackend>::new();
let ptr_h = unsafe { alloc_hardened.alloc::<HardenedPolicy>(32) };
assert!(!ptr_h.is_null(), "hardened consumer allocation failed");
let stats_h = alloc_hardened.stats();
assert_eq!(
stats_h.orphan_segments_adopted, 0,
"hardened consumer must not adopt a plain-encoded orphan"
);
assert_eq!(stats_h.fresh_segments, 1);
assert_eq!(stats_h.current_thread_owned_segments, 1);
let mut alloc_standard = ThreadAllocator::<DefaultBackend>::new();
let ptr_s = unsafe { alloc_standard.alloc::<StandardPolicy>(64) };
assert!(!ptr_s.is_null(), "standard consumer allocation failed");
let stats_s = alloc_standard.stats();
assert_eq!(
stats_s.orphan_segments_adopted, 1,
"standard consumer must adopt the deferred plain orphan"
);
assert_eq!(stats_s.current_thread_owned_segments, 1);
unsafe {
crate::thread_free::<StandardPolicy, DefaultBackend>(live_ptr);
crate::thread_free::<HardenedPolicy, DefaultBackend>(ptr_h);
crate::thread_free::<StandardPolicy, DefaultBackend>(ptr_s);
}
}
#[test]
fn test_mixed_policy_free_and_realloc_preserve_segment_encoding() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use mnemosyne_core::policy::HardenedPolicy;
use std::alloc::Layout;
unsafe { drain_orphan_pools_for_test() };
let hardened_slot =
<DefaultBackend as LocalAllocatorSelector<DefaultBackend>>::get_allocator_ptr_for_policy::<
HardenedPolicy,
>();
let standard_slot =
<DefaultBackend as LocalAllocatorSelector<DefaultBackend>>::get_allocator_ptr_for_policy::<
StandardPolicy,
>();
assert!(
!standard_slot.is_null(),
"standard TLS slot must initialize"
);
let hardened_first = unsafe { crate::thread_alloc::<HardenedPolicy, DefaultBackend>(32, 8) };
let hardened_second = unsafe { crate::thread_alloc::<HardenedPolicy, DefaultBackend>(32, 8) };
let hardened_third = unsafe { crate::thread_alloc::<HardenedPolicy, DefaultBackend>(32, 8) };
assert!(!hardened_first.is_null());
assert!(!hardened_second.is_null());
assert!(!hardened_third.is_null());
let hardened_slot_after = <DefaultBackend as LocalAllocatorSelector<DefaultBackend>>::
get_allocator_ptr_raw_for_policy::<HardenedPolicy>();
assert!(!hardened_slot_after.is_null());
assert_ne!(
hardened_slot_after, standard_slot,
"standard and hardened policies must not share a TLS allocator"
);
assert_eq!(hardened_slot, hardened_slot_after);
unsafe {
crate::thread_free::<StandardPolicy, DefaultBackend>(hardened_second);
}
let reused = unsafe { crate::thread_alloc::<HardenedPolicy, DefaultBackend>(32, 8) };
assert_eq!(
reused, hardened_second,
"hardened free-list head must remain decodable after a standard-policy free"
);
let layout = Layout::from_size_align(32, 8).expect("test layout is valid");
let resized = unsafe {
crate::thread_realloc::<StandardPolicy, DefaultBackend>(hardened_first, layout, 64)
};
assert!(
!resized.is_null(),
"mixed-policy realloc must produce a block"
);
let realloc_reused = unsafe { crate::thread_alloc::<HardenedPolicy, DefaultBackend>(32, 8) };
assert_eq!(
realloc_reused, hardened_first,
"hardened allocator must decode the block freed by standard-policy realloc"
);
unsafe {
crate::thread_free::<HardenedPolicy, DefaultBackend>(hardened_third);
crate::thread_free::<HardenedPolicy, DefaultBackend>(reused);
crate::thread_free::<HardenedPolicy, DefaultBackend>(realloc_reused);
crate::thread_free::<StandardPolicy, DefaultBackend>(resized);
}
}
#[test]
fn test_online_defragmentation_page_prioritization() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
let mut alloc = ThreadAllocator::<DefaultBackend>::new();
let seg1 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg1 allocation failed");
let seg2 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg2 allocation failed");
unsafe {
(*seg1).pages[1].set_alloc_count(1);
(*seg1).pages[2].set_alloc_count(0);
}
unsafe {
for i in 1..mnemosyne_core::constants::PAGES_PER_SEGMENT {
(*seg2).pages[i].set_alloc_count(0);
}
}
let seg1_page2 = unsafe { NonNull::new_unchecked(&mut (*seg1).pages[2] as *mut Page) };
let seg2_page1 = unsafe { NonNull::new_unchecked(&mut (*seg2).pages[1] as *mut Page) };
unsafe {
alloc.push_empty_page(seg1_page2);
alloc.push_empty_page(seg2_page1);
}
let popped = unsafe { alloc.pop_best_empty_page() };
assert_eq!(popped, Some(seg1_page2));
let popped2 = unsafe { alloc.pop_best_empty_page() };
assert_eq!(popped2, Some(seg2_page1));
let popped3 = unsafe { alloc.pop_best_empty_page() };
assert_eq!(popped3, None);
unsafe {
deallocate_segment::<DefaultBackend>(seg1);
deallocate_segment::<DefaultBackend>(seg2);
}
}
#[test]
fn test_periodic_defragmentation_segment_reclaim() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
{
let mut alloc = ThreadAllocator::<DefaultBackend>::new();
let seg1 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg1 failed");
let seg2 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg2 failed");
let seg3 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg3 failed");
unsafe {
alloc.push_owned_segment::<StandardPolicy>(seg1);
alloc.push_owned_segment::<StandardPolicy>(seg2);
alloc.push_owned_segment::<StandardPolicy>(seg3);
}
let stats = alloc.stats();
assert_eq!(stats.current_thread_owned_segments, 3);
unsafe {
alloc.periodic_defragmentation_sweep::<StandardPolicy>();
}
let stats = alloc.stats();
assert_eq!(stats.current_thread_owned_segments, 3);
}
{
let mut alloc = ThreadAllocator::<DefaultBackend>::new();
let seg1 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg1 failed");
let seg2 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg2 failed");
let seg3 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg3 failed");
let seg4 = unsafe { allocate_segment::<DefaultBackend>() }.expect("seg4 failed");
unsafe {
alloc.push_owned_segment::<StandardPolicy>(seg1);
alloc.push_owned_segment::<StandardPolicy>(seg2);
alloc.push_owned_segment::<StandardPolicy>(seg3);
alloc.push_owned_segment::<StandardPolicy>(seg4);
}
unsafe {
alloc.set_current_segment(Some(NonNull::new_unchecked(seg1)));
}
let stats = alloc.stats();
assert_eq!(stats.current_thread_owned_segments, 4);
unsafe {
alloc.periodic_defragmentation_sweep::<StandardPolicy>();
}
let stats = alloc.stats();
assert_eq!(stats.current_thread_owned_segments, 3);
assert!(alloc.is_current_segment(seg1));
}
}
#[test]
fn cross_thread_free_pushes_block_to_page_thread_free_queue() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use std::thread;
let mut owner = ThreadAllocator::<DefaultBackend>::new();
let ptr = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(
!ptr.is_null(),
"owner alloc for thread_free queue anchor failed"
);
let ptr_val = ptr as usize;
let segment_addr = ptr_val & !(mnemosyne_core::constants::SEGMENT_SIZE - 1);
let segment = segment_addr as *mut Segment;
let page_index = (ptr_val >> PAGE_SHIFT) & (PAGES_PER_SEGMENT - 1);
let page = unsafe { &(*segment).pages[page_index] };
assert!(
page.thread_free.is_empty(),
"thread_free must be empty before any remote free; alloc_count={}",
page.alloc_count,
);
let handle = thread::spawn(move || unsafe {
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(ptr_val as *mut u8);
});
handle.join().expect("cross-thread free worker panicked");
let page = unsafe { &mut (*segment).pages[page_index] };
assert!(
!page.thread_free.is_empty(),
"cross-thread free did not enqueue the block on page.thread_free",
);
let before_alloc_count = page.alloc_count;
let reclaimed = unsafe { page.reclaim_thread_free::<StandardPolicy>() };
assert_eq!(
reclaimed, 1,
"expected exactly one block from the cross-thread free on this page; got {} \
(alloc_count before drain = {})",
reclaimed, before_alloc_count,
);
}
#[test]
fn allocation_side_reclaim_counts_cross_thread_blocks_exactly() {
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
use std::thread;
unsafe {
mnemosyne_arena::purge_segment_pool::<DefaultBackend>();
mnemosyne_arena::purge_segment_pool::<mnemosyne_backend::MemoryBackendWrapper>();
}
let mut owner = ThreadAllocator::<DefaultBackend>::new();
let first = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(!first.is_null(), "owner anchor allocation failed");
let (segment, page_index) = unsafe { mnemosyne_core::types::locate_segment(first) };
let max_blocks = unsafe { (*segment).pages[page_index].max_blocks() };
assert!(max_blocks >= 2, "size class must hold at least two blocks");
let mut blocks = std::vec::Vec::with_capacity(max_blocks);
blocks.push(first as usize);
for _ in 1..max_blocks {
let p = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(!p.is_null(), "owner fill allocation failed");
blocks.push(p as usize);
}
assert_eq!(
owner.cross_thread_reclaimed, 0,
"fresh allocator must have reclaimed no cross-thread blocks"
);
let stats_before = owner.stats().cross_thread_reclaimed_blocks;
let freed = blocks.clone();
thread::spawn(move || unsafe {
for addr in freed {
crate::thread_free::<mnemosyne_core::StandardPolicy, DefaultBackend>(addr as *mut u8);
}
})
.join()
.expect("cross-thread free worker panicked");
let reclaimed_ptr = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(
!reclaimed_ptr.is_null(),
"owner allocation after remote frees failed"
);
assert_eq!(
owner.cross_thread_reclaimed, max_blocks,
"per-thread reclaim counter must equal the number of cross-thread frees"
);
assert_eq!(
owner.stats().cross_thread_reclaimed_blocks,
stats_before + max_blocks,
"stats() must report the exact cross-thread reclaimed delta"
);
}
#[test]
fn cross_thread_stress_producer_consumer() {
use std::sync::mpsc;
use std::thread;
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
const NUM_PRODUCERS: usize = 4;
const ALLOCS_PER_PRODUCER: usize = 200;
let mut producers = std::vec::Vec::new();
let mut consumers = std::vec::Vec::new();
for tid in 0..NUM_PRODUCERS {
let (tx, rx) = mpsc::channel::<std::vec::Vec<usize>>();
producers.push(thread::spawn(move || {
let mut alloc = ThreadAllocator::<DefaultBackend>::new();
let mut ptrs = std::vec::Vec::with_capacity(ALLOCS_PER_PRODUCER);
for i in 0..ALLOCS_PER_PRODUCER {
let size = if (i + tid) % 2 == 0 { 32 } else { 64 };
let ptr = unsafe { alloc.alloc::<StandardPolicy>(size) };
assert!(!ptr.is_null(), "producer {tid} alloc {i} failed");
unsafe {
*ptr = (tid * 100 + i) as u8;
}
ptrs.push(ptr as usize);
}
tx.send(ptrs).expect("producer failed to send ptrs");
}));
consumers.push(thread::spawn(move || {
let _alloc = ThreadAllocator::<DefaultBackend>::new();
for ptrs in rx {
for addr in ptrs {
unsafe {
crate::thread_free::<StandardPolicy, DefaultBackend>(addr as *mut u8);
}
}
}
}));
}
for handle in producers.into_iter() {
handle.join().expect("producer thread panicked");
}
for handle in consumers.into_iter() {
handle.join().expect("consumer thread panicked");
}
}
#[test]
fn cross_thread_stress_many_to_one_free() {
use std::sync::mpsc;
use std::thread;
let _guard = TEST_LOCK
.lock()
.expect("local allocator test lock was poisoned");
const NUM_FREER_THREADS: usize = 8;
const TOTAL_ALLOCS: usize = 640;
let mut owner = ThreadAllocator::<DefaultBackend>::new();
let mut all_ptrs = std::vec::Vec::with_capacity(TOTAL_ALLOCS);
for i in 0..TOTAL_ALLOCS {
let ptr = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(!ptr.is_null(), "owner alloc {i} failed");
unsafe {
*ptr = i as u8;
}
all_ptrs.push(ptr as usize);
}
let chunk_size = TOTAL_ALLOCS / NUM_FREER_THREADS;
let (tx, rx) = mpsc::channel();
for chunk_idx in 0..NUM_FREER_THREADS {
let start = chunk_idx * chunk_size;
let end = if chunk_idx == NUM_FREER_THREADS - 1 {
TOTAL_ALLOCS
} else {
start + chunk_size
};
let chunk: std::vec::Vec<usize> = all_ptrs[start..end].to_vec();
let tx = tx.clone();
thread::spawn(move || unsafe {
for addr in chunk {
crate::thread_free::<StandardPolicy, DefaultBackend>(addr as *mut u8);
}
tx.send(()).expect("freer failed to signal completion");
});
}
drop(tx);
for _ in 0..NUM_FREER_THREADS {
rx.recv().expect("freer thread did not signal completion");
}
let post_stress = unsafe { owner.alloc::<StandardPolicy>(32) };
assert!(
!post_stress.is_null(),
"owner allocation failed after cross-thread contention storm"
);
unsafe {
core::ptr::write_bytes(post_stress, 0xFF, 32);
assert_eq!(*post_stress, 0xFF);
}
unsafe {
crate::thread_free::<StandardPolicy, DefaultBackend>(post_stress);
}
}