script: Eliminate code duplication in the task queue (#34798)

Instead of creating a type for each `TaskSource` variety have each `TaskSource`
hold the same kind of sender (this was inconsistent before, but each
sender was effectively the same trait object), a pipeline, and a
`TaskSourceName`. This elminates the need to reimplement the same
queuing code for every task source.

In addition, have workers hold their own `TaskManager`. This allows just
exposing the manager on the `GlobalScope`. Currently the `TaskCanceller`
is different, but this will also be eliminated in a followup change.

This is a the first step toward having a shared set of `Sender`s on
`GlobalScope`.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-01 14:50:52 +01:00 committed by GitHub
parent deb819f233
commit 77cfca65c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
67 changed files with 432 additions and 1200 deletions

View file

@ -35,7 +35,7 @@ impl ScriptChan for SendableWorkerScriptChan {
self.sender.send(msg).map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan + Send> {
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(SendableWorkerScriptChan {
sender: self.sender.clone(),
worker: self.worker.clone(),
@ -62,7 +62,7 @@ impl ScriptChan for WorkerThreadWorkerChan {
self.sender.send(msg).map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan + Send> {
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(WorkerThreadWorkerChan {
sender: self.sender.clone(),
worker: self.worker.clone(),

View file

@ -27,7 +27,6 @@ use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
use crate::dom::bindings::root::DomRoot;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct AnalyserNode {

View file

@ -35,7 +35,6 @@ use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::realms::InRealm;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct AudioContext {

View file

@ -17,7 +17,6 @@ use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::num::Finite;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::DomObject;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct AudioScheduledSourceNode {

View file

@ -16,7 +16,6 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct AudioTrackList {

View file

@ -68,7 +68,6 @@ use crate::dom::stereopannernode::StereoPannerNode;
use crate::dom::window::Window;
use crate::realms::InRealm;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[allow(dead_code)]
pub enum BaseAudioContextOptions {

View file

@ -244,7 +244,7 @@ pub fn response_async<T: AsyncBluetoothListener + DomObject + 'static>(
receiver: &T,
) -> IpcSender<BluetoothResponseResult> {
let (action_sender, action_receiver) = ipc::channel().unwrap();
let task_source = receiver.global().networking_task_source();
let task_source = receiver.global().task_manager().networking_task_source();
let context = Arc::new(Mutex::new(BluetoothContext {
promise: Some(TrustedPromise::new(promise.clone())),
receiver: Trusted::new(receiver),

View file

@ -60,8 +60,7 @@ use crate::script_runtime::{
ThreadSafeJSContext,
};
use crate::task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::TaskSourceName;
use crate::task_source::{TaskSource, TaskSourceName};
/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
/// value for the duration of this object's lifetime. This ensures that the related Worker
@ -192,7 +191,7 @@ pub struct DedicatedWorkerGlobalScope {
worker: DomRefCell<Option<TrustedWorkerAddress>>,
#[ignore_malloc_size_of = "Can't measure trait objects"]
/// Sender to the parent thread.
parent_sender: Box<dyn ScriptChan + Send>,
parent_sender: Box<dyn ScriptChan>,
#[ignore_malloc_size_of = "Arc"]
#[no_trace]
image_cache: Arc<dyn ImageCache>,
@ -381,13 +380,14 @@ impl DedicatedWorkerGlobalScope {
.origin(origin);
let runtime = unsafe {
let task_source = NetworkingTaskSource(
Box::new(WorkerThreadWorkerChan {
let task_source = TaskSource {
sender: Box::new(WorkerThreadWorkerChan {
sender: own_sender.clone(),
worker: worker.clone(),
}),
pipeline_id,
);
name: TaskSourceName::Networking,
};
Runtime::new_with_parent(Some(parent), Some(task_source))
};

View file

@ -192,7 +192,7 @@ use crate::script_runtime::{CanGc, CommonScriptMsg, ScriptThreadEventCategory};
use crate::script_thread::{with_script_thread, ScriptThread};
use crate::stylesheet_set::StylesheetSetRef;
use crate::task::TaskBox;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSourceName;
use crate::timers::OneshotTimerCallback;
/// The number of times we are allowed to see spurious `requestAnimationFrame()` calls before

View file

@ -45,7 +45,7 @@ use crate::fetch::{create_a_potential_cors_request, FetchCanceller};
use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingListener};
use crate::realms::enter_realm;
use crate::script_runtime::CanGc;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSourceName;
use crate::timers::OneshotTimerCallback;
const DEFAULT_RECONNECTION_TIME: Duration = Duration::from_millis(5000);
@ -113,7 +113,7 @@ impl EventSourceContext {
let global = event_source.global();
let event_source = self.event_source.clone();
// FIXME(nox): Why are errors silenced here?
let _ = global.remote_event_task_source().queue(
let _ = global.task_manager().remote_event_task_source().queue(
task!(announce_the_event_source_connection: move || {
let event_source = event_source.root();
if event_source.ready_state.get() != ReadyState::Closed {
@ -146,7 +146,7 @@ impl EventSourceContext {
let action_sender = self.action_sender.clone();
let global = event_source.global();
// FIXME(nox): Why are errors silenced here?
let _ = global.remote_event_task_source().queue(
let _ = global.task_manager().remote_event_task_source().queue(
task!(reestablish_the_event_source_onnection: move || {
let event_source = trusted_event_source.root();
@ -259,7 +259,7 @@ impl EventSourceContext {
let event_source = self.event_source.clone();
let event = Trusted::new(&*event);
// FIXME(nox): Why are errors silenced here?
let _ = global.remote_event_task_source().queue(
let _ = global.task_manager().remote_event_task_source().queue(
task!(dispatch_the_event_source_event: move || {
let event_source = event_source.root();
if event_source.ready_state.get() != ReadyState::Closed {
@ -500,7 +500,7 @@ impl EventSource {
let global = self.global();
let event_source = Trusted::new(self);
// FIXME(nox): Why are errors silenced here?
let _ = global.remote_event_task_source().queue(
let _ = global.task_manager().remote_event_task_source().queue(
task!(fail_the_event_source_connection: move || {
let event_source = event_source.root();
if event_source.ready_state.get() != ReadyState::Closed {
@ -605,7 +605,7 @@ impl EventSourceMethods<crate::DomTypeHolder> for EventSource {
};
let listener = NetworkListener {
context: Arc::new(Mutex::new(context)),
task_source: global.networking_task_source(),
task_source: global.task_manager().networking_task_source(),
canceller: Some(global.task_canceller(TaskSourceName::Networking)),
};
ROUTER.add_typed_route(

View file

@ -36,9 +36,41 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::progressevent::ProgressEvent;
use crate::realms::enter_realm;
use crate::script_runtime::{CanGc, JSContext};
use crate::task_source::file_reading::FileReadingTask;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task::TaskOnce;
use crate::task_source::TaskSourceName;
#[allow(dead_code)]
pub enum FileReadingTask {
ProcessRead(TrustedFileReader, GenerationId),
ProcessReadData(TrustedFileReader, GenerationId),
ProcessReadError(TrustedFileReader, GenerationId, DOMErrorName),
ProcessReadEOF(TrustedFileReader, GenerationId, ReadMetaData, Vec<u8>),
}
impl TaskOnce for FileReadingTask {
fn run_once(self) {
self.handle_task(CanGc::note());
}
}
impl FileReadingTask {
pub fn handle_task(self, can_gc: CanGc) {
use self::FileReadingTask::*;
match self {
ProcessRead(reader, gen_id) => FileReader::process_read(reader, gen_id, can_gc),
ProcessReadData(reader, gen_id) => {
FileReader::process_read_data(reader, gen_id, can_gc)
},
ProcessReadError(reader, gen_id, error) => {
FileReader::process_read_error(reader, gen_id, error, can_gc)
},
ProcessReadEOF(reader, gen_id, metadata, blob_contents) => {
FileReader::process_read_eof(reader, gen_id, metadata, blob_contents, can_gc)
},
}
}
}
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub enum FileReaderFunction {
Text,
@ -472,7 +504,7 @@ impl FileReader {
let filereader = Trusted::new(self);
let global = self.global();
let canceller = global.task_canceller(TaskSourceName::FileReading);
let task_source = global.file_reading_task_source();
let task_source = global.task_manager().file_reading_task_source();
// Queue tasks as appropriate.
let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id);

View file

@ -28,12 +28,11 @@ use crate::dom::promise::Promise;
use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskCanceller;
use crate::task_source::gamepad::GamepadTaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
struct HapticEffectListener {
canceller: TaskCanceller,
task_source: GamepadTaskSource,
task_source: TaskSource,
context: Trusted<GamepadHapticActuator>,
}
@ -199,7 +198,7 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
if let Some(promise) = self.playing_effect_promise.borrow_mut().take() {
let trusted_promise = TrustedPromise::new(promise);
let _ = self.global().gamepad_task_source().queue(
let _ = self.global().task_manager().gamepad_task_source().queue(
task!(preempt_promise: move || {
let promise = trusted_promise.root();
let message = DOMString::from("preempted");
@ -221,7 +220,7 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let (effect_complete_sender, effect_complete_receiver) =
ipc::channel().expect("ipc channel failure");
let (task_source, canceller) = (
self.global().gamepad_task_source(),
self.global().task_manager().gamepad_task_source(),
self.global().task_canceller(TaskSourceName::Gamepad),
);
let listener = HapticEffectListener {
@ -272,7 +271,7 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
if let Some(promise) = self.playing_effect_promise.borrow_mut().take() {
let trusted_promise = TrustedPromise::new(promise);
let _ = self.global().gamepad_task_source().queue(
let _ = self.global().task_manager().gamepad_task_source().queue(
task!(preempt_promise: move || {
let promise = trusted_promise.root();
let message = DOMString::from("preempted");
@ -290,7 +289,7 @@ impl GamepadHapticActuatorMethods<crate::DomTypeHolder> for GamepadHapticActuato
let (effect_stop_sender, effect_stop_receiver) =
ipc::channel().expect("ipc channel failure");
let (task_source, canceller) = (
self.global().gamepad_task_source(),
self.global().task_manager().gamepad_task_source(),
self.global().task_canceller(TaskSourceName::Gamepad),
);
let listener = HapticEffectListener {
@ -342,7 +341,7 @@ impl GamepadHapticActuator {
let trusted_promise = TrustedPromise::new(promise);
let sequence_id = self.sequence_id.get();
let reset_sequence_id = self.reset_sequence_id.get();
let _ = self.global().gamepad_task_source().queue(
let _ = self.global().task_manager().gamepad_task_source().queue(
task!(complete_promise: move || {
if sequence_id != reset_sequence_id {
warn!("Mismatched sequence/reset sequence ids: {} != {}", sequence_id, reset_sequence_id);
@ -364,7 +363,7 @@ impl GamepadHapticActuator {
}
let this = Trusted::new(self);
let _ = self.global().gamepad_task_source().queue(
let _ = self.global().task_manager().gamepad_task_source().queue(
task!(stop_playing_effect: move || {
let actuator = this.root();
let Some(promise) = actuator.playing_effect_promise.borrow_mut().take() else {

View file

@ -138,15 +138,7 @@ use crate::script_runtime::{
use crate::script_thread::{with_script_thread, ScriptThread};
use crate::security_manager::CSPViolationReporter;
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::gamepad::GamepadTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_manager::TaskManager;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::timers::{
IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
@ -383,14 +375,14 @@ pub struct GlobalScope {
/// A wrapper for glue-code between the ipc router and the event-loop.
struct MessageListener {
canceller: TaskCanceller,
task_source: PortMessageQueue,
task_source: TaskSource,
context: Trusted<GlobalScope>,
}
/// A wrapper for broadcasts coming in over IPC, and the event-loop.
struct BroadcastListener {
canceller: TaskCanceller,
task_source: DOMManipulationTaskSource,
task_source: TaskSource,
context: Trusted<GlobalScope>,
}
@ -398,7 +390,7 @@ struct BroadcastListener {
#[derive(Clone)]
pub(crate) struct TimerListener {
canceller: TaskCanceller,
task_source: TimerTaskSource,
task_source: TaskSource,
context: Trusted<GlobalScope>,
}
@ -410,7 +402,7 @@ struct FileListener {
/// - Some(Empty) => Some(Receiving) => None
/// - Some(Empty) => None
state: Option<FileListenerState>,
task_source: FileReadingTaskSource,
task_source: TaskSource,
task_canceller: TaskCanceller,
}
@ -860,7 +852,7 @@ impl GlobalScope {
fn timers(&self) -> &OneshotTimers {
self.timers.get_or_init(|| {
let (task_source, canceller) = (
self.timer_task_source(),
self.task_manager().timer_task_source(),
self.task_canceller(TaskSourceName::Timer),
);
OneshotTimers::new(
@ -1102,7 +1094,7 @@ impl GlobalScope {
for task in message_buffer {
let port_id = *port_id;
let this = Trusted::new(self);
let _ = self.port_message_queue().queue(
let _ = self.task_manager().port_message_queue().queue(
task!(process_pending_port_messages: move || {
let target_global = this.root();
target_global.route_task_to_port(port_id, task, CanGc::note());
@ -1156,7 +1148,7 @@ impl GlobalScope {
if let Some(entangled_id) = entangled_port {
// Step 7
let this = Trusted::new(self);
let _ = self.port_message_queue().queue(
let _ = self.task_manager().port_message_queue().queue(
task!(post_message: move || {
let global = this.root();
// Note: we do this in a task, as this will ensure the global and constellation
@ -1253,7 +1245,7 @@ impl GlobalScope {
// to fire the message event
let channel = Trusted::new(&*channel);
let global = Trusted::new(self);
let _ = self.dom_manipulation_task_source().queue(
let _ = self.task_manager().dom_manipulation_task_source().queue(
task!(process_pending_port_messages: move || {
let destination = channel.root();
let global = global.root();
@ -1447,7 +1439,7 @@ impl GlobalScope {
ipc::channel().expect("ipc channel failure");
let context = Trusted::new(self);
let (task_source, canceller) = (
self.dom_manipulation_task_source(),
self.task_manager().dom_manipulation_task_source(),
self.task_canceller(TaskSourceName::DOMManipulation),
);
let listener = BroadcastListener {
@ -1500,7 +1492,7 @@ impl GlobalScope {
ipc::channel().expect("ipc channel failure");
let context = Trusted::new(self);
let (task_source, canceller) = (
self.port_message_queue(),
self.task_manager().port_message_queue(),
self.task_canceller(TaskSourceName::PortMessage),
);
let listener = MessageListener {
@ -1543,7 +1535,7 @@ impl GlobalScope {
// Queue a task to complete the transfer,
// unless the port is re-transferred in the current task.
let this = Trusted::new(self);
let _ = self.port_message_queue().queue(
let _ = self.task_manager().port_message_queue().queue(
task!(process_pending_port_messages: move || {
let target_global = this.root();
target_global.maybe_add_pending_ports();
@ -2026,7 +2018,7 @@ impl GlobalScope {
let trusted_stream = Trusted::new(&*stream.clone());
let task_canceller = self.task_canceller(TaskSourceName::FileReading);
let task_source = self.file_reading_task_source();
let task_source = self.task_manager().file_reading_task_source();
let mut file_listener = FileListener {
state: Some(FileListenerState::Empty(FileListenerTarget::Stream(
@ -2051,7 +2043,7 @@ impl GlobalScope {
let trusted_promise = TrustedPromise::new(promise);
let task_canceller = self.task_canceller(TaskSourceName::FileReading);
let task_source = self.file_reading_task_source();
let task_source = self.task_manager().file_reading_task_source();
let mut file_listener = FileListener {
state: Some(FileListenerState::Empty(FileListenerTarget::Promise(
@ -2595,72 +2587,13 @@ impl GlobalScope {
unreachable!();
}
/// `TaskSource` to send messages to the gamepad task source of
/// this global scope.
/// <https://w3c.github.io/gamepad/#dfn-gamepad-task-source>
pub fn gamepad_task_source(&self) -> GamepadTaskSource {
/// The [`TaskManager`] used to schedule tasks for this [`GlobalScope`].
pub fn task_manager(&self) -> &TaskManager {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().gamepad_task_source();
}
unreachable!();
}
/// `TaskSource` to send messages to the networking task source of
/// this global scope.
pub fn networking_task_source(&self) -> NetworkingTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().networking_task_source();
return window.task_manager();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.networking_task_source();
}
unreachable!();
}
/// `TaskSource` to send messages to the port message queue of
/// this global scope.
pub fn port_message_queue(&self) -> PortMessageQueue {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().port_message_queue();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.port_message_queue();
}
unreachable!();
}
/// `TaskSource` to send messages to the timer queue of
/// this global scope.
pub fn timer_task_source(&self) -> TimerTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().timer_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.timer_task_source();
}
unreachable!();
}
/// `TaskSource` to send messages to the remote-event task source of
/// this global scope.
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().remote_event_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.remote_event_task_source();
}
unreachable!();
}
/// `TaskSource` to send messages to the websocket task source of
/// this global scope.
pub fn websocket_task_source(&self) -> WebsocketTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().websocket_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.websocket_task_source();
return worker.task_manager();
}
unreachable!();
}
@ -2842,7 +2775,8 @@ impl GlobalScope {
scripted_caller.line,
scripted_caller.col,
);
self.dom_manipulation_task_source()
self.task_manager()
.dom_manipulation_task_source()
.queue(task, self)
.unwrap();
}
@ -3024,28 +2958,6 @@ impl GlobalScope {
unreachable!();
}
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().dom_manipulation_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.dom_manipulation_task_source();
}
unreachable!();
}
/// Channel to send messages to the file reading task source of
/// this of this global scope.
pub fn file_reading_task_source(&self) -> FileReadingTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().file_reading_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.file_reading_task_source();
}
unreachable!();
}
pub fn runtime_handle(&self) -> ParentRuntime {
if self.is::<Window>() {
ScriptThread::runtime_handle()
@ -3096,18 +3008,6 @@ impl GlobalScope {
unreachable!();
}
/// Channel to send messages to the performance timeline task source
/// of this global scope.
pub fn performance_timeline_task_source(&self) -> PerformanceTimelineTaskSource {
if let Some(window) = self.downcast::<Window>() {
return window.task_manager().performance_timeline_task_source();
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
return worker.performance_timeline_task_source();
}
unreachable!();
}
/// <https://w3c.github.io/performance-timeline/#supportedentrytypes-attribute>
pub fn supported_performance_entry_types(&self, cx: SafeJSContext, retval: MutableHandleValue) {
self.frozen_supported_performance_entry_types.get_or_init(
@ -3261,7 +3161,8 @@ impl GlobalScope {
// TODO: 2. If document is not null and is not allowed to use the "gamepad" permission,
// then abort these steps.
let this = Trusted::new(self);
self.gamepad_task_source()
self.task_manager()
.gamepad_task_source()
.queue_with_canceller(
task!(gamepad_connected: move || {
let global = this.root();
@ -3291,7 +3192,8 @@ impl GlobalScope {
/// <https://www.w3.org/TR/gamepad/#dfn-gamepaddisconnected>
pub fn handle_gamepad_disconnect(&self, index: usize) {
let this = Trusted::new(self);
self.gamepad_task_source()
self.task_manager()
.gamepad_task_source()
.queue_with_canceller(
task!(gamepad_disconnected: move || {
let global = this.root();
@ -3315,7 +3217,8 @@ impl GlobalScope {
let this = Trusted::new(self);
// <https://w3c.github.io/gamepad/#dfn-update-gamepad-state>
self.gamepad_task_source()
self.task_manager()
.gamepad_task_source()
.queue_with_canceller(
task!(update_gamepad_state: move || {
let global = this.root();
@ -3427,7 +3330,7 @@ impl GlobalScope {
&self,
request_builder: RequestBuilder,
context: Arc<Mutex<Listener>>,
task_source: NetworkingTaskSource,
task_source: TaskSource,
cancellation_sender: Option<ipc::IpcReceiver<()>>,
) {
let canceller = Some(self.task_canceller(TaskSourceName::Networking));

View file

@ -20,7 +20,6 @@ use crate::dom::htmlelement::HTMLElement;
use crate::dom::node::{window_from_node, Node, NodeDamage};
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct HTMLDetailsElement {

View file

@ -84,7 +84,6 @@ use crate::dom::window::Window;
use crate::links::{get_element_target, LinkRelations};
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
pub struct GenerationId(u32);

View file

@ -98,7 +98,6 @@ use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
use crate::realms::enter_realm;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
#[derive(Clone, Copy, Debug)]
enum ParseState {

View file

@ -106,7 +106,6 @@ use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
#[derive(PartialEq)]
enum FrameStatus {

View file

@ -67,7 +67,6 @@ use crate::script_module::{
};
use crate::script_runtime::CanGc;
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::unminify::{unminify_js, ScriptSource};
@ -104,7 +103,7 @@ impl ScriptSource for ScriptOrigin {
script_kind: ExternalScriptKind,
final_url: ServoUrl,
url: ServoUrl,
task_source: DOMManipulationTaskSource,
task_source: TaskSource,
canceller: TaskCanceller,
script_text: String,
fetch_options: ScriptFetchOptions,
@ -478,7 +477,7 @@ impl FetchResponseListener for ClassicContext {
script_kind: self.kind,
final_url,
url: self.url.clone(),
task_source: global.dom_manipulation_task_source(),
task_source: global.task_manager().dom_manipulation_task_source(),
canceller: global.task_canceller(TaskSourceName::DOMManipulation),
script_text: source_string,
fetch_options: self.fetch_options.clone(),

View file

@ -32,7 +32,6 @@ use crate::dom::promise::Promise;
use crate::dom::window::Window;
use crate::realms::InRealm;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct OfflineAudioContext {

View file

@ -10,6 +10,7 @@ use base::cross_process_instant::CrossProcessInstant;
use dom_struct::dom_struct;
use time_03::Duration;
use super::bindings::refcounted::Trusted;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::PerformanceBinding::{
DOMHighResTimeStamp, PerformanceEntryList as DOMPerformanceEntryList, PerformanceMethods,
@ -237,8 +238,16 @@ impl Performance {
if !self.pending_notification_observers_task.get() {
self.pending_notification_observers_task.set(true);
let task_source = self.global().performance_timeline_task_source();
task_source.queue_notification(&self.global());
let task_source = self
.global()
.task_manager()
.performance_timeline_task_source();
let global = &self.global();
let owner = Trusted::new(&*global.performance());
let task = task!(notify_performance_observers: move || {
owner.root().notify_observers();
});
let _ = task_source.queue(task, global);
}
}
let mut observers = self.observers.borrow_mut();
@ -315,8 +324,17 @@ impl Performance {
// Step 6.
// Queue a new notification task.
self.pending_notification_observers_task.set(true);
let task_source = self.global().performance_timeline_task_source();
task_source.queue_notification(&self.global());
let task_source = self
.global()
.task_manager()
.performance_timeline_task_source();
let global = &self.global();
let owner = Trusted::new(&*global.performance());
let task = task!(notify_performance_observers: move || {
owner.root().notify_observers();
});
let _ = task_source.queue(task, global);
Some(entry_last_index)
}

View file

@ -53,7 +53,6 @@ use crate::dom::window::Window;
use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
use crate::task::TaskCanceller;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::TaskSource;
#[dom_struct]
@ -81,7 +80,7 @@ pub struct RTCPeerConnection {
struct RTCSignaller {
trusted: Trusted<RTCPeerConnection>,
task_source: NetworkingTaskSource,
task_source: TaskSource,
canceller: TaskCanceller,
}

View file

@ -20,7 +20,6 @@ use crate::dom::eventtarget::EventTarget;
use crate::dom::node::{window_from_node, Node};
use crate::dom::range::Range;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[derive(Clone, Copy, JSTraceable, MallocSizeOf)]
enum Direction {

View file

@ -27,7 +27,6 @@ use crate::dom::serviceworkerregistration::ServiceWorkerRegistration;
use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::CanGc;
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
#[dom_struct]
@ -143,7 +142,7 @@ impl ServiceWorkerContainerMethods<crate::DomTypeHolder> for ServiceWorkerContai
// Setup the callback for reject/resolve of the promise,
// from steps running "in-parallel" from here in the serviceworker manager.
let (task_source, task_canceller) = (
global.dom_manipulation_task_source(),
global.task_manager().dom_manipulation_task_source(),
global.task_canceller(TaskSourceName::DOMManipulation),
);
@ -190,7 +189,7 @@ impl ServiceWorkerContainerMethods<crate::DomTypeHolder> for ServiceWorkerContai
/// <https://w3c.github.io/ServiceWorker/#register>
struct RegisterJobResultHandler {
trusted_promise: Option<TrustedPromise>,
task_source: DOMManipulationTaskSource,
task_source: TaskSource,
task_canceller: TaskCanceller,
}

View file

@ -143,7 +143,7 @@ impl ScriptChan for ServiceWorkerChan {
.map_err(|_| ())
}
fn as_boxed(&self) -> Box<dyn ScriptChan + Send> {
fn as_boxed(&self) -> Box<dyn ScriptChan> {
Box::new(ServiceWorkerChan {
sender: self.sender.clone(),
})

View file

@ -21,7 +21,6 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::storageevent::StorageEvent;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct Storage {

View file

@ -54,7 +54,6 @@ use crate::dom::workerglobalscope::WorkerGlobalScope;
use crate::realms::InRealm;
use crate::script_runtime::{CanGc, JSContext};
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::TaskSource;
// String constants for algorithms/curves
@ -142,13 +141,13 @@ impl SubtleCrypto {
)
}
fn task_source_with_canceller(&self) -> (DOMManipulationTaskSource, TaskCanceller) {
fn task_source_with_canceller(&self) -> (TaskSource, TaskCanceller) {
if let Some(window) = self.global().downcast::<Window>() {
window
.task_manager()
.dom_manipulation_task_source_with_canceller()
} else if let Some(worker_global) = self.global().downcast::<WorkerGlobalScope>() {
let task_source = worker_global.dom_manipulation_task_source();
let task_source = worker_global.task_manager().dom_manipulation_task_source();
let canceller = worker_global.task_canceller();
(task_source, canceller)
} else {

View file

@ -18,7 +18,6 @@ use crate::dom::texttrack::TextTrack;
use crate::dom::trackevent::TrackEvent;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct TextTrackList {

View file

@ -16,7 +16,6 @@ use crate::dom::htmlmediaelement::HTMLMediaElement;
use crate::dom::videotrack::VideoTrack;
use crate::dom::window::Window;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct VideoTrackList {

View file

@ -16,7 +16,6 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct WebGLQuery {

View file

@ -15,7 +15,6 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::webglobject::WebGLObject;
use crate::dom::webglrenderingcontext::{Operation, WebGLRenderingContext};
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct WebGLSync {

View file

@ -25,7 +25,7 @@ use crate::dom::promise::Promise;
use crate::dom::webgpu::gpuadapter::GPUAdapter;
use crate::realms::InRealm;
use crate::script_runtime::CanGc;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSourceName;
#[dom_struct]
#[allow(clippy::upper_case_acronyms)]
@ -69,7 +69,10 @@ pub fn response_async<T: AsyncWGPUListener + DomObject + 'static>(
receiver: &T,
) -> IpcSender<WebGPUResponse> {
let (action_sender, action_receiver) = ipc::channel().unwrap();
let task_source = receiver.global().dom_manipulation_task_source();
let task_source = receiver
.global()
.task_manager()
.dom_manipulation_task_source();
let canceller = receiver
.global()
.task_canceller(TaskSourceName::DOMManipulation);

View file

@ -38,11 +38,9 @@ use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::script_runtime::ScriptThreadEventCategory::WebSocketEvent;
use crate::script_runtime::{CanGc, CommonScriptMsg};
use crate::script_runtime::CanGc;
use crate::task::{TaskCanceller, TaskOnce};
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_source::TaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
enum WebSocketRequestState {
@ -72,7 +70,7 @@ mod close_code {
fn close_the_websocket_connection(
address: Trusted<WebSocket>,
task_source: &WebsocketTaskSource,
task_source: &TaskSource,
canceller: &TaskCanceller,
code: Option<u16>,
reason: String,
@ -88,7 +86,7 @@ fn close_the_websocket_connection(
fn fail_the_websocket_connection(
address: Trusted<WebSocket>,
task_source: &WebsocketTaskSource,
task_source: &TaskSource,
canceller: &TaskCanceller,
) {
let close_task = CloseTask {
@ -168,19 +166,12 @@ impl WebSocket {
if !self.clearing_buffer.get() && self.ready_state.get() == WebSocketRequestState::Open {
self.clearing_buffer.set(true);
let task = Box::new(BufferedAmountTask { address });
let pipeline_id = self.global().pipeline_id();
self.global()
.script_chan()
// TODO: Use a dedicated `websocket-task-source` task source instead.
.send(CommonScriptMsg::Task(
WebSocketEvent,
task,
Some(pipeline_id),
WebsocketTaskSource::NAME,
))
.unwrap();
// TODO(mrobinson): Should this task be cancellable?
let _ = self
.global()
.task_manager()
.websocket_task_source()
.queue_unconditionally(BufferedAmountTask { address });
}
Ok(true)
@ -284,8 +275,8 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
.core_resource_thread()
.send(CoreResourceMsg::Fetch(request, channels));
let task_source = global.websocket_task_source();
let canceller = global.task_canceller(WebsocketTaskSource::NAME);
let task_source = global.task_manager().websocket_task_source();
let canceller = global.task_canceller(TaskSourceName::WebSocket);
ROUTER.add_typed_route(
dom_event_receiver.to_ipc_receiver(),
Box::new(move |message| match message.unwrap() {
@ -451,11 +442,11 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
// TODO: use a dedicated task source,
// https://html.spec.whatwg.org/multipage/#websocket-task-source
// When making the switch, also update the task_canceller call.
let task_source = self.global().websocket_task_source();
let task_source = self.global().task_manager().websocket_task_source();
fail_the_websocket_connection(
address,
&task_source,
&self.global().task_canceller(WebsocketTaskSource::NAME),
&self.global().task_canceller(TaskSourceName::WebSocket),
);
},
WebSocketRequestState::Open => {

View file

@ -35,7 +35,6 @@ use crate::dom::fakexrinputcontroller::{init_to_mock_buttons, FakeXRInputControl
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::script_runtime::CanGc;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct FakeXRDevice {

View file

@ -68,7 +68,6 @@ use crate::dom::xrsessionevent::XRSessionEvent;
use crate::dom::xrspace::XRSpace;
use crate::realms::InRealm;
use crate::script_runtime::JSContext;
use crate::task_source::TaskSource;
use crate::script_runtime::CanGc;
#[dom_struct]

View file

@ -35,7 +35,6 @@ use crate::dom::xrtest::XRTest;
use crate::realms::InRealm;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct XRSystem {

View file

@ -28,7 +28,6 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::script_runtime::CanGc;
use crate::script_thread::ScriptThread;
use crate::task_source::TaskSource;
#[dom_struct]
pub struct XRTest {

View file

@ -158,7 +158,7 @@ use crate::script_runtime::{
};
use crate::script_thread::ScriptThread;
use crate::task_manager::TaskManager;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::task_source::TaskSourceName;
use crate::timers::{IsInterval, TimerCallback};
use crate::unminify::unminified_path;
use crate::webdriver_handlers::jsval_to_webdriver;

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::{RefCell, RefMut};
use std::cell::{OnceCell, RefCell, RefMut};
use std::default::Default;
use std::rc::Rc;
use std::sync::atomic::{AtomicBool, Ordering};
@ -44,7 +44,7 @@ use crate::dom::bindings::reflector::DomObject;
use crate::dom::bindings::root::{DomRoot, MutNullableDom};
use crate::dom::bindings::settings_stack::AutoEntryScript;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::bindings::trace::{CustomTraceable, RootedTraceableBox};
use crate::dom::crypto::Crypto;
use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use crate::dom::globalscope::GlobalScope;
@ -60,14 +60,7 @@ use crate::fetch;
use crate::realms::{enter_realm, InRealm};
use crate::script_runtime::{CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort};
use crate::task::TaskCanceller;
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
use crate::task_source::file_reading::FileReadingTaskSource;
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::performance_timeline::PerformanceTimelineTaskSource;
use crate::task_source::port_message::PortMessageQueue;
use crate::task_source::remote_event::RemoteEventTaskSource;
use crate::task_source::timer::TimerTaskSource;
use crate::task_source::websocket::WebsocketTaskSource;
use crate::task_manager::TaskManager;
use crate::timers::{IsInterval, TimerCallback};
pub fn prepare_workerscope_init(
@ -135,6 +128,9 @@ pub struct WorkerGlobalScope {
/// Timers are handled in the service worker event loop.
#[no_trace]
timer_scheduler: RefCell<TimerScheduler>,
/// A [`TaskManager`] for this [`WorkerGlobalScope`].
task_manager: OnceCell<TaskManager>,
}
impl WorkerGlobalScope {
@ -189,6 +185,7 @@ impl WorkerGlobalScope {
navigation_start: CrossProcessInstant::now(),
performance: Default::default(),
timer_scheduler: RefCell::default(),
task_manager: Default::default(),
}
}
@ -510,36 +507,9 @@ impl WorkerGlobalScope {
}
}
pub fn dom_manipulation_task_source(&self) -> DOMManipulationTaskSource {
DOMManipulationTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn file_reading_task_source(&self) -> FileReadingTaskSource {
FileReadingTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn networking_task_source(&self) -> NetworkingTaskSource {
NetworkingTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn performance_timeline_task_source(&self) -> PerformanceTimelineTaskSource {
PerformanceTimelineTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn port_message_queue(&self) -> PortMessageQueue {
PortMessageQueue(self.script_chan(), self.pipeline_id())
}
pub fn timer_task_source(&self) -> TimerTaskSource {
TimerTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn remote_event_task_source(&self) -> RemoteEventTaskSource {
RemoteEventTaskSource(self.script_chan(), self.pipeline_id())
}
pub fn websocket_task_source(&self) -> WebsocketTaskSource {
WebsocketTaskSource(self.script_chan(), self.pipeline_id())
pub(crate) fn task_manager(&self) -> &TaskManager {
self.task_manager
.get_or_init(|| TaskManager::new(self.script_chan(), self.pipeline_id()))
}
pub fn new_script_pair(&self) -> (Box<dyn ScriptChan + Send>, Box<dyn ScriptPort + Send>) {

View file

@ -73,7 +73,7 @@ use crate::dom::xmlhttprequestupload::XMLHttpRequestUpload;
use crate::fetch::FetchCanceller;
use crate::network_listener::{self, PreInvoke, ResourceTimingListener};
use crate::script_runtime::{CanGc, JSContext};
use crate::task_source::networking::NetworkingTaskSource;
use crate::task_source::{TaskSource, TaskSourceName};
use crate::timers::{OneshotTimerCallback, OneshotTimerHandle};
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
@ -294,7 +294,7 @@ impl XMLHttpRequest {
fn initiate_async_xhr(
context: Arc<Mutex<XHRContext>>,
task_source: NetworkingTaskSource,
task_source: TaskSource,
global: &GlobalScope,
init: RequestBuilder,
cancellation_chan: ipc::IpcReceiver<()>,
@ -1560,10 +1560,17 @@ impl XMLHttpRequest {
}));
let (task_source, script_port) = if self.sync.get() {
let (tx, rx) = global.new_script_pair();
(NetworkingTaskSource(tx, global.pipeline_id()), Some(rx))
let (sender, receiver) = global.new_script_pair();
(
TaskSource {
sender,
pipeline_id: global.pipeline_id(),
name: TaskSourceName::Networking,
},
Some(receiver),
)
} else {
(global.networking_task_source(), None)
(global.task_manager().networking_task_source(), None)
};
let cancel_receiver = self.canceller.borrow_mut().initialize();