1use crate::Frame;
2use dashmap::DashSet as Set;
3use once_cell::sync::Lazy;
4use rustc_hash::FxHasher;
5use std::{hash::BuildHasherDefault, ops::Deref, ptr::NonNull};
6
7#[derive(Hash, Eq, PartialEq)]
9#[repr(transparent)]
10pub struct Task(NonNull<Frame>);
11
12unsafe impl Send for Task {}
13unsafe impl Sync for Task {}
14
15static TASK_SET: Lazy<Set<Task, BuildHasherDefault<FxHasher>>> = Lazy::new(Set::default);
16
17pub(crate) unsafe fn register(root_frame: &Frame) {
21 let unique = TASK_SET.insert(Task(NonNull::from(root_frame)));
22 debug_assert!(unique);
23}
24
25pub(crate) fn deregister(root_frame: &Frame) {
27 TASK_SET.remove(&Task(NonNull::from(root_frame)));
28}
29
30pub fn tasks() -> impl Iterator<Item = impl Deref<Target = Task>> {
35 TASK_SET.iter()
36}
37
38impl Task {
39 pub fn location(&self) -> crate::Location {
41 let frame = unsafe { self.0.as_ref() };
43 frame.location()
44 }
45
46 pub fn pretty_tree(&self, block_until_idle: bool) -> String {
56 use crate::sync::TryLockError;
57
58 let frame = unsafe { self.0.as_ref() };
60
61 let current_task: Option<NonNull<Frame>> =
62 Frame::with_active(|maybe_frame| maybe_frame.map(|frame| frame.root().into()));
63
64 let maybe_lock = &frame
65 .mutex()
66 .filter(|_| Some(self.0) != current_task)
68 .map(|mutex| {
69 if block_until_idle {
70 mutex.lock().map_err(TryLockError::from)
71 } else {
72 mutex.try_lock()
73 }
74 });
75
76 let subframes_locked = match maybe_lock {
77 None | Some(Ok(..)) => true,
78 Some(Err(TryLockError::WouldBlock)) => false,
79 Some(Err(err @ TryLockError::Poisoned(..))) => panic!("{:?}", err),
80 };
81
82 let mut string = String::new();
83
84 unsafe {
85 frame.fmt(&mut string, subframes_locked).unwrap();
86 }
87
88 string
89 }
90}