1use core::cell::RefCell;
6use core::sync::atomic::Ordering;
7use std::cell::Ref;
8use std::collections::HashMap;
9
10use base::id::PipelineId;
11use strum::VariantArray;
12
13use crate::messaging::ScriptEventLoopSender;
14use crate::task::TaskCanceller;
15use crate::task_source::{TaskSource, TaskSourceName};
16
17#[derive(JSTraceable, MallocSizeOf)]
18enum TaskCancellers {
19 Shared(TaskCanceller),
22 OnePerTaskSource(RefCell<HashMap<TaskSourceName, TaskCanceller>>),
24}
25
26impl TaskCancellers {
27 fn get(&self, name: TaskSourceName) -> TaskCanceller {
28 match self {
29 Self::Shared(canceller) => canceller.clone(),
30 Self::OnePerTaskSource(map) => map.borrow_mut().entry(name).or_default().clone(),
31 }
32 }
33
34 fn cancel_all_tasks_and_ignore_future_tasks(&self) {
35 match self {
36 Self::Shared(canceller) => canceller.cancelled.store(true, Ordering::SeqCst),
37 Self::OnePerTaskSource(..) => {
38 for task_source_name in TaskSourceName::VARIANTS.iter() {
41 self.get(*task_source_name)
42 .cancelled
43 .store(true, Ordering::SeqCst)
44 }
45 },
46 }
47 }
48
49 fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) {
50 let Self::OnePerTaskSource(map) = self else {
51 unreachable!(
52 "It isn't possible to cancel pending tasks for Worker \
53 TaskManager's without ignoring future tasks."
54 )
55 };
56
57 if let Some(canceller) = map.borrow_mut().remove(&task_source_name) {
60 canceller.cancelled.store(true, Ordering::SeqCst);
62 }
63 }
64}
65
66macro_rules! task_source_functions {
67 ($self:ident, $task_source:ident, $task_source_name:ident) => {
68 pub(crate) fn $task_source(&$self) -> TaskSource<'_> {
69 TaskSource {
70 task_manager: $self,
71 name: TaskSourceName::$task_source_name,
72 }
73 }
74 };
75}
76
77#[derive(JSTraceable, MallocSizeOf)]
78pub(crate) struct TaskManager {
79 sender: RefCell<Option<ScriptEventLoopSender>>,
80 #[no_trace]
81 pipeline_id: PipelineId,
82 cancellers: TaskCancellers,
83}
84
85impl TaskManager {
86 pub(crate) fn new(
87 sender: Option<ScriptEventLoopSender>,
88 pipeline_id: PipelineId,
89 shared_canceller: Option<TaskCanceller>,
90 ) -> Self {
91 let cancellers = match shared_canceller {
92 Some(shared_canceller) => TaskCancellers::Shared(shared_canceller),
93 None => TaskCancellers::OnePerTaskSource(Default::default()),
94 };
95 let sender = RefCell::new(sender);
96
97 TaskManager {
98 sender,
99 pipeline_id,
100 cancellers,
101 }
102 }
103
104 pub(crate) fn pipeline_id(&self) -> PipelineId {
105 self.pipeline_id
106 }
107
108 pub(crate) fn sender(&self) -> Ref<'_, Option<ScriptEventLoopSender>> {
109 self.sender.borrow()
110 }
111
112 pub(crate) fn canceller(&self, name: TaskSourceName) -> TaskCanceller {
113 self.cancellers.get(name)
114 }
115
116 pub(crate) fn set_sender(&self, sender: Option<ScriptEventLoopSender>) {
120 *self.sender.borrow_mut() = sender;
121 }
122
123 pub(crate) fn cancel_all_tasks_and_ignore_future_tasks(&self) {
125 self.cancellers.cancel_all_tasks_and_ignore_future_tasks();
126 }
127
128 pub(crate) fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) {
131 self.cancellers
132 .cancel_pending_tasks_for_source(task_source_name);
133 }
134
135 task_source_functions!(self, bitmap_task_source, Bitmap);
136 task_source_functions!(self, canvas_blob_task_source, Canvas);
137 task_source_functions!(self, clipboard_task_source, Clipboard);
138 task_source_functions!(self, database_access_task_source, DatabaseAccess);
139 task_source_functions!(self, dom_manipulation_task_source, DOMManipulation);
140 task_source_functions!(self, file_reading_task_source, FileReading);
141 task_source_functions!(self, font_loading_task_source, FontLoading);
142 task_source_functions!(self, gamepad_task_source, Gamepad);
143 task_source_functions!(self, media_element_task_source, MediaElement);
144 task_source_functions!(self, networking_task_source, Networking);
145 task_source_functions!(self, performance_timeline_task_source, PerformanceTimeline);
146 task_source_functions!(self, port_message_queue, PortMessage);
147 task_source_functions!(self, remote_event_task_source, RemoteEvent);
148 task_source_functions!(self, timer_task_source, Timer);
149 task_source_functions!(self, user_interaction_task_source, UserInteraction);
150 task_source_functions!(self, websocket_task_source, WebSocket);
151 task_source_functions!(
152 self,
153 intersection_observer_task_source,
154 IntersectionObserver
155 );
156 task_source_functions!(self, webgpu_task_source, WebGPU);
157}