memscope_rs/capture/backends/async_tracker/
task_context.rs1use std::cell::RefCell;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::Arc;
6
7thread_local! {
8 static SCOPES: RefCell<Vec<TaskFrame>> = const { RefCell::new(Vec::new()) };
9}
10
11struct TaskFrame {
12 task_id: u64,
13 active: Option<Arc<AtomicBool>>,
15}
16
17impl TaskFrame {
18 fn is_active(&self) -> bool {
19 self.active
20 .as_ref()
21 .is_none_or(|active| active.load(Ordering::Acquire))
22 }
23}
24
25pub struct TaskGuard {
30 task_id: u64,
31 active: Arc<AtomicBool>,
32}
33
34impl TaskGuard {
35 pub fn task_id(&self) -> u64 {
36 self.task_id
37 }
38
39 pub fn release(self) {
40 drop(self);
41 }
42}
43
44impl Drop for TaskGuard {
45 fn drop(&mut self) {
46 self.active.store(false, Ordering::Release);
47 }
48}
49
50pub(super) fn current() -> Option<u64> {
51 SCOPES.with(|scopes| {
52 let mut scopes = scopes.borrow_mut();
53 scopes.retain(TaskFrame::is_active);
54 scopes.last().map(|frame| frame.task_id)
55 })
56}
57
58pub(super) fn enter(task_id: u64) -> TaskGuard {
59 let active = Arc::new(AtomicBool::new(true));
60 SCOPES.with(|scopes| {
61 let mut scopes = scopes.borrow_mut();
62 scopes.retain(TaskFrame::is_active);
63 scopes.push(TaskFrame {
64 task_id,
65 active: Some(Arc::clone(&active)),
66 });
67 });
68 TaskGuard { task_id, active }
69}
70
71pub(super) fn set(task_id: u64) {
72 SCOPES.with(|scopes| {
73 let mut scopes = scopes.borrow_mut();
74 scopes.retain(|frame| frame.active.is_some() && frame.is_active());
76 scopes.push(TaskFrame {
77 task_id,
78 active: None,
79 });
80 });
81}
82
83pub(super) fn clear() {
84 SCOPES.with(|scopes| scopes.borrow_mut().clear());
85}
86
87pub(super) fn end(task_id: u64) {
93 SCOPES.with(|scopes| {
94 scopes.borrow_mut().retain(|frame| {
95 frame.is_active() && !(frame.task_id == task_id && frame.active.is_none())
96 });
97 });
98}