use std::sync::{
Arc, OnceLock,
atomic::{AtomicUsize, Ordering},
};
#[derive(Clone)]
pub struct ForegroundRunnableCounter(Arc<AtomicUsize>);
impl ForegroundRunnableCounter {
pub fn new() -> Self {
Self(Arc::new(AtomicUsize::new(0)))
}
pub fn queued(&self) {
self.0.fetch_add(1, Ordering::Release);
}
pub fn finished(&self) {
let _ = self
.0
.fetch_update(Ordering::AcqRel, Ordering::Acquire, |count| {
count.checked_sub(1)
});
}
pub fn has_runnables(&self) -> bool {
self.0.load(Ordering::Acquire) > 0
}
}
impl Default for ForegroundRunnableCounter {
fn default() -> Self {
Self::new()
}
}
thread_local! {
static FOREGROUND_RUNNABLES: ForegroundRunnableCounter = ForegroundRunnableCounter::new();
}
pub fn foreground_runnable_counter() -> ForegroundRunnableCounter {
FOREGROUND_RUNNABLES.with(Clone::clone)
}
pub fn foreground_runnable_finished() {
FOREGROUND_RUNNABLES.with(ForegroundRunnableCounter::finished);
}
pub type UpdateRunningTaskFn = fn(scheduler::SpawnTime, &'static std::panic::Location<'static>);
pub type SaveTaskTimingFn = fn();
struct TaskProfilerHooks {
update_running_task: UpdateRunningTaskFn,
save_task_timing: SaveTaskTimingFn,
}
static TASK_PROFILER_HOOKS: OnceLock<TaskProfilerHooks> = OnceLock::new();
pub fn set_task_profiler(
update_running_task: UpdateRunningTaskFn,
save_task_timing: SaveTaskTimingFn,
) {
if TASK_PROFILER_HOOKS
.set(TaskProfilerHooks {
update_running_task,
save_task_timing,
})
.is_err()
{
log::debug!("task profiler hooks were already installed");
}
}
#[doc(hidden)]
#[inline]
pub fn update_running_task(
spawned: scheduler::SpawnTime,
location: &'static std::panic::Location<'static>,
) {
if let Some(hooks) = TASK_PROFILER_HOOKS.get() {
(hooks.update_running_task)(spawned, location);
}
}
#[doc(hidden)]
#[inline]
pub fn save_task_timing() {
if let Some(hooks) = TASK_PROFILER_HOOKS.get() {
(hooks.save_task_timing)();
}
}