use std::io;
use std::sync::atomic::{AtomicI64, AtomicU32, AtomicU64, Ordering};
use crate::shared_mem;
#[repr(C)]
pub struct SharedStats {
pub global_energy: AtomicI64,
pub total_timelines: AtomicU64,
pub fork_points: AtomicU64,
pub bug_found: AtomicU64,
}
pub const MAX_RECIPE_ENTRIES: usize = 128;
#[repr(C)]
pub struct SharedRecipe {
pub claimed: AtomicU32,
pub len: u32,
pub entries: [(u64, u64); MAX_RECIPE_ENTRIES],
}
#[derive(Debug, Clone)]
pub struct ExplorationStats {
pub global_energy: i64,
pub total_timelines: u64,
pub fork_points: u64,
pub bug_found: u64,
pub realloc_pool_remaining: i64,
pub sancov_edges_total: usize,
pub sancov_edges_covered: usize,
}
pub fn init_shared_stats(energy: i64) -> Result<*mut SharedStats, io::Error> {
let ptr = shared_mem::alloc_shared(std::mem::size_of::<SharedStats>())?;
let stats = ptr as *mut SharedStats;
unsafe {
(*stats).global_energy.store(energy, Ordering::Relaxed);
}
Ok(stats)
}
pub fn init_shared_recipe() -> Result<*mut SharedRecipe, io::Error> {
let ptr = shared_mem::alloc_shared(std::mem::size_of::<SharedRecipe>())?;
Ok(ptr as *mut SharedRecipe)
}
pub unsafe fn decrement_energy(stats: *mut SharedStats) -> bool {
unsafe { (*stats).global_energy.fetch_sub(1, Ordering::Relaxed) > 0 }
}
pub unsafe fn reset_shared_stats(stats: *mut SharedStats, new_energy: i64) {
let s = unsafe { &*stats };
s.global_energy.store(new_energy, Ordering::Relaxed);
s.total_timelines.store(0, Ordering::Relaxed);
s.fork_points.store(0, Ordering::Relaxed);
s.bug_found.store(0, Ordering::Relaxed);
}
pub unsafe fn reset_shared_recipe(recipe: *mut SharedRecipe) {
let r = unsafe { &*recipe };
r.claimed.store(0, Ordering::Relaxed);
}
pub fn exploration_stats() -> Option<ExplorationStats> {
let ptr = crate::context::SHARED_STATS.with(|c| c.get());
if ptr.is_null() {
return None;
}
let realloc_pool = crate::context::ENERGY_BUDGET_PTR.with(|c| {
let energy_ptr = c.get();
if energy_ptr.is_null() {
0
} else {
unsafe { (*energy_ptr).realloc_pool.load(Ordering::Relaxed) }
}
});
unsafe {
Some(ExplorationStats {
global_energy: (*ptr).global_energy.load(Ordering::Relaxed),
total_timelines: (*ptr).total_timelines.load(Ordering::Relaxed),
fork_points: (*ptr).fork_points.load(Ordering::Relaxed),
bug_found: (*ptr).bug_found.load(Ordering::Relaxed),
realloc_pool_remaining: realloc_pool,
sancov_edges_total: crate::sancov::sancov_edge_count(),
sancov_edges_covered: crate::sancov::sancov_edges_covered(),
})
}
}
pub fn bug_recipe() -> Option<Vec<(u64, u64)>> {
let ptr = crate::context::SHARED_RECIPE.with(|c| c.get());
if ptr.is_null() {
return None;
}
unsafe {
let recipe = &*ptr;
if recipe.claimed.load(Ordering::Relaxed) == 0 {
return None;
}
let len = recipe.len as usize;
Some(recipe.entries[..len].to_vec())
}
}