use core::any::TypeId;
use ruda_core::device::DeviceId;
pub(super) type ServiceId = (TypeId, DeviceId);
pub(super) fn service_id<R: Runtime>(client: &ComputeClient<R>) -> ServiceId {
(TypeId::of::<R::Server>(), client.device_id())
}
use hashbrown::HashMap;
use spin::Mutex;
use ruda::runtime::{backend::Runtime, client::ComputeClient};
static POOLED_PROBES: Mutex<Option<HashMap<ServiceId, usize>>> = Mutex::new(None);
pub(super) struct PooledProbes {
service: ServiceId,
}
impl PooledProbes {
pub(super) fn enter<R: Runtime>(client: &ComputeClient<R>) -> Self {
Self::enter_service(service_id(client))
}
fn enter_service(service: ServiceId) -> Self {
let mut pooled = POOLED_PROBES.lock();
*pooled
.get_or_insert_with(HashMap::new)
.entry(service)
.or_insert(0) += 1;
Self { service }
}
pub(super) fn cleanup_unless_held<R: Runtime>(client: &ComputeClient<R>) {
Self::cleanup_unless_held_by(service_id(client), || {
let _ = client.memory_cleanup();
});
}
fn cleanup_unless_held_by(service: ServiceId, release: impl FnOnce()) {
let held = {
let pooled = POOLED_PROBES.lock();
Self::held_by(&pooled, service)
};
if !held {
release();
}
}
fn held_by(pooled: &Option<HashMap<ServiceId, usize>>, service: ServiceId) -> bool {
pooled
.as_ref()
.is_some_and(|sweeps| sweeps.contains_key(&service))
}
}
impl Drop for PooledProbes {
fn drop(&mut self) {
let mut pooled = POOLED_PROBES.lock();
let Some(sweeps) = pooled.as_mut() else {
return;
};
if let Some(holders) = sweeps.get_mut(&self.service) {
*holders -= 1;
if *holders == 0 {
sweeps.remove(&self.service);
}
}
}
}