use std::cell::RefCell;
use std::collections::HashMap;
use crate::sched::assert_control::{self, SiteId};
use crate::sched::{ProcessId, current_process};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Entry {
pub process: Option<ProcessId>,
pub key: u64,
pub values: Vec<i64>,
}
thread_local! {
static QUEUE: RefCell<Vec<Entry>> = const { RefCell::new(Vec::new()) };
static SITES: RefCell<HashMap<i64, SiteId>> = RefCell::new(HashMap::new());
static PROCESSES: RefCell<HashMap<i64, ProcessId>> = RefCell::new(HashMap::new());
}
pub const PROCESS_KEY_FLAG: i64 = 1 << 40;
pub fn register_process(plan_index: i64, pid: ProcessId) {
PROCESSES.with(|p| p.borrow_mut().insert(plan_index, pid));
}
pub fn register_site(key: i64, site: SiteId) {
SITES.with(|s| s.borrow_mut().insert(key, site));
}
pub(crate) fn clear_sites(sites: &[SiteId]) {
let keys: Vec<i64> = SITES.with(|s| {
s.borrow()
.iter()
.filter(|(_, site)| sites.contains(site))
.map(|(k, _)| *k)
.collect()
});
clear(&keys);
}
#[cfg_attr(feature = "aot-exports", unsafe(export_name = "sv_rt_proc_assert"))]
pub unsafe extern "C" fn real_sv_rt_proc_assert(key: i64, values: *const i64, n: i64) {
if let Some(site) = SITES.with(|s| s.borrow().get(&key).copied())
&& !assert_control::state(site).checking
{
return;
}
let values = if n <= 0 || values.is_null() {
Vec::new()
} else {
unsafe { std::slice::from_raw_parts(values, n as usize) }.to_vec()
};
let process = current_process();
QUEUE.with(|q| {
q.borrow_mut().push(Entry {
process,
key: key as u64,
values,
});
});
}
pub(crate) fn flush(proc: ProcessId) {
QUEUE.with(|q| q.borrow_mut().retain(|e| e.process != Some(proc)));
}
#[cfg_attr(
feature = "aot-exports",
unsafe(export_name = "sv_rt_proc_assert_disable")
)]
pub unsafe extern "C" fn real_sv_rt_proc_assert_disable(keys: *const i64, n: i64) {
if n <= 0 || keys.is_null() {
return;
}
let keys = unsafe { std::slice::from_raw_parts(keys, n as usize) };
clear(keys);
for k in keys.iter().filter(|k| **k & PROCESS_KEY_FLAG != 0) {
if let Some(pid) = PROCESSES.with(|p| p.borrow().get(&(*k & !PROCESS_KEY_FLAG)).copied()) {
crate::sched::deferred::flush_deferred(pid);
}
}
}
pub(crate) fn clear(keys: &[i64]) {
QUEUE.with(|q| q.borrow_mut().retain(|e| !keys.contains(&(e.key as i64))));
}
pub fn drain() -> Vec<Entry> {
QUEUE.with(|q| std::mem::take(&mut *q.borrow_mut()))
}
pub fn is_empty() -> bool {
QUEUE.with(|q| q.borrow().is_empty())
}
pub fn reset() {
QUEUE.with(|q| q.borrow_mut().clear());
SITES.with(|s| s.borrow_mut().clear());
PROCESSES.with(|p| p.borrow_mut().clear());
}
thread_local! {
static INPUTS: RefCell<Vec<i64>> = const { RefCell::new(Vec::new()) };
}
pub fn set_action_inputs(values: Vec<i64>) {
INPUTS.with(|i| *i.borrow_mut() = values);
}
#[cfg_attr(feature = "aot-exports", unsafe(export_name = "sv_rt_assert_input"))]
pub extern "C" fn real_sv_rt_assert_input(k: i64) -> i64 {
INPUTS.with(|i| i.borrow().get(k as usize).copied().unwrap_or(0))
}