use std::collections::{BTreeMap, VecDeque};
use crate::*;
static mut TIMER: std::sync::Mutex<Option<Timer>> = std::sync::Mutex::new(None);
pub struct Context {
pub plugins: BTreeMap<PluginIndex, Plugin>,
pub error: Option<std::ffi::CString>,
next_id: std::sync::atomic::AtomicI32,
reclaimed_ids: VecDeque<PluginIndex>,
pub(crate) epoch_timer_tx: std::sync::mpsc::SyncSender<TimerAction>,
}
impl Default for Context {
fn default() -> Self {
Context::new()
}
}
const START_REUSING_IDS: usize = 25;
impl Context {
pub(crate) fn timer() -> std::sync::MutexGuard<'static, Option<Timer>> {
match unsafe { TIMER.lock() } {
Ok(x) => x,
Err(e) => e.into_inner(),
}
}
pub fn new() -> Context {
let timer = &mut *Self::timer();
let tx = match timer {
None => Timer::init(timer),
Some(t) => t.tx.clone(),
};
Context {
plugins: BTreeMap::new(),
error: None,
next_id: std::sync::atomic::AtomicI32::new(0),
reclaimed_ids: VecDeque::new(),
epoch_timer_tx: tx,
}
}
pub fn next_id(&mut self) -> Result<PluginIndex, Error> {
let exhausted = self.next_id.load(std::sync::atomic::Ordering::SeqCst) == PluginIndex::MAX;
if self.reclaimed_ids.len() >= START_REUSING_IDS || exhausted {
if let Some(x) = self.reclaimed_ids.pop_front() {
return Ok(x);
}
if exhausted {
return Err(anyhow::format_err!(
"All plugin descriptors are in use, unable to allocate a new plugin"
));
}
}
Ok(self
.next_id
.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
}
pub fn insert(&mut self, plugin: Plugin) -> PluginIndex {
let id: i32 = match self.next_id() {
Ok(id) => id,
Err(e) => {
error!("Error creating Plugin: {:?}", e);
self.set_error(e);
return -1;
}
};
self.plugins.insert(id, plugin);
id
}
pub fn new_plugin<'a>(
&mut self,
data: impl AsRef<[u8]>,
imports: impl IntoIterator<Item = &'a Function>,
with_wasi: bool,
) -> PluginIndex {
let plugin = match Plugin::new(data, imports, with_wasi) {
Ok(x) => x,
Err(e) => {
error!("Error creating Plugin: {:?}", e);
self.set_error(e);
return -1;
}
};
self.insert(plugin)
}
pub fn set_error(&mut self, e: impl std::fmt::Debug) {
trace!("Set context error: {:?}", e);
self.error = Some(error_string(e));
}
pub fn error<T>(&mut self, e: impl std::fmt::Debug, x: T) -> T {
self.set_error(e);
x
}
pub fn plugin(&mut self, id: PluginIndex) -> Option<*mut Plugin> {
match self.plugins.get_mut(&id) {
Some(x) => Some(x),
None => None,
}
}
pub fn plugin_exists(&mut self, id: PluginIndex) -> bool {
self.plugins.contains_key(&id)
}
pub fn remove(&mut self, id: PluginIndex) {
if self.plugins.remove(&id).is_some() {
self.reclaimed_ids.push_back(id);
}
}
}