From b2eda71952f32c0e486c72ed881f472e59ad37c0 Mon Sep 17 00:00:00 2001 From: Martin Robinson Date: Sat, 4 Jan 2025 09:41:50 +0100 Subject: [PATCH] script: Move `TaskManager` to `GlobalScope` (#34827) This is a simplification of the internal `TaskQueue` API that moves the `TaskManager` to the `GlobalScope` itself. In addition, the handling of cancellers is moved to the `TaskManager` as well. This means that no arguments other than the `task` are necessary for queueing tasks, which makes the API a lot easier to use and cleaner. `TaskSource` now also keeps a copy of the canceller with it, so that they always know the proper way to cancel any tasks queued on them. There is one complication here. The event loop `sender` for dedicated workers is constantly changing as it is set to `None` when not handling messages. This is because this sender keeps a handle to the main thread's `Worker` object, preventing garbage collection while any messages are still in flight or being handled. This change allows setting the `sender` on the `TaskManager` to `None` to allow proper garbabge collection. Signed-off-by: Martin Robinson --- components/script/body.rs | 22 +- components/script/dom/analysernode.rs | 15 +- components/script/dom/audiocontext.rs | 46 +-- .../script/dom/audioscheduledsourcenode.rs | 26 +- components/script/dom/audiotracklist.rs | 17 +- components/script/dom/baseaudiocontext.rs | 87 ++--- .../script/dom/dedicatedworkerglobalscope.rs | 40 ++- components/script/dom/document.rs | 233 +++++++------- components/script/dom/eventsource.rs | 6 - components/script/dom/filereader.rs | 22 +- .../script/dom/gamepadhapticactuator.rs | 42 +-- components/script/dom/globalscope.rs | 297 +++++++----------- components/script/dom/htmldetailselement.rs | 1 - components/script/dom/htmldialogelement.rs | 2 +- components/script/dom/htmlformelement.rs | 2 +- components/script/dom/htmlimageelement.rs | 68 ++-- components/script/dom/htmlinputelement.rs | 4 +- components/script/dom/htmlmediaelement.rs | 261 +++++++-------- components/script/dom/htmlscriptelement.rs | 13 +- components/script/dom/htmlstyleelement.rs | 5 +- components/script/dom/htmltextareaelement.rs | 4 +- components/script/dom/htmlvideoelement.rs | 7 +- components/script/dom/offlineaudiocontext.rs | 11 +- components/script/dom/performance.rs | 4 +- components/script/dom/rtcpeerconnection.rs | 216 +++++-------- components/script/dom/selection.rs | 7 +- .../script/dom/serviceworkercontainer.rs | 65 ++-- .../script/dom/serviceworkerglobalscope.rs | 4 +- components/script/dom/storage.rs | 38 +-- components/script/dom/subtlecrypto.rs | 285 ++++++++--------- components/script/dom/textcontrol.rs | 5 +- components/script/dom/texttracklist.rs | 46 ++- components/script/dom/videotracklist.rs | 17 +- components/script/dom/webglquery.rs | 6 +- components/script/dom/webglsync.rs | 12 +- components/script/dom/webgpu/gpu.rs | 13 +- components/script/dom/websocket.rs | 39 +-- components/script/dom/webxr/fakexrdevice.rs | 7 +- components/script/dom/webxr/xrsession.rs | 67 ++-- components/script/dom/webxr/xrsystem.rs | 33 +- components/script/dom/webxr/xrtest.rs | 24 +- components/script/dom/window.rs | 104 ++---- components/script/dom/worker.rs | 5 +- components/script/dom/workerglobalscope.rs | 46 +-- components/script/dom/xmlhttprequest.rs | 1 + components/script/image_listener.rs | 22 +- components/script/links.rs | 2 +- components/script/network_listener.rs | 13 +- components/script/script_module.rs | 7 +- components/script/script_runtime.rs | 8 +- components/script/script_thread.rs | 16 +- components/script/task.rs | 8 +- components/script/task_manager.rs | 194 +++++++----- components/script/task_source.rs | 31 +- 54 files changed, 1060 insertions(+), 1516 deletions(-) diff --git a/components/script/body.rs b/components/script/body.rs index 0d625ac1ff4..1475928c07e 100644 --- a/components/script/body.rs +++ b/components/script/body.rs @@ -40,8 +40,7 @@ use crate::dom::readablestream::{get_read_promise_bytes, get_read_promise_done, use crate::dom::urlsearchparams::URLSearchParams; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::script_runtime::{CanGc, JSContext}; -use crate::task::TaskCanceller; -use crate::task_source::{TaskSource, TaskSourceName}; +use crate::task_source::TaskSource; /// The Dom object, or ReadableStream, that is the source of a body. /// @@ -72,7 +71,6 @@ enum StopReading { struct TransmitBodyConnectHandler { stream: Trusted, task_source: TaskSource, - canceller: TaskCanceller, bytes_sender: Option>, control_sender: IpcSender, in_memory: Option>, @@ -84,7 +82,6 @@ impl TransmitBodyConnectHandler { pub fn new( stream: Trusted, task_source: TaskSource, - canceller: TaskCanceller, control_sender: IpcSender, in_memory: Option>, source: BodySource, @@ -92,7 +89,6 @@ impl TransmitBodyConnectHandler { TransmitBodyConnectHandler { stream, task_source, - canceller, bytes_sender: None, control_sender, in_memory, @@ -178,8 +174,9 @@ impl TransmitBodyConnectHandler { // If we're using an actual ReadableStream, acquire a reader for it. if self.source == BodySource::Null { let stream = self.stream.clone(); - let _ = self.task_source.queue_with_canceller( - task!(start_reading_request_body_stream: move || { + let _ = self + .task_source + .queue(task!(start_reading_request_body_stream: move || { // Step 1, Let body be request’s body. let rooted_stream = stream.root(); @@ -190,9 +187,7 @@ impl TransmitBodyConnectHandler { .expect("Couldn't acquire a reader for the body stream."); // Note: this algorithm continues when the first chunk is requested by `net`. - }), - &self.canceller, - ); + })); } } @@ -236,7 +231,7 @@ impl TransmitBodyConnectHandler { return; } - let _ = self.task_source.queue_with_canceller( + let _ = self.task_source.queue( task!(setup_native_body_promise_handler: move || { let rooted_stream = stream.root(); let global = rooted_stream.global(); @@ -265,8 +260,7 @@ impl TransmitBodyConnectHandler { let realm = enter_realm(&*global); let comp = InRealm::Entered(&realm); promise.append_native_handler(&handler, comp, CanGc::note()); - }), - &self.canceller, + }) ); } } @@ -379,7 +373,6 @@ impl ExtractedBody { let global = stream.global(); let task_source = global.task_manager().networking_task_source(); - let canceller = global.task_canceller(TaskSourceName::Networking); // In case of the data being in-memory, send everything in one chunk, by-passing SM. let in_memory = stream.get_in_memory_bytes(); @@ -392,7 +385,6 @@ impl ExtractedBody { let mut body_handler = TransmitBodyConnectHandler::new( trusted_stream, task_source, - canceller, chunk_request_sender.clone(), in_memory, source, diff --git a/components/script/dom/analysernode.rs b/components/script/dom/analysernode.rs index 263cf7737d4..bc9928ff4cf 100644 --- a/components/script/dom/analysernode.rs +++ b/components/script/dom/analysernode.rs @@ -110,22 +110,17 @@ impl AnalyserNode { ) -> Fallible> { let (node, recv) = AnalyserNode::new_inherited(window, context, options)?; let object = reflect_dom_object_with_proto(Box::new(node), window, proto, can_gc); - let (source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = window.task_manager().dom_manipulation_task_source(); let this = Trusted::new(&*object); ROUTER.add_typed_route( recv, Box::new(move |block| { let this = this.clone(); - let _ = source.queue_with_canceller( - task!(append_analysis_block: move || { - let this = this.root(); - this.push_block(block.unwrap()) - }), - &canceller, - ); + let _ = task_source.queue(task!(append_analysis_block: move || { + let this = this.root(); + this.push_block(block.unwrap()) + })); }), ); Ok(object) diff --git a/components/script/dom/audiocontext.rs b/components/script/dom/audiocontext.rs index a42809caae8..5ef4fd99bfc 100644 --- a/components/script/dom/audiocontext.rs +++ b/components/script/dom/audiocontext.rs @@ -157,8 +157,7 @@ impl AudioContextMethods for AudioContext { } // Steps 4 and 5. - let window = DomRoot::downcast::(self.global()).unwrap(); - let task_source = window.task_manager().dom_manipulation_task_source(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); match self.context.audio_context_impl().lock().unwrap().suspend() { Ok(_) => { @@ -172,27 +171,21 @@ impl AudioContextMethods for AudioContext { promise.resolve_native(&()); if base_context.State() != AudioContextState::Suspended { base_context.set_state_attribute(AudioContextState::Suspended); - let window = DomRoot::downcast::(context.global()).unwrap(); - window.task_manager().dom_manipulation_task_source().queue_simple_event( + context.global().task_manager().dom_manipulation_task_source().queue_simple_event( context.upcast(), atom!("statechange"), - &window - ); + ); } - }), - window.upcast(), + }) ); }, Err(_) => { // The spec does not define the error case and `suspend` should // never fail, but we handle the case here for completion. - let _ = task_source.queue( - task!(suspend_error: move || { - let promise = trusted_promise.root(); - promise.reject_error(Error::Type("Something went wrong".to_owned())); - }), - window.upcast(), - ); + let _ = task_source.queue(task!(suspend_error: move || { + let promise = trusted_promise.root(); + promise.reject_error(Error::Type("Something went wrong".to_owned())); + })); }, }; @@ -218,8 +211,7 @@ impl AudioContextMethods for AudioContext { } // Steps 4 and 5. - let window = DomRoot::downcast::(self.global()).unwrap(); - let task_source = window.task_manager().dom_manipulation_task_source(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); match self.context.audio_context_impl().lock().unwrap().close() { Ok(_) => { @@ -233,27 +225,21 @@ impl AudioContextMethods for AudioContext { promise.resolve_native(&()); if base_context.State() != AudioContextState::Closed { base_context.set_state_attribute(AudioContextState::Closed); - let window = DomRoot::downcast::(context.global()).unwrap(); - window.task_manager().dom_manipulation_task_source().queue_simple_event( + context.global().task_manager().dom_manipulation_task_source().queue_simple_event( context.upcast(), atom!("statechange"), - &window - ); + ); } - }), - window.upcast(), + }) ); }, Err(_) => { // The spec does not define the error case and `suspend` should // never fail, but we handle the case here for completion. - let _ = task_source.queue( - task!(suspend_error: move || { - let promise = trusted_promise.root(); - promise.reject_error(Error::Type("Something went wrong".to_owned())); - }), - window.upcast(), - ); + let _ = task_source.queue(task!(suspend_error: move || { + let promise = trusted_promise.root(); + promise.reject_error(Error::Type("Something went wrong".to_owned())); + })); }, }; diff --git a/components/script/dom/audioscheduledsourcenode.rs b/components/script/dom/audioscheduledsourcenode.rs index 26a5002ce47..091e2efc7d2 100644 --- a/components/script/dom/audioscheduledsourcenode.rs +++ b/components/script/dom/audioscheduledsourcenode.rs @@ -71,25 +71,15 @@ impl AudioScheduledSourceNodeMethods for AudioScheduledSou } let this = Trusted::new(self); - let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let callback = OnEndedCallback::new(move || { - let _ = task_source.queue_with_canceller( - task!(ended: move || { - let this = this.root(); - let global = this.global(); - let window = global.as_window(); - window.task_manager().dom_manipulation_task_source().queue_simple_event( - this.upcast(), - atom!("ended"), - window - ); - }), - &canceller, - ); + let _ = task_source.queue(task!(ended: move || { + let this = this.root(); + this.global().task_manager().dom_manipulation_task_source().queue_simple_event( + this.upcast(), + atom!("ended"), + ); + })); }); self.node() diff --git a/components/script/dom/audiotracklist.rs b/components/script/dom/audiotracklist.rs index 19dba0fee3c..e7fd06ba513 100644 --- a/components/script/dom/audiotracklist.rs +++ b/components/script/dom/audiotracklist.rs @@ -89,18 +89,11 @@ impl AudioTrackList { // Queue a task to fire an event named change. let global = &self.global(); let this = Trusted::new(self); - let (source, canceller) = global - .as_window() - .task_manager() - .media_element_task_source_with_canceller(); - - let _ = source.queue_with_canceller( - task!(media_track_change: move || { - let this = this.root(); - this.upcast::().fire_event(atom!("change"), CanGc::note()); - }), - &canceller, - ); + let task_source = global.task_manager().media_element_task_source(); + let _ = task_source.queue(task!(media_track_change: move || { + let this = this.root(); + this.upcast::().fire_event(atom!("change"), CanGc::note()); + })); } pub fn add(&self, track: &AudioTrack) { diff --git a/components/script/dom/baseaudiocontext.rs b/components/script/dom/baseaudiocontext.rs index 1da48d4b1c8..8c349b59a21 100644 --- a/components/script/dom/baseaudiocontext.rs +++ b/components/script/dom/baseaudiocontext.rs @@ -65,7 +65,6 @@ use crate::dom::oscillatornode::OscillatorNode; use crate::dom::pannernode::PannerNode; use crate::dom::promise::Promise; use crate::dom::stereopannernode::StereoPannerNode; -use crate::dom::window::Window; use crate::realms::InRealm; use crate::script_runtime::CanGc; @@ -230,9 +229,7 @@ impl BaseAudioContext { } pub fn resume(&self) { - let global = self.global(); - let window = global.as_window(); - let task_source = window.task_manager().dom_manipulation_task_source(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); // Set the rendering thread state to 'running' and start // rendering the audio graph. @@ -245,28 +242,22 @@ impl BaseAudioContext { this.fulfill_in_flight_resume_promises(|| { if this.state.get() != AudioContextState::Running { this.state.set(AudioContextState::Running); - let window = DomRoot::downcast::(this.global()).unwrap(); - window.task_manager().dom_manipulation_task_source().queue_simple_event( + this.global().task_manager().dom_manipulation_task_source().queue_simple_event( this.upcast(), atom!("statechange"), - &window ); } }); - }), - window.upcast(), + }) ); }, Err(()) => { self.take_pending_resume_promises(Err(Error::Type( "Something went wrong".to_owned(), ))); - let _ = task_source.queue( - task!(resume_error: move || { - this.root().fulfill_in_flight_resume_promises(|| {}) - }), - window.upcast(), - ); + let _ = task_source.queue(task!(resume_error: move || { + this.root().fulfill_in_flight_resume_promises(|| {}) + })); }, } } @@ -485,8 +476,6 @@ impl BaseAudioContextMethods for BaseAudioContext { ) -> Rc { // Step 1. let promise = Promise::new_in_current_realm(comp, can_gc); - let global = self.global(); - let window = global.as_window(); if audio_data.len() > 0 { // Step 2. @@ -512,12 +501,8 @@ impl BaseAudioContextMethods for BaseAudioContext { let channels = Arc::new(Mutex::new(HashMap::new())); let this = Trusted::new(self); let this_ = this.clone(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); - let (task_source_, canceller_) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); + let task_source_clone = task_source.clone(); let callbacks = AudioDecoderCallbacks::new() .ready(move |channel_count| { decoded_audio @@ -538,36 +523,32 @@ impl BaseAudioContextMethods for BaseAudioContext { decoded_audio[channel].extend_from_slice((*buffer).as_ref()); }) .eos(move || { - let _ = task_source.queue_with_canceller( - task!(audio_decode_eos: move || { - let this = this.root(); - let decoded_audio = decoded_audio__.lock().unwrap(); - let length = if decoded_audio.len() >= 1 { - decoded_audio[0].len() - } else { - 0 - }; - let buffer = AudioBuffer::new( - this.global().as_window(), - decoded_audio.len() as u32 /* number of channels */, - length as u32, - this.sample_rate, - Some(decoded_audio.as_slice()), - CanGc::note()); - let mut resolvers = this.decode_resolvers.borrow_mut(); - assert!(resolvers.contains_key(&uuid_)); - let resolver = resolvers.remove(&uuid_).unwrap(); - if let Some(callback) = resolver.success_callback { - let _ = callback.Call__(&buffer, ExceptionHandling::Report); - } - resolver.promise.resolve_native(&buffer); - }), - &canceller, - ); + let _ = task_source.queue(task!(audio_decode_eos: move || { + let this = this.root(); + let decoded_audio = decoded_audio__.lock().unwrap(); + let length = if decoded_audio.len() >= 1 { + decoded_audio[0].len() + } else { + 0 + }; + let buffer = AudioBuffer::new( + this.global().as_window(), + decoded_audio.len() as u32 /* number of channels */, + length as u32, + this.sample_rate, + Some(decoded_audio.as_slice()), + CanGc::note()); + let mut resolvers = this.decode_resolvers.borrow_mut(); + assert!(resolvers.contains_key(&uuid_)); + let resolver = resolvers.remove(&uuid_).unwrap(); + if let Some(callback) = resolver.success_callback { + let _ = callback.Call__(&buffer, ExceptionHandling::Report); + } + resolver.promise.resolve_native(&buffer); + })); }) .error(move |error| { - let _ = task_source_.queue_with_canceller( - task!(audio_decode_eos: move || { + let _ = task_source_clone.queue(task!(audio_decode_eos: move || { let this = this_.root(); let mut resolvers = this.decode_resolvers.borrow_mut(); assert!(resolvers.contains_key(&uuid)); @@ -579,9 +560,7 @@ impl BaseAudioContextMethods for BaseAudioContext { } let error = format!("Audio decode error {:?}", error); resolver.promise.reject_error(Error::Type(error)); - }), - &canceller_, - ); + })); }) .build(); self.audio_context_impl diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index 45684477b84..ad750ee1edc 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -2,7 +2,6 @@ * 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::mem::replace; use std::sync::atomic::AtomicBool; use std::sync::Arc; use std::thread::{self, JoinHandle}; @@ -76,9 +75,10 @@ impl<'a> AutoWorkerReset<'a> { workerscope: &'a DedicatedWorkerGlobalScope, worker: TrustedWorkerAddress, ) -> AutoWorkerReset<'a> { + let old_worker = workerscope.replace_worker(Some(worker)); AutoWorkerReset { workerscope, - old_worker: replace(&mut *workerscope.worker.borrow_mut(), Some(worker)), + old_worker, } } } @@ -86,9 +86,7 @@ impl<'a> AutoWorkerReset<'a> { impl Drop for AutoWorkerReset<'_> { fn drop(&mut self) { self.workerscope - .worker - .borrow_mut() - .clone_from(&self.old_worker) + .replace_worker(std::mem::take(&mut self.old_worker)); } } @@ -387,6 +385,7 @@ impl DedicatedWorkerGlobalScope { }), pipeline_id, name: TaskSourceName::Networking, + canceller: Default::default(), }; Runtime::new_with_parent(Some(parent), Some(task_source)) }; @@ -501,15 +500,38 @@ impl DedicatedWorkerGlobalScope { .expect("Thread spawning failed") } + /// The non-None value of the `worker` field can contain a rooted [`TrustedWorkerAddress`] + /// version of the main thread's worker object. This is set while handling messages and then + /// unset otherwise, ensuring that the main thread object can be garbage collected. See + /// [`AutoWorkerReset`]. + fn replace_worker( + &self, + new_worker: Option, + ) -> Option { + let old_worker = std::mem::replace(&mut *self.worker.borrow_mut(), new_worker); + + // The `TaskManager` maintains a handle to this `DedicatedWorkerGlobalScope`'s + // event_loop_sender, which might in turn have a `TrustedWorkerAddress` rooting of the main + // thread's worker, which prevents garbage collection. Resetting it here ensures that + // garbage collection of the main thread object can happen again (assuming the new `worker` + // is `None`). + self.upcast::() + .task_manager() + .set_sender(self.event_loop_sender()); + + old_worker + } + pub fn image_cache(&self) -> Arc { self.image_cache.clone() } - pub fn script_chan(&self) -> Box { - Box::new(WorkerThreadWorkerChan { + pub(crate) fn event_loop_sender(&self) -> Option> { + let worker = self.worker.borrow().clone()?; + Some(Box::new(WorkerThreadWorkerChan { sender: self.own_sender.clone(), - worker: self.worker.borrow().as_ref().unwrap().clone(), - }) + worker, + })) } pub fn new_script_pair(&self) -> (Box, Box) { diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index c4614c00a53..4cdc6b4e641 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -696,37 +696,34 @@ impl Document { // But it's now Step 4 in https://html.spec.whatwg.org/multipage/#reactivate-a-document // TODO: See #32687 for more information. let document = Trusted::new(self); - self.window + self.window() .task_manager() .dom_manipulation_task_source() - .queue( - task!(fire_pageshow_event: move || { - let document = document.root(); - let window = document.window(); - // Step 4.6.1 - if document.page_showing.get() { - return; - } - // Step 4.6.2 Set document's page showing flag to true. - document.page_showing.set(true); - // Step 4.6.3 Update the visibility state of document to "visible". - document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note()); - // Step 4.6.4 Fire a page transition event named pageshow at document's relevant - // global object with true. - let event = PageTransitionEvent::new( - window, - atom!("pageshow"), - false, // bubbles - false, // cancelable - true, // persisted - CanGc::note(), - ); - let event = event.upcast::(); - event.set_trusted(true); - window.dispatch_event_with_target_override(event, CanGc::note()); - }), - self.window.upcast(), - ) + .queue(task!(fire_pageshow_event: move || { + let document = document.root(); + let window = document.window(); + // Step 4.6.1 + if document.page_showing.get() { + return; + } + // Step 4.6.2 Set document's page showing flag to true. + document.page_showing.set(true); + // Step 4.6.3 Update the visibility state of document to "visible". + document.update_visibility_state(DocumentVisibilityState::Visible, CanGc::note()); + // Step 4.6.4 Fire a page transition event named pageshow at document's relevant + // global object with true. + let event = PageTransitionEvent::new( + window, + atom!("pageshow"), + false, // bubbles + false, // cancelable + true, // persisted + CanGc::note(), + ); + let event = event.upcast::(); + event.set_trusted(true); + window.dispatch_event_with_target_override(event, CanGc::note()); + })) .unwrap(); } @@ -2129,14 +2126,9 @@ impl Document { request: RequestBuilder, listener: Listener, ) { - let (task_source, canceller) = self - .window() - .task_manager() - .networking_task_source_with_canceller(); let callback = NetworkListener { context: std::sync::Arc::new(Mutex::new(listener)), - task_source, - canceller: Some(canceller), + task_source: self.window().task_manager().networking_task_source(), } .into_callback(); self.loader_mut() @@ -2149,14 +2141,9 @@ impl Document { listener: Listener, cancel_override: Option>, ) { - let (task_source, canceller) = self - .window() - .task_manager() - .networking_task_source_with_canceller(); let callback = NetworkListener { context: std::sync::Arc::new(Mutex::new(listener)), - task_source, - canceller: Some(canceller), + task_source: self.window().task_manager().networking_task_source(), } .into_callback(); self.loader_mut() @@ -2384,81 +2371,75 @@ impl Document { // Step 7. debug!("Document loads are complete."); let document = Trusted::new(self); - self.window + self.window() .task_manager() .dom_manipulation_task_source() - .queue( - task!(fire_load_event: move || { - let document = document.root(); - let window = document.window(); - if !window.is_alive() { - return; - } + .queue(task!(fire_load_event: move || { + let document = document.root(); + let window = document.window(); + if !window.is_alive() { + return; + } - // Step 7.1. - document.set_ready_state(DocumentReadyState::Complete, CanGc::note()); + // Step 7.1. + document.set_ready_state(DocumentReadyState::Complete, CanGc::note()); - // Step 7.2. - if document.browsing_context().is_none() { - return; - } - let event = Event::new( - window.upcast(), - atom!("load"), - EventBubbles::DoesNotBubble, - EventCancelable::NotCancelable, - CanGc::note(), - ); - event.set_trusted(true); + // Step 7.2. + if document.browsing_context().is_none() { + return; + } + let event = Event::new( + window.upcast(), + atom!("load"), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable, + CanGc::note(), + ); + event.set_trusted(true); - // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart - update_with_current_instant(&document.load_event_start); + // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventStart + update_with_current_instant(&document.load_event_start); - debug!("About to dispatch load for {:?}", document.url()); - window.dispatch_event_with_target_override(&event, CanGc::note()); + debug!("About to dispatch load for {:?}", document.url()); + window.dispatch_event_with_target_override(&event, CanGc::note()); - // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd - update_with_current_instant(&document.load_event_end); + // http://w3c.github.io/navigation-timing/#widl-PerformanceNavigationTiming-loadEventEnd + update_with_current_instant(&document.load_event_end); - if let Some(fragment) = document.url().fragment() { - document.check_and_scroll_fragment(fragment, CanGc::note()); - } - }), - self.window.upcast(), - ) + if let Some(fragment) = document.url().fragment() { + document.check_and_scroll_fragment(fragment, CanGc::note()); + } + })) .unwrap(); // Step 8. let document = Trusted::new(self); if document.root().browsing_context().is_some() { - self.window + self.window() .task_manager() .dom_manipulation_task_source() - .queue( - task!(fire_pageshow_event: move || { - let document = document.root(); - let window = document.window(); - if document.page_showing.get() || !window.is_alive() { - return; - } + .queue(task!(fire_pageshow_event: move || { + let document = document.root(); + let window = document.window(); + if document.page_showing.get() || !window.is_alive() { + return; + } - document.page_showing.set(true); + document.page_showing.set(true); - let event = PageTransitionEvent::new( - window, - atom!("pageshow"), - false, // bubbles - false, // cancelable - false, // persisted - CanGc::note(), - ); - let event = event.upcast::(); - event.set_trusted(true); + let event = PageTransitionEvent::new( + window, + atom!("pageshow"), + false, // bubbles + false, // cancelable + false, // persisted + CanGc::note(), + ); + let event = event.upcast::(); + event.set_trusted(true); - window.dispatch_event_with_target_override(event, CanGc::note()); - }), - self.window.upcast(), - ) + window.dispatch_event_with_target_override(event, CanGc::note()); + })) .unwrap(); } @@ -2486,32 +2467,29 @@ impl Document { // TODO: fully implement "completely loaded". let document = Trusted::new(self); if document.root().browsing_context().is_some() { - self.window + self.window() .task_manager() .dom_manipulation_task_source() - .queue( - task!(completely_loaded: move || { - let document = document.root(); - document.completely_loaded.set(true); - if let Some(DeclarativeRefresh::PendingLoad { - url, - time - }) = &*document.declarative_refresh.borrow() { - // https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps - document.window.upcast::().schedule_callback( - OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue { - window: DomRoot::from_ref(document.window()), - url: url.clone(), - }), - Duration::from_secs(*time), - ); - } - // Note: this will, among others, result in the "iframe-load-event-steps" being run. - // https://html.spec.whatwg.org/multipage/#iframe-load-event-steps - document.notify_constellation_load(); - }), - self.window.upcast(), - ) + .queue(task!(completely_loaded: move || { + let document = document.root(); + document.completely_loaded.set(true); + if let Some(DeclarativeRefresh::PendingLoad { + url, + time + }) = &*document.declarative_refresh.borrow() { + // https://html.spec.whatwg.org/multipage/#shared-declarative-refresh-steps + document.window.upcast::().schedule_callback( + OneshotTimerCallback::RefreshRedirectDue(RefreshRedirectDue { + window: DomRoot::from_ref(document.window()), + url: url.clone(), + }), + Duration::from_secs(*time), + ); + } + // Note: this will, among others, result in the "iframe-load-event-steps" being run. + // https://html.spec.whatwg.org/multipage/#iframe-load-event-steps + document.notify_constellation_load(); + })) .unwrap(); } } @@ -2657,9 +2635,8 @@ impl Document { update_with_current_instant(&self.dom_content_loaded_event_start); // Step 4.1. - let window = self.window(); let document = Trusted::new(self); - window + self.window() .task_manager() .dom_manipulation_task_source() .queue( @@ -2667,8 +2644,7 @@ impl Document { let document = document.root(); document.upcast::().fire_bubbling_event(atom!("DOMContentLoaded"), CanGc::note()); update_with_current_instant(&document.dom_content_loaded_event_end); - }), - window.upcast(), + }) ) .unwrap(); @@ -2713,8 +2689,9 @@ impl Document { // Note: the spec says to discard any tasks queued for fetch. // This cancels all tasks on the networking task source, which might be too broad. // See https://github.com/whatwg/html/issues/3837 - self.window - .cancel_all_tasks_from_source(TaskSourceName::Networking); + self.window() + .task_manager() + .cancel_pending_tasks_for_source(TaskSourceName::Networking); // Step 3. if let Some(parser) = self.get_current_parser() { diff --git a/components/script/dom/eventsource.rs b/components/script/dom/eventsource.rs index a64c5be8088..40309ba50ed 100644 --- a/components/script/dom/eventsource.rs +++ b/components/script/dom/eventsource.rs @@ -45,7 +45,6 @@ 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::TaskSourceName; use crate::timers::OneshotTimerCallback; const DEFAULT_RECONNECTION_TIME: Duration = Duration::from_millis(5000); @@ -121,7 +120,6 @@ impl EventSourceContext { event_source.upcast::().fire_event(atom!("open"), CanGc::note()); } }), - &global, ); } @@ -177,7 +175,6 @@ impl EventSourceContext { // FIXME(nox): Why are errors silenced here? let _ = event_source.global().schedule_callback(callback, duration); }), - &global, ); } @@ -266,7 +263,6 @@ impl EventSourceContext { event.root().upcast::().fire(event_source.upcast(), CanGc::note()); } }), - &global, ); } @@ -508,7 +504,6 @@ impl EventSource { event_source.upcast::().fire_event(atom!("error"), CanGc::note()); } }), - &global, ); } @@ -606,7 +601,6 @@ impl EventSourceMethods for EventSource { let listener = NetworkListener { context: Arc::new(Mutex::new(context)), task_source: global.task_manager().networking_task_source(), - canceller: Some(global.task_canceller(TaskSourceName::Networking)), }; ROUTER.add_typed_route( action_receiver, diff --git a/components/script/dom/filereader.rs b/components/script/dom/filereader.rs index ad21a11f639..55637105058 100644 --- a/components/script/dom/filereader.rs +++ b/components/script/dom/filereader.rs @@ -37,7 +37,6 @@ use crate::dom::progressevent::ProgressEvent; use crate::realms::enter_realm; use crate::script_runtime::{CanGc, JSContext}; use crate::task::TaskOnce; -use crate::task_source::TaskSourceName; #[allow(dead_code)] pub enum FileReadingTask { @@ -503,20 +502,27 @@ impl FileReader { let filereader = Trusted::new(self); let global = self.global(); - let canceller = global.task_canceller(TaskSourceName::FileReading); let task_source = global.task_manager().file_reading_task_source(); // Queue tasks as appropriate. - let task = FileReadingTask::ProcessRead(filereader.clone(), gen_id); - task_source.queue_with_canceller(task, &canceller).unwrap(); + task_source + .queue(FileReadingTask::ProcessRead(filereader.clone(), gen_id)) + .unwrap(); if !blob_contents.is_empty() { - let task = FileReadingTask::ProcessReadData(filereader.clone(), gen_id); - task_source.queue_with_canceller(task, &canceller).unwrap(); + task_source + .queue(FileReadingTask::ProcessReadData(filereader.clone(), gen_id)) + .unwrap(); } - let task = FileReadingTask::ProcessReadEOF(filereader, gen_id, load_data, blob_contents); - task_source.queue_with_canceller(task, &canceller).unwrap(); + task_source + .queue(FileReadingTask::ProcessReadEOF( + filereader, + gen_id, + load_data, + blob_contents, + )) + .unwrap(); Ok(()) } diff --git a/components/script/dom/gamepadhapticactuator.rs b/components/script/dom/gamepadhapticactuator.rs index 6892092a9a5..909d60a83f9 100644 --- a/components/script/dom/gamepadhapticactuator.rs +++ b/components/script/dom/gamepadhapticactuator.rs @@ -27,11 +27,9 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; use crate::realms::InRealm; use crate::script_runtime::{CanGc, JSContext}; -use crate::task::TaskCanceller; -use crate::task_source::{TaskSource, TaskSourceName}; +use crate::task_source::TaskSource; struct HapticEffectListener { - canceller: TaskCanceller, task_source: TaskSource, context: Trusted, } @@ -39,24 +37,22 @@ struct HapticEffectListener { impl HapticEffectListener { fn handle_stopped(&self, stopped_successfully: bool) { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( - task!(handle_haptic_effect_stopped: move || { + let _ = self + .task_source + .queue(task!(handle_haptic_effect_stopped: move || { let actuator = context.root(); actuator.handle_haptic_effect_stopped(stopped_successfully); - }), - &self.canceller, - ); + })); } fn handle_completed(&self, completed_successfully: bool) { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( - task!(handle_haptic_effect_completed: move || { + let _ = self + .task_source + .queue(task!(handle_haptic_effect_completed: move || { let actuator = context.root(); actuator.handle_haptic_effect_completed(completed_successfully); - }), - &self.canceller, - ); + })); } } @@ -204,7 +200,6 @@ impl GamepadHapticActuatorMethods for GamepadHapticActuato let message = DOMString::from("preempted"); promise.resolve_native(&message); }), - &self.global(), ); } @@ -219,13 +214,8 @@ impl GamepadHapticActuatorMethods for GamepadHapticActuato let context = Trusted::new(self); let (effect_complete_sender, effect_complete_receiver) = ipc::channel().expect("ipc channel failure"); - let (task_source, canceller) = ( - self.global().task_manager().gamepad_task_source(), - self.global().task_canceller(TaskSourceName::Gamepad), - ); let listener = HapticEffectListener { - canceller, - task_source, + task_source: self.global().task_manager().gamepad_task_source(), context, }; @@ -277,7 +267,6 @@ impl GamepadHapticActuatorMethods for GamepadHapticActuato let message = DOMString::from("preempted"); promise.resolve_native(&message); }), - &self.global(), ); } @@ -288,13 +277,8 @@ impl GamepadHapticActuatorMethods for GamepadHapticActuato let context = Trusted::new(self); let (effect_stop_sender, effect_stop_receiver) = ipc::channel().expect("ipc channel failure"); - let (task_source, canceller) = ( - self.global().task_manager().gamepad_task_source(), - self.global().task_canceller(TaskSourceName::Gamepad), - ); let listener = HapticEffectListener { - canceller, - task_source, + task_source: self.global().task_manager().gamepad_task_source(), context, }; @@ -350,8 +334,7 @@ impl GamepadHapticActuator { let promise = trusted_promise.root(); let message = DOMString::from("complete"); promise.resolve_native(&message); - }), - &self.global(), + }) ); } } @@ -372,7 +355,6 @@ impl GamepadHapticActuator { let message = DOMString::from("preempted"); promise.resolve_native(&message); }), - &self.global(), ); let (send, _rcv) = ipc::channel().expect("ipc channel failure"); diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 632f75c8405..87e7a5ffc1c 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -70,6 +70,7 @@ use super::bindings::codegen::Bindings::MessagePortBinding::StructuredSerializeO use super::bindings::codegen::Bindings::WebGPUBinding::GPUDeviceLostReason; use super::bindings::error::Fallible; use super::bindings::trace::{HashMapTracedValues, RootedTraceableBox}; +use super::serviceworkerglobalscope::ServiceWorkerGlobalScope; use crate::dom::bindings::cell::{DomRefCell, RefMut}; use crate::dom::bindings::codegen::Bindings::BroadcastChannelBinding::BroadcastChannelMethods; use crate::dom::bindings::codegen::Bindings::EventSourceBinding::EventSource_Binding::EventSourceMethods; @@ -127,7 +128,6 @@ use crate::dom::webgpu::identityhub::IdentityHub; use crate::dom::window::Window; use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::dom::workletglobalscope::WorkletGlobalScope; -use crate::messaging::MainThreadScriptChan; use crate::microtask::{Microtask, MicrotaskQueue, UserMicrotask}; use crate::network_listener::{NetworkListener, PreInvoke}; use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; @@ -137,9 +137,8 @@ use crate::script_runtime::{ }; use crate::script_thread::{with_script_thread, ScriptThread}; use crate::security_manager::CSPViolationReporter; -use crate::task::TaskCanceller; use crate::task_manager::TaskManager; -use crate::task_source::{TaskSource, TaskSourceName}; +use crate::task_source::TaskSource; use crate::timers::{ IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback, }; @@ -195,6 +194,9 @@ pub struct GlobalScope { eventtarget: EventTarget, crypto: MutNullableDom, + /// A [`TaskManager`] for this [`GlobalScope`]. + task_manager: OnceCell, + /// The message-port router id for this global, if it is managing ports. message_port_state: DomRefCell, @@ -374,14 +376,12 @@ pub struct GlobalScope { /// A wrapper for glue-code between the ipc router and the event-loop. struct MessageListener { - canceller: TaskCanceller, task_source: TaskSource, context: Trusted, } /// A wrapper for broadcasts coming in over IPC, and the event-loop. struct BroadcastListener { - canceller: TaskCanceller, task_source: TaskSource, context: Trusted, } @@ -389,7 +389,6 @@ struct BroadcastListener { /// A wrapper between timer events coming in over IPC, and the event-loop. #[derive(Clone)] pub(crate) struct TimerListener { - canceller: TaskCanceller, task_source: TaskSource, context: Trusted, } @@ -403,7 +402,6 @@ struct FileListener { /// - Some(Empty) => None state: Option, task_source: TaskSource, - task_canceller: TaskCanceller, } enum FileListenerTarget { @@ -516,15 +514,14 @@ impl BroadcastListener { // This however seems to be hard to avoid in the light of the IPC. // One can imagine queueing tasks directly, // for channels that would be in the same script-thread. - let _ = self.task_source.queue_with_canceller( - task!(broadcast_message_event: move || { + let _ = self + .task_source + .queue(task!(broadcast_message_event: move || { let global = context.root(); // Step 10 of https://html.spec.whatwg.org/multipage/#dom-broadcastchannel-postmessage, // For each BroadcastChannel object destination in destinations, queue a task. global.broadcast_message_event(event, None); - }), - &self.canceller, - ); + })); } } @@ -535,7 +532,7 @@ impl TimerListener { let context = self.context.clone(); // Step 18, queue a task, // https://html.spec.whatwg.org/multipage/#timer-initialisation-steps - let _ = self.task_source.queue_with_canceller( + let _ = self.task_source.queue( task!(timer_event: move || { let global = context.root(); let TimerEvent(source, id) = event; @@ -550,8 +547,7 @@ impl TimerListener { }; // Step 7, substeps run in a task. global.fire_timer(id, CanGc::note()); - }), - &self.canceller, + }) ); } @@ -568,7 +564,7 @@ impl MessageListener { match msg { MessagePortMsg::CompleteTransfer(ports) => { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( + let _ = self.task_source.queue( task!(process_complete_transfer: move || { let global = context.root(); @@ -598,39 +594,31 @@ impl MessageListener { let _ = global.script_to_constellation_chan().send( ScriptMsg::MessagePortTransferResult(Some(router_id), succeeded, failed), ); - }), - &self.canceller, + }) ); }, MessagePortMsg::CompletePendingTransfer(port_id, buffer) => { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( - task!(complete_pending: move || { - let global = context.root(); - global.complete_port_transfer(port_id, buffer); - }), - &self.canceller, - ); + let _ = self.task_source.queue(task!(complete_pending: move || { + let global = context.root(); + global.complete_port_transfer(port_id, buffer); + })); }, MessagePortMsg::NewTask(port_id, task) => { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( - task!(process_new_task: move || { - let global = context.root(); - global.route_task_to_port(port_id, task, CanGc::note()); - }), - &self.canceller, - ); + let _ = self.task_source.queue(task!(process_new_task: move || { + let global = context.root(); + global.route_task_to_port(port_id, task, CanGc::note()); + })); }, MessagePortMsg::RemoveMessagePort(port_id) => { let context = self.context.clone(); - let _ = self.task_source.queue_with_canceller( - task!(process_remove_message_port: move || { + let _ = self + .task_source + .queue(task!(process_remove_message_port: move || { let global = context.root(); global.note_entangled_port_removed(&port_id); - }), - &self.canceller, - ); + })); }, } } @@ -665,10 +653,8 @@ impl FileListener { let stream = trusted.root(); stream_handle_incoming(&stream, Ok(blob_buf.bytes)); }); + let _ = self.task_source.queue(task); - let _ = self - .task_source - .queue_with_canceller(task, &self.task_canceller); Vec::with_capacity(0) } else { blob_buf.bytes @@ -690,9 +676,7 @@ impl FileListener { stream_handle_incoming(&stream, Ok(bytes_in)); }); - let _ = self - .task_source - .queue_with_canceller(task, &self.task_canceller); + let _ = self.task_source.queue(task); } else { bytes.append(&mut bytes_in); }; @@ -712,9 +696,7 @@ impl FileListener { callback(promise, Ok(bytes)); }); - let _ = self - .task_source - .queue_with_canceller(task, &self.task_canceller); + let _ = self.task_source.queue(task); }, FileListenerTarget::Stream(trusted_stream) => { let trusted = trusted_stream.clone(); @@ -724,9 +706,7 @@ impl FileListener { stream_handle_eof(&stream); }); - let _ = self - .task_source - .queue_with_canceller(task, &self.task_canceller); + let _ = self.task_source.queue(task); }, }, _ => { @@ -740,23 +720,17 @@ impl FileListener { match target { FileListenerTarget::Promise(trusted_promise, callback) => { - let _ = self.task_source.queue_with_canceller( - task!(reject_promise: move || { - let promise = trusted_promise.root(); - let _ac = enter_realm(&*promise.global()); - callback(promise, error); - }), - &self.task_canceller, - ); + let _ = self.task_source.queue(task!(reject_promise: move || { + let promise = trusted_promise.root(); + let _ac = enter_realm(&*promise.global()); + callback(promise, error); + })); }, FileListenerTarget::Stream(trusted_stream) => { - let _ = self.task_source.queue_with_canceller( - task!(error_stream: move || { - let stream = trusted_stream.root(); - stream_handle_incoming(&stream, error); - }), - &self.task_canceller, - ); + let _ = self.task_source.queue(task!(error_stream: move || { + let stream = trusted_stream.root(); + stream_handle_incoming(&stream, error); + })); }, } }, @@ -785,6 +759,7 @@ impl GlobalScope { unminify_js: bool, ) -> Self { Self { + task_manager: Default::default(), message_port_state: DomRefCell::new(MessagePortState::UnManaged), broadcast_channel_state: DomRefCell::new(BroadcastChannelState::UnManaged), blob_state: DomRefCell::new(BlobState::UnManaged), @@ -851,16 +826,11 @@ impl GlobalScope { fn timers(&self) -> &OneshotTimers { self.timers.get_or_init(|| { - let (task_source, canceller) = ( - self.task_manager().timer_task_source(), - self.task_canceller(TaskSourceName::Timer), - ); OneshotTimers::new( self, TimerListener { context: Trusted::new(self), - task_source, - canceller, + task_source: self.task_manager().timer_task_source(), }, ) }) @@ -1099,7 +1069,6 @@ impl GlobalScope { let target_global = this.root(); target_global.route_task_to_port(port_id, task, CanGc::note()); }), - self, ); } } @@ -1148,15 +1117,15 @@ impl GlobalScope { if let Some(entangled_id) = entangled_port { // Step 7 let this = Trusted::new(self); - 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 - // are aware of any transfer that might still take place in the current task. - global.route_task_to_port(entangled_id, task, CanGc::note()); - }), - self, - ); + 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 + // are aware of any transfer that might still take place in the current task. + global.route_task_to_port(entangled_id, task, CanGc::note()); + })); } } else { warn!("post_messageport_msg called on a global not managing any ports."); @@ -1273,8 +1242,7 @@ impl GlobalScope { // Step 10.3, fire an event named messageerror at destination. MessageEvent::dispatch_error(destination.upcast(), &global, CanGc::note()); } - }), - self, + }) ); }); } @@ -1438,13 +1406,8 @@ impl GlobalScope { let (broadcast_control_sender, broadcast_control_receiver) = ipc::channel().expect("ipc channel failure"); let context = Trusted::new(self); - let (task_source, canceller) = ( - self.task_manager().dom_manipulation_task_source(), - self.task_canceller(TaskSourceName::DOMManipulation), - ); let listener = BroadcastListener { - canceller, - task_source, + task_source: self.task_manager().dom_manipulation_task_source(), context, }; ROUTER.add_typed_route( @@ -1491,13 +1454,8 @@ impl GlobalScope { let (port_control_sender, port_control_receiver) = ipc::channel().expect("ipc channel failure"); let context = Trusted::new(self); - let (task_source, canceller) = ( - self.task_manager().port_message_queue(), - self.task_canceller(TaskSourceName::PortMessage), - ); let listener = MessageListener { - canceller, - task_source, + task_source: self.task_manager().port_message_queue(), context, }; ROUTER.add_typed_route( @@ -1540,7 +1498,6 @@ impl GlobalScope { let target_global = this.root(); target_global.maybe_add_pending_ports(); }), - self, ); } else { // If this is a newly-created port, let the constellation immediately know. @@ -2017,15 +1974,11 @@ impl GlobalScope { let recv = self.send_msg(file_id); let trusted_stream = Trusted::new(&*stream.clone()); - let task_canceller = self.task_canceller(TaskSourceName::FileReading); - let task_source = self.task_manager().file_reading_task_source(); - let mut file_listener = FileListener { state: Some(FileListenerState::Empty(FileListenerTarget::Stream( trusted_stream, ))), - task_source, - task_canceller, + task_source: self.task_manager().file_reading_task_source(), }; ROUTER.add_typed_route( @@ -2042,16 +1995,12 @@ impl GlobalScope { let recv = self.send_msg(id); let trusted_promise = TrustedPromise::new(promise); - let task_canceller = self.task_canceller(TaskSourceName::FileReading); - let task_source = self.task_manager().file_reading_task_source(); - let mut file_listener = FileListener { state: Some(FileListenerState::Empty(FileListenerTarget::Promise( trusted_promise, callback, ))), - task_source, - task_canceller, + task_source: self.task_manager().file_reading_task_source(), }; ROUTER.add_typed_route( @@ -2574,28 +2523,36 @@ impl GlobalScope { self.resource_threads().sender() } - /// `ScriptChan` to send messages to the event loop of this global scope. - pub fn script_chan(&self) -> Box { + /// A sender to the event loop of this global scope. This either sends to the Worker event loop + /// or the ScriptThread event loop in the case of a `Window`. This can be `None` for dedicated + /// workers that are not currently handling a message. + pub(crate) fn event_loop_sender(&self) -> Option> { if let Some(window) = self.downcast::() { - return Box::new( - MainThreadScriptChan(window.main_thread_script_chan().clone()).clone(), + Some(window.event_loop_sender()) + } else if let Some(dedicated) = self.downcast::() { + dedicated.event_loop_sender() + } else if let Some(service_worker) = self.downcast::() { + Some(service_worker.event_loop_sender()) + } else { + unreachable!( + "Tried to access event loop sender for incompatible \ + GlobalScope (PaintWorklet or DissimilarOriginWindow)" ); } - if let Some(worker) = self.downcast::() { - return worker.script_chan(); - } - unreachable!(); } - /// The [`TaskManager`] used to schedule tasks for this [`GlobalScope`]. - pub fn task_manager(&self) -> &TaskManager { - if let Some(window) = self.downcast::() { - return window.task_manager(); - } - if let Some(worker) = self.downcast::() { - return worker.task_manager(); - } - unreachable!(); + /// A reference to the [`TaskManager`] used to schedule tasks for this [`GlobalScope`]. + pub(crate) fn task_manager(&self) -> &TaskManager { + let shared_canceller = self + .downcast::() + .map(WorkerGlobalScope::shared_task_canceller); + self.task_manager.get_or_init(|| { + TaskManager::new( + self.event_loop_sender(), + self.pipeline_id(), + shared_canceller, + ) + }) } /// Evaluate JS code on this global scope. @@ -2777,7 +2734,7 @@ impl GlobalScope { ); self.task_manager() .dom_manipulation_task_source() - .queue(task, self) + .queue(task) .unwrap(); } } @@ -2894,21 +2851,6 @@ impl GlobalScope { true } - /// Returns the task canceller of this global to ensure that everything is - /// properly cancelled when the global scope is destroyed. - pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller { - if let Some(window) = self.downcast::() { - return window.task_manager().task_canceller(name); - } - if let Some(worker) = self.downcast::() { - // Note: the "name" is not passed to the worker, - // because 'closing' it only requires one task canceller for all task sources. - // https://html.spec.whatwg.org/multipage/#dom-workerglobalscope-closing - return worker.task_canceller(); - } - unreachable!(); - } - /// Perform a microtask checkpoint. pub fn perform_a_microtask_checkpoint(&self, can_gc: CanGc) { // Only perform the checkpoint if we're not shutting down. @@ -3163,29 +3105,26 @@ impl GlobalScope { let this = Trusted::new(self); self.task_manager() .gamepad_task_source() - .queue_with_canceller( - task!(gamepad_connected: move || { - let global = this.root(); + .queue(task!(gamepad_connected: move || { + let global = this.root(); - if let Some(window) = global.downcast::() { - let navigator = window.Navigator(); - let selected_index = navigator.select_gamepad_index(); - let gamepad = Gamepad::new( - &global, - selected_index, - name, - "standard".into(), - axis_bounds, - button_bounds, - supported_haptic_effects, - false, - CanGc::note(), - ); - navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note()); - } - }), - &self.task_canceller(TaskSourceName::Gamepad), - ) + if let Some(window) = global.downcast::() { + let navigator = window.Navigator(); + let selected_index = navigator.select_gamepad_index(); + let gamepad = Gamepad::new( + &global, + selected_index, + name, + "standard".into(), + axis_bounds, + button_bounds, + supported_haptic_effects, + false, + CanGc::note(), + ); + navigator.set_gamepad(selected_index as usize, &gamepad, CanGc::note()); + } + })) .expect("Failed to queue gamepad connected task."); } @@ -3194,21 +3133,18 @@ impl GlobalScope { let this = Trusted::new(self); self.task_manager() .gamepad_task_source() - .queue_with_canceller( - task!(gamepad_disconnected: move || { - let global = this.root(); - if let Some(window) = global.downcast::() { - let navigator = window.Navigator(); - if let Some(gamepad) = navigator.get_gamepad(index) { - if window.Document().is_fully_active() { - gamepad.update_connected(false, gamepad.exposed(), CanGc::note()); - navigator.remove_gamepad(index); - } + .queue(task!(gamepad_disconnected: move || { + let global = this.root(); + if let Some(window) = global.downcast::() { + let navigator = window.Navigator(); + if let Some(gamepad) = navigator.get_gamepad(index) { + if window.Document().is_fully_active() { + gamepad.update_connected(false, gamepad.exposed(), CanGc::note()); + navigator.remove_gamepad(index); } } - }), - &self.task_canceller(TaskSourceName::Gamepad), - ) + } + })) .expect("Failed to queue gamepad disconnected task."); } @@ -3217,9 +3153,7 @@ impl GlobalScope { let this = Trusted::new(self); // - self.task_manager() - .gamepad_task_source() - .queue_with_canceller( + self.task_manager().gamepad_task_source().queue( task!(update_gamepad_state: move || { let global = this.root(); if let Some(window) = global.downcast::() { @@ -3245,13 +3179,11 @@ impl GlobalScope { gamepad.update_timestamp(*current_time); let new_gamepad = Trusted::new(&**gamepad); if window.Document().is_fully_active() { - window.task_manager().gamepad_task_source().queue_with_canceller( + global.task_manager().gamepad_task_source().queue( task!(update_gamepad_connect: move || { let gamepad = new_gamepad.root(); gamepad.notify_event(GamepadEventType::Connected, CanGc::note()); - }), - &window.upcast::() - .task_canceller(TaskSourceName::Gamepad), + }) ) .expect("Failed to queue update gamepad connect task."); } @@ -3259,8 +3191,7 @@ impl GlobalScope { } } } - }), - &self.task_canceller(TaskSourceName::Gamepad), + }) ) .expect("Failed to queue update gamepad state task."); } @@ -3333,11 +3264,9 @@ impl GlobalScope { task_source: TaskSource, cancellation_sender: Option>, ) { - let canceller = Some(self.task_canceller(TaskSourceName::Networking)); let network_listener = NetworkListener { context, task_source, - canceller, }; self.fetch_with_network_listener(request_builder, network_listener, cancellation_sender); } diff --git a/components/script/dom/htmldetailselement.rs b/components/script/dom/htmldetailselement.rs index 39baba43a5c..e6541786a63 100644 --- a/components/script/dom/htmldetailselement.rs +++ b/components/script/dom/htmldetailselement.rs @@ -92,7 +92,6 @@ impl VirtualMethods for HTMLDetailsElement { this.upcast::().fire_event(atom!("toggle"), CanGc::note()); } }), - window.upcast(), ); self.upcast::().dirty(NodeDamage::OtherNodeDamage) } diff --git a/components/script/dom/htmldialogelement.rs b/components/script/dom/htmldialogelement.rs index e556e9ed99b..644bce31ea5 100644 --- a/components/script/dom/htmldialogelement.rs +++ b/components/script/dom/htmldialogelement.rs @@ -122,6 +122,6 @@ impl HTMLDialogElementMethods for HTMLDialogElement { // Step 5 win.task_manager() .dom_manipulation_task_source() - .queue_simple_event(target, atom!("close"), &win); + .queue_simple_event(target, atom!("close")); } } diff --git a/components/script/dom/htmlformelement.rs b/components/script/dom/htmlformelement.rs index 70e578dace9..5a13ccac7df 100644 --- a/components/script/dom/htmlformelement.rs +++ b/components/script/dom/htmlformelement.rs @@ -1039,7 +1039,7 @@ impl HTMLFormElement { target .task_manager() .dom_manipulation_task_source() - .queue(task, target.upcast()) + .queue(task) .unwrap(); } diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 5cd9797a28e..293fc1200cd 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -892,24 +892,21 @@ impl HTMLImageElement { self.abort_request(State::Broken, ImageRequestPhase::Pending, can_gc); // Step 9. // FIXME(nox): Why are errors silenced here? - let _ = task_source.queue( - task!(image_null_source_error: move || { - let this = this.root(); - { - let mut current_request = - this.current_request.borrow_mut(); - current_request.source_url = None; - current_request.parsed_url = None; - } - let elem = this.upcast::(); - let src_present = elem.has_attribute(&local_name!("src")); + let _ = task_source.queue(task!(image_null_source_error: move || { + let this = this.root(); + { + let mut current_request = + this.current_request.borrow_mut(); + current_request.source_url = None; + current_request.parsed_url = None; + } + let elem = this.upcast::(); + let src_present = elem.has_attribute(&local_name!("src")); - if src_present || Self::uses_srcset_or_picture(elem) { - this.upcast::().fire_event(atom!("error"), CanGc::note()); - } - }), - window.upcast(), - ); + if src_present || Self::uses_srcset_or_picture(elem) { + this.upcast::().fire_event(atom!("error"), CanGc::note()); + } + })); return; }, }; @@ -928,19 +925,16 @@ impl HTMLImageElement { // Step 12.1-12.5. let src = src.0; // FIXME(nox): Why are errors silenced here? - let _ = task_source.queue( - task!(image_selected_source_error: move || { - let this = this.root(); - { - let mut current_request = - this.current_request.borrow_mut(); - current_request.source_url = Some(USVString(src)) - } - this.upcast::().fire_event(atom!("error"), CanGc::note()); + let _ = task_source.queue(task!(image_selected_source_error: move || { + let this = this.root(); + { + let mut current_request = + this.current_request.borrow_mut(); + current_request.source_url = Some(USVString(src)) + } + this.upcast::().fire_event(atom!("error"), CanGc::note()); - }), - window.upcast(), - ); + })); }, } } @@ -1021,6 +1015,7 @@ impl HTMLImageElement { current_request.current_pixel_density = pixel_density; let this = Trusted::new(self); let src = src.0; + let _ = window.task_manager().dom_manipulation_task_source().queue( task!(image_load_event: move || { let this = this.root(); @@ -1033,7 +1028,6 @@ impl HTMLImageElement { // TODO: restart animation, if set. this.upcast::().fire_event(atom!("load"), CanGc::note()); }), - window.upcast(), ); return; } @@ -1069,11 +1063,7 @@ impl HTMLImageElement { ) -> IpcSender { let trusted_node = Trusted::new(elem); let (responder_sender, responder_receiver) = ipc::channel().unwrap(); - - let window = elem.owner_window(); - let (task_source, canceller) = window - .task_manager() - .networking_task_source_with_canceller(); + let task_source = elem.owner_window().task_manager().networking_task_source(); let generation = elem.generation.get(); ROUTER.add_typed_route( @@ -1085,7 +1075,7 @@ impl HTMLImageElement { let element = trusted_node.clone(); let image: PendingImageResponse = message.unwrap(); let selected_source_clone = selected_source.clone(); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(process_image_response_for_environment_change: move || { let element = element.root(); // Ignore any image response for a previous request that has been discarded. @@ -1094,8 +1084,7 @@ impl HTMLImageElement { USVString::from(selected_source_clone), generation, selected_pixel_density, CanGc::note()); } - }), - &canceller, + }) ); }), ); @@ -1283,8 +1272,7 @@ impl HTMLImageElement { // Step 15.7 this.upcast::().fire_event(atom!("load"), CanGc::note()); - }), - window.upcast(), + }) ); } diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 21898720d75..3a1163ac0d7 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -2576,8 +2576,7 @@ impl VirtualMethods for HTMLInputElement { self.input_type().is_textual_or_password() { if event.IsTrusted() { - let window = self.owner_window(); - window + self.owner_window() .task_manager() .user_interaction_task_source() .queue_event( @@ -2585,7 +2584,6 @@ impl VirtualMethods for HTMLInputElement { atom!("input"), EventBubbles::Bubbles, EventCancelable::NotCancelable, - &window, ); } } else if (event.type_() == atom!("compositionstart") || diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs index d5e8ab5d1fd..5b6727bf95a 100644 --- a/components/script/dom/htmlmediaelement.rs +++ b/components/script/dom/htmlmediaelement.rs @@ -523,11 +523,10 @@ impl HTMLMediaElement { fn time_marches_on(&self) { // Step 6. if Instant::now() > self.next_timeupdate_event.get() { - let window = self.owner_window(); - window + self.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + .queue_simple_event(self.upcast(), atom!("timeupdate")); self.next_timeupdate_event .set(Instant::now() + Duration::from_millis(350)); } @@ -547,11 +546,13 @@ impl HTMLMediaElement { self.take_pending_play_promises(Err(Error::Abort)); // Step 2.3. - let window = self.owner_window(); let this = Trusted::new(self); let generation_id = self.generation_id.get(); - let _ = window.task_manager().media_element_task_source().queue( - task!(internal_pause_steps: move || { + let _ = self + .owner_window() + .task_manager() + .media_element_task_source() + .queue(task!(internal_pause_steps: move || { let this = this.root(); if generation_id != this.generation_id.get() { return; @@ -574,9 +575,7 @@ impl HTMLMediaElement { // Done after running this closure in // `fulfill_in_flight_play_promises`. }); - }), - window.upcast(), - ); + })); // Step 2.4. // FIXME(nox): Set the official playback position to the current @@ -594,12 +593,14 @@ impl HTMLMediaElement { self.take_pending_play_promises(Ok(())); // Step 2. - let window = self.owner_window(); let this = Trusted::new(self); let generation_id = self.generation_id.get(); // FIXME(nox): Why are errors silenced here? - let _ = window.task_manager().media_element_task_source().queue( - task!(notify_about_playing: move || { + let _ = self + .owner_window() + .task_manager() + .media_element_task_source() + .queue(task!(notify_about_playing: move || { let this = this.root(); if generation_id != this.generation_id.get() { return; @@ -615,9 +616,7 @@ impl HTMLMediaElement { // `fulfill_in_flight_play_promises`. }); - }), - window.upcast(), - ); + })); } // https://html.spec.whatwg.org/multipage/#ready-states @@ -633,13 +632,15 @@ impl HTMLMediaElement { return; } - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); + let task_source = self + .owner_window() + .task_manager() + .media_element_task_source(); // Step 1. match (old_ready_state, ready_state) { (ReadyState::HaveNothing, ReadyState::HaveMetadata) => { - task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata"), &window); + task_source.queue_simple_event(self.upcast(), atom!("loadedmetadata")); // No other steps are applicable in this case. return; }, @@ -648,14 +649,11 @@ impl HTMLMediaElement { self.fired_loadeddata_event.set(true); let this = Trusted::new(self); // FIXME(nox): Why are errors silenced here? - let _ = task_source.queue( - task!(media_reached_current_data: move || { - let this = this.root(); - this.upcast::().fire_event(atom!("loadeddata"), CanGc::note()); - this.delay_load_event(false, CanGc::note()); - }), - window.upcast(), - ); + let _ = task_source.queue(task!(media_reached_current_data: move || { + let this = this.root(); + this.upcast::().fire_event(atom!("loadeddata"), CanGc::note()); + this.delay_load_event(false, CanGc::note()); + })); } // Steps for the transition from HaveMetadata to HaveCurrentData @@ -676,7 +674,7 @@ impl HTMLMediaElement { if old_ready_state <= ReadyState::HaveCurrentData && ready_state >= ReadyState::HaveFutureData { - task_source.queue_simple_event(self.upcast(), atom!("canplay"), &window); + task_source.queue_simple_event(self.upcast(), atom!("canplay")); if !self.Paused() { self.notify_about_playing(); @@ -697,7 +695,7 @@ impl HTMLMediaElement { self.time_marches_on(); } // Step 3 - task_source.queue_simple_event(self.upcast(), atom!("play"), &window); + task_source.queue_simple_event(self.upcast(), atom!("play")); // Step 4 self.notify_about_playing(); // Step 5 @@ -706,7 +704,7 @@ impl HTMLMediaElement { // FIXME(nox): According to the spec, this should come *before* the // "play" event. - task_source.queue_simple_event(self.upcast(), atom!("canplaythrough"), &window); + task_source.queue_simple_event(self.upcast(), atom!("canplaythrough")); } } @@ -787,11 +785,10 @@ impl HTMLMediaElement { self.network_state.set(NetworkState::Loading); // Step 8. - let window = self.owner_window(); - window + self.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("loadstart"), &window); + .queue_simple_event(self.upcast(), atom!("loadstart")); // Step 9. match mode { @@ -941,19 +938,16 @@ impl HTMLMediaElement { window .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("suspend"), &window); + .queue_simple_event(self.upcast(), atom!("suspend")); // Step 4.remote.1.3. let this = Trusted::new(self); window .task_manager() .media_element_task_source() - .queue( - task!(set_media_delay_load_event_flag_to_false: move || { - this.root().delay_load_event(false, CanGc::note()); - }), - window.upcast(), - ) + .queue(task!(set_media_delay_load_event_flag_to_false: move || { + this.root().delay_load_event(false, CanGc::note()); + })) .unwrap(); // Steps 4.remote.1.4. @@ -1007,13 +1001,15 @@ impl HTMLMediaElement { /// /// [steps]: https://html.spec.whatwg.org/multipage/#dedicated-media-source-failure-steps fn queue_dedicated_media_source_failure_steps(&self) { - let window = self.owner_window(); let this = Trusted::new(self); let generation_id = self.generation_id.get(); self.take_pending_play_promises(Err(Error::NotSupported)); // FIXME(nox): Why are errors silenced here? - let _ = window.task_manager().media_element_task_source().queue( - task!(dedicated_media_source_failure_steps: move || { + let _ = self + .owner_window() + .task_manager() + .media_element_task_source() + .queue(task!(dedicated_media_source_failure_steps: move || { let this = this.root(); if generation_id != this.generation_id.get() { return; @@ -1052,15 +1048,14 @@ impl HTMLMediaElement { // Step 7. this.delay_load_event(false, CanGc::note()); - }), - window.upcast(), - ); + })); } fn queue_ratechange_event(&self) { - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("ratechange"), &window); + self.owner_window() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("ratechange")); } fn in_error_state(&self) -> bool { @@ -1110,19 +1105,21 @@ impl HTMLMediaElement { self.fulfill_in_flight_play_promises(|| ()); } - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); + let task_source = self + .owner_window() + .task_manager() + .media_element_task_source(); // Step 5. let network_state = self.network_state.get(); if network_state == NetworkState::Loading || network_state == NetworkState::Idle { - task_source.queue_simple_event(self.upcast(), atom!("abort"), &window); + task_source.queue_simple_event(self.upcast(), atom!("abort")); } // Step 6. if network_state != NetworkState::Empty { // Step 6.1. - task_source.queue_simple_event(self.upcast(), atom!("emptied"), &window); + task_source.queue_simple_event(self.upcast(), atom!("emptied")); // Step 6.2. if let Some(ref mut current_fetch_context) = *self.current_fetch_context.borrow_mut() { @@ -1160,7 +1157,7 @@ impl HTMLMediaElement { let queue_timeupdate_event = self.playback_position.get() != 0.; self.playback_position.set(0.); if queue_timeupdate_event { - task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + task_source.queue_simple_event(self.upcast(), atom!("timeupdate")); } // Step 6.9. @@ -1291,9 +1288,10 @@ impl HTMLMediaElement { // servo-media with gstreamer does not support inaccurate seeking for now. // Step 10. - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("seeking"), &window); + self.owner_window() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("seeking")); // Step 11. if let Some(ref player) = *self.player.borrow() { @@ -1316,12 +1314,14 @@ impl HTMLMediaElement { self.time_marches_on(); // Step 16. - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("timeupdate"), &window); + let task_source = self + .owner_window() + .task_manager() + .media_element_task_source(); + task_source.queue_simple_event(self.upcast(), atom!("timeupdate")); // Step 17. - task_source.queue_simple_event(self.upcast(), atom!("seeked"), &window); + task_source.queue_simple_event(self.upcast(), atom!("seeked")); } /// @@ -1339,9 +1339,10 @@ impl HTMLMediaElement { self.upcast::().dirty(NodeDamage::OtherNodeDamage); if pref!(media.testing.enabled) { - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("postershown"), &window); + self.owner_window() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("postershown")); } } @@ -1385,21 +1386,16 @@ impl HTMLMediaElement { *self.player.borrow_mut() = Some(player); let trusted_node = Trusted::new(self); - let (task_source, canceller) = window - .task_manager() - .media_element_task_source_with_canceller(); + let task_source = window.task_manager().media_element_task_source(); ROUTER.add_typed_route( action_receiver, Box::new(move |message| { let event = message.unwrap(); trace!("Player event {:?}", event); let this = trusted_node.clone(); - if let Err(err) = task_source.queue_with_canceller( - task!(handle_player_event: move || { - this.root().handle_player_event(&event, CanGc::note()); - }), - &canceller, - ) { + if let Err(err) = task_source.queue(task!(handle_player_event: move || { + this.root().handle_player_event(&event, CanGc::note()); + })) { warn!("Could not queue player event handler task {:?}", err); } }), @@ -1428,42 +1424,37 @@ impl HTMLMediaElement { if let Some(image_receiver) = image_receiver { let trusted_node = Trusted::new(self); - let (task_source, canceller) = window - .task_manager() - .media_element_task_source_with_canceller(); + let task_source = window.task_manager().media_element_task_source(); ROUTER.add_typed_route( image_receiver.to_ipc_receiver(), Box::new(move |message| { let msg = message.unwrap(); let this = trusted_node.clone(); - if let Err(err) = task_source.queue_with_canceller( - task!(handle_glplayer_message: move || { - trace!("GLPlayer message {:?}", msg); - let video_renderer = this.root().video_renderer.clone(); + if let Err(err) = task_source.queue(task!(handle_glplayer_message: move || { + trace!("GLPlayer message {:?}", msg); + let video_renderer = this.root().video_renderer.clone(); - match msg { - GLPlayerMsgForward::Lock(sender) => { - if let Some(holder) = video_renderer - .lock() - .unwrap() - .current_frame_holder - .as_mut() { - holder.lock(); - sender.send(holder.get()).unwrap(); - }; - }, - GLPlayerMsgForward::Unlock() => { - if let Some(holder) = video_renderer - .lock() - .unwrap() - .current_frame_holder - .as_mut() { holder.unlock() } - }, - _ => (), - } - }), - &canceller, - ) { + match msg { + GLPlayerMsgForward::Lock(sender) => { + if let Some(holder) = video_renderer + .lock() + .unwrap() + .current_frame_holder + .as_mut() { + holder.lock(); + sender.send(holder.get()).unwrap(); + }; + }, + GLPlayerMsgForward::Unlock() => { + if let Some(holder) = video_renderer + .lock() + .unwrap() + .current_frame_holder + .as_mut() { holder.unlock() } + }, + _ => (), + } + })) { warn!("Could not queue GL player message handler task {:?}", err); } }), @@ -1513,10 +1504,9 @@ impl HTMLMediaElement { // the HTMLMediaElementMethods::Ended method // Step 3. - let window = self.owner_window(); let this = Trusted::new(self); - let _ = window.task_manager().media_element_task_source().queue( + let _ = self.owner_window().task_manager().media_element_task_source().queue( task!(reaches_the_end_steps: move || { let this = this.root(); // Step 3.1. @@ -1537,8 +1527,7 @@ impl HTMLMediaElement { // Step 3.3. this.upcast::().fire_event(atom!("ended"), CanGc::note()); - }), - window.upcast(), + }) ); // https://html.spec.whatwg.org/multipage/#dom-media-have_current_data @@ -1548,12 +1537,10 @@ impl HTMLMediaElement { PlaybackDirection::Backwards => { if self.playback_position.get() <= self.earliest_possible_position() { - let window = self.owner_window(); - - window + self.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("ended"), &window); + .queue_simple_event(self.upcast(), atom!("ended")); } }, } @@ -1737,9 +1724,10 @@ impl HTMLMediaElement { self.duration.set(f64::INFINITY); } if previous_duration != self.duration.get() { - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("durationchange"), &window); + self.owner_window() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("durationchange")); } // Step 5. @@ -2130,11 +2118,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } self.muted.set(value); - let window = self.owner_window(); - window + self.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("volumechange"), &window); + .queue_simple_event(self.upcast(), atom!("volumechange")); if !self.is_allowed_to_play() { self.internal_pause_steps(); } @@ -2229,9 +2216,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement { let state = self.ready_state.get(); - let window = self.owner_window(); - // FIXME(nox): Why are errors silenced here? - let task_source = window.task_manager().media_element_task_source(); + let task_source = self + .owner_window() + .task_manager() + .media_element_task_source(); if self.Paused() { // Step 6.1. self.paused.set(false); @@ -2243,14 +2231,14 @@ impl HTMLMediaElementMethods for HTMLMediaElement { } // Step 6.3. - task_source.queue_simple_event(self.upcast(), atom!("play"), &window); + task_source.queue_simple_event(self.upcast(), atom!("play")); // Step 6.4. match state { ReadyState::HaveNothing | ReadyState::HaveMetadata | ReadyState::HaveCurrentData => { - task_source.queue_simple_event(self.upcast(), atom!("waiting"), &window); + task_source.queue_simple_event(self.upcast(), atom!("waiting")); }, ReadyState::HaveFutureData | ReadyState::HaveEnoughData => { self.notify_about_playing(); @@ -2262,19 +2250,16 @@ impl HTMLMediaElementMethods for HTMLMediaElement { let this = Trusted::new(self); let generation_id = self.generation_id.get(); task_source - .queue( - task!(resolve_pending_play_promises: move || { - let this = this.root(); - if generation_id != this.generation_id.get() { - return; - } + .queue(task!(resolve_pending_play_promises: move || { + let this = this.root(); + if generation_id != this.generation_id.get() { + return; + } - this.fulfill_in_flight_play_promises(|| { - this.play_media(); - }); - }), - window.upcast(), - ) + this.fulfill_in_flight_play_promises(|| { + this.play_media(); + }); + })) .unwrap(); } @@ -2478,11 +2463,10 @@ impl HTMLMediaElementMethods for HTMLMediaElement { if *value != self.volume.get() { self.volume.set(*value); - let window = self.owner_window(); - window + self.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(self.upcast(), atom!("volumechange"), &window); + .queue_simple_event(self.upcast(), atom!("volumechange")); if !self.is_allowed_to_play() { self.internal_pause_steps(); } @@ -2809,11 +2793,10 @@ impl FetchResponseListener for HTMLMediaElementFetchListener { // https://html.spec.whatwg.org/multipage/#concept-media-load-resource step 4, // => "If mode is remote" step 2 if Instant::now() > self.next_progress_event { - let window = elem.owner_window(); - window + elem.owner_window() .task_manager() .media_element_task_source() - .queue_simple_event(elem.upcast(), atom!("progress"), &window); + .queue_simple_event(elem.upcast(), atom!("progress")); self.next_progress_event = Instant::now() + Duration::from_millis(350); } } diff --git a/components/script/dom/htmlscriptelement.rs b/components/script/dom/htmlscriptelement.rs index 1095d847354..3b81f9bb1e1 100644 --- a/components/script/dom/htmlscriptelement.rs +++ b/components/script/dom/htmlscriptelement.rs @@ -64,7 +64,6 @@ use crate::script_module::{ fetch_external_module_script, fetch_inline_module_script, ModuleOwner, ScriptFetchOptions, }; use crate::script_runtime::CanGc; -use crate::task::TaskCanceller; use crate::task_source::{TaskSource, TaskSourceName}; use crate::unminify::{unminify_js, ScriptSource}; @@ -102,7 +101,6 @@ impl ScriptSource for ScriptOrigin { final_url: ServoUrl, url: ServoUrl, task_source: TaskSource, - canceller: TaskCanceller, script_text: String, fetch_options: ScriptFetchOptions, } @@ -123,7 +121,7 @@ unsafe extern "C" fn off_thread_compilation_callback( let fetch_options = context.fetch_options.clone(); // Continue with - let _ = context.task_source.queue_with_canceller( + let _ = context.task_source.queue( task!(off_thread_compile_continue: move || { let elem = script_element.root(); let global = elem.global(); @@ -157,8 +155,7 @@ unsafe extern "C" fn off_thread_compilation_callback( }; finish_fetching_a_classic_script(&elem, script_kind, url, load); - }), - &context.canceller, + }) ); }*/ @@ -476,7 +473,6 @@ impl FetchResponseListener for ClassicContext { final_url, url: self.url.clone(), 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(), }); @@ -1061,11 +1057,10 @@ impl HTMLScriptElement { } pub fn queue_error_event(&self) { - let window = self.owner_window(); - window + self.owner_window() .task_manager() .dom_manipulation_task_source() - .queue_simple_event(self.upcast(), atom!("error"), &window); + .queue_simple_event(self.upcast(), atom!("error")); } pub fn dispatch_load_event(&self, can_gc: CanGc) { diff --git a/components/script/dom/htmlstyleelement.rs b/components/script/dom/htmlstyleelement.rs index 1d3111e38ec..1335f860352 100644 --- a/components/script/dom/htmlstyleelement.rs +++ b/components/script/dom/htmlstyleelement.rs @@ -133,11 +133,10 @@ impl HTMLStyleElement { // No subresource loads were triggered, queue load event if self.pending_loads.get() == 0 { - let window = self.owner_window(); - window + self.owner_window() .task_manager() .dom_manipulation_task_source() - .queue_simple_event(self.upcast(), atom!("load"), &window); + .queue_simple_event(self.upcast(), atom!("load")); } self.set_stylesheet(sheet); diff --git a/components/script/dom/htmltextareaelement.rs b/components/script/dom/htmltextareaelement.rs index 8d3aa032924..b8275115afd 100644 --- a/components/script/dom/htmltextareaelement.rs +++ b/components/script/dom/htmltextareaelement.rs @@ -650,8 +650,7 @@ impl VirtualMethods for HTMLTextAreaElement { } } else if event.type_() == atom!("keypress") && !event.DefaultPrevented() { if event.IsTrusted() { - let window = self.owner_window(); - window + self.owner_window() .task_manager() .user_interaction_task_source() .queue_event( @@ -659,7 +658,6 @@ impl VirtualMethods for HTMLTextAreaElement { atom!("input"), EventBubbles::Bubbles, EventCancelable::NotCancelable, - &window, ); } } else if event.type_() == atom!("compositionstart") || diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs index 0b10bafb16a..66057d8d1bc 100644 --- a/components/script/dom/htmlvideoelement.rs +++ b/components/script/dom/htmlvideoelement.rs @@ -125,9 +125,10 @@ impl HTMLVideoElement { let sent_resize = if self.htmlmediaelement.get_ready_state() == ReadyState::HaveNothing { None } else { - let window = self.owner_window(); - let task_source = window.task_manager().media_element_task_source(); - task_source.queue_simple_event(self.upcast(), atom!("resize"), &window); + self.owner_window() + .task_manager() + .media_element_task_source() + .queue_simple_event(self.upcast(), atom!("resize")); Some((width, height)) }; diff --git a/components/script/dom/offlineaudiocontext.rs b/components/script/dom/offlineaudiocontext.rs index f3deeae2cc9..17691b2158f 100644 --- a/components/script/dom/offlineaudiocontext.rs +++ b/components/script/dom/offlineaudiocontext.rs @@ -170,16 +170,12 @@ impl OfflineAudioContextMethods for OfflineAudioContext { })); let this = Trusted::new(self); - let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); Builder::new() .name("OfflineACResolver".to_owned()) .spawn(move || { let _ = receiver.recv(); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(resolve: move || { let this = this.root(); let processed_audio = processed_audio.lock().unwrap(); @@ -207,8 +203,7 @@ impl OfflineAudioContextMethods for OfflineAudioContext { EventCancelable::NotCancelable, &buffer, CanGc::note()); event.upcast::().fire(this.upcast(), CanGc::note()); - }), - &canceller, + }) ); }) .unwrap(); diff --git a/components/script/dom/performance.rs b/components/script/dom/performance.rs index f5aab785293..ba89eea4932 100644 --- a/components/script/dom/performance.rs +++ b/components/script/dom/performance.rs @@ -247,7 +247,7 @@ impl Performance { let task = task!(notify_performance_observers: move || { owner.root().notify_observers(); }); - let _ = task_source.queue(task, global); + let _ = task_source.queue(task); } } let mut observers = self.observers.borrow_mut(); @@ -334,7 +334,7 @@ impl Performance { let task = task!(notify_performance_observers: move || { owner.root().notify_observers(); }); - let _ = task_source.queue(task, global); + let _ = task_source.queue(task); Some(entry_last_index) } diff --git a/components/script/dom/rtcpeerconnection.rs b/components/script/dom/rtcpeerconnection.rs index 6495d9e1ec5..b2a31e99882 100644 --- a/components/script/dom/rtcpeerconnection.rs +++ b/components/script/dom/rtcpeerconnection.rs @@ -52,7 +52,6 @@ use crate::dom::rtctrackevent::RTCTrackEvent; use crate::dom::window::Window; use crate::realms::{enter_realm, InRealm}; use crate::script_runtime::CanGc; -use crate::task::TaskCanceller; use crate::task_source::TaskSource; #[dom_struct] @@ -81,75 +80,64 @@ pub struct RTCPeerConnection { struct RTCSignaller { trusted: Trusted, task_source: TaskSource, - canceller: TaskCanceller, } impl WebRtcSignaller for RTCSignaller { fn on_ice_candidate(&self, _: &WebRtcController, candidate: IceCandidate) { let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(on_ice_candidate: move || { - let this = this.root(); - this.on_ice_candidate(candidate, CanGc::note()); - }), - &self.canceller, - ); + let _ = self.task_source.queue(task!(on_ice_candidate: move || { + let this = this.root(); + this.on_ice_candidate(candidate, CanGc::note()); + })); } fn on_negotiation_needed(&self, _: &WebRtcController) { let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(on_negotiation_needed: move || { + let _ = self + .task_source + .queue(task!(on_negotiation_needed: move || { let this = this.root(); this.on_negotiation_needed(CanGc::note()); - }), - &self.canceller, - ); + })); } fn update_gathering_state(&self, state: GatheringState) { let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(update_gathering_state: move || { + let _ = self + .task_source + .queue(task!(update_gathering_state: move || { let this = this.root(); this.update_gathering_state(state, CanGc::note()); - }), - &self.canceller, - ); + })); } fn update_ice_connection_state(&self, state: IceConnectionState) { let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(update_ice_connection_state: move || { + let _ = self + .task_source + .queue(task!(update_ice_connection_state: move || { let this = this.root(); this.update_ice_connection_state(state, CanGc::note()); - }), - &self.canceller, - ); + })); } fn update_signaling_state(&self, state: SignalingState) { let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(update_signaling_state: move || { + let _ = self + .task_source + .queue(task!(update_signaling_state: move || { let this = this.root(); this.update_signaling_state(state, CanGc::note()); - }), - &self.canceller, - ); + })); } fn on_add_stream(&self, id: &MediaStreamId, ty: MediaStreamType) { let this = self.trusted.clone(); let id = *id; - let _ = self.task_source.queue_with_canceller( - task!(on_add_stream: move || { - let this = this.root(); - this.on_add_stream(id, ty, CanGc::note()); - }), - &self.canceller, - ); + let _ = self.task_source.queue(task!(on_add_stream: move || { + let this = this.root(); + this.on_add_stream(id, ty, CanGc::note()); + })); } fn on_data_channel_event( @@ -160,15 +148,14 @@ impl WebRtcSignaller for RTCSignaller { ) { // XXX(ferjm) get label and options from channel properties. let this = self.trusted.clone(); - let _ = self.task_source.queue_with_canceller( - task!(on_data_channel_event: move || { + let _ = self + .task_source + .queue(task!(on_data_channel_event: move || { let this = this.root(); let global = this.global(); let _ac = enter_realm(&*global); this.on_data_channel_event(channel, event, CanGc::note()); - }), - &self.canceller, - ); + })); } fn close(&self) { @@ -237,15 +224,10 @@ impl RTCPeerConnection { fn make_signaller(&self) -> Box { let trusted = Trusted::new(self); - let (task_source, canceller) = self - .global() - .as_window() - .task_manager() - .networking_task_source_with_canceller(); + let task_source = self.global().task_manager().networking_task_source(); Box::new(RTCSignaller { trusted, task_source, - canceller, }) } @@ -460,65 +442,51 @@ impl RTCPeerConnection { fn create_offer(&self) { let generation = self.offer_answer_generation.get(); - let (task_source, canceller) = self - .global() - .as_window() - .task_manager() - .networking_task_source_with_canceller(); + let task_source = self.global().task_manager().networking_task_source(); let this = Trusted::new(self); self.controller .borrow_mut() .as_ref() .unwrap() .create_offer(Box::new(move |desc: SessionDescription| { - let _ = task_source.queue_with_canceller( - task!(offer_created: move || { - let this = this.root(); - if this.offer_answer_generation.get() != generation { - // the state has changed since we last created the offer, - // create a fresh one - this.create_offer(); - } else { - let init: RTCSessionDescriptionInit = desc.convert(); - for promise in this.offer_promises.borrow_mut().drain(..) { - promise.resolve_native(&init); - } + let _ = task_source.queue(task!(offer_created: move || { + let this = this.root(); + if this.offer_answer_generation.get() != generation { + // the state has changed since we last created the offer, + // create a fresh one + this.create_offer(); + } else { + let init: RTCSessionDescriptionInit = desc.convert(); + for promise in this.offer_promises.borrow_mut().drain(..) { + promise.resolve_native(&init); } - }), - &canceller, - ); + } + })); })); } fn create_answer(&self) { let generation = self.offer_answer_generation.get(); - let (task_source, canceller) = self - .global() - .as_window() - .task_manager() - .networking_task_source_with_canceller(); + let task_source = self.global().task_manager().networking_task_source(); let this = Trusted::new(self); self.controller .borrow_mut() .as_ref() .unwrap() .create_answer(Box::new(move |desc: SessionDescription| { - let _ = task_source.queue_with_canceller( - task!(answer_created: move || { - let this = this.root(); - if this.offer_answer_generation.get() != generation { - // the state has changed since we last created the offer, - // create a fresh one - this.create_answer(); - } else { - let init: RTCSessionDescriptionInit = desc.convert(); - for promise in this.answer_promises.borrow_mut().drain(..) { - promise.resolve_native(&init); - } + let _ = task_source.queue(task!(answer_created: move || { + let this = this.root(); + if this.offer_answer_generation.get() != generation { + // the state has changed since we last created the offer, + // create a fresh one + this.create_answer(); + } else { + let init: RTCSessionDescriptionInit = desc.convert(); + for promise in this.answer_promises.borrow_mut().drain(..) { + promise.resolve_native(&init); } - }), - &canceller, - ); + } + })); })); } } @@ -667,11 +635,7 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { let this = Trusted::new(self); let desc: SessionDescription = desc.convert(); let trusted_promise = TrustedPromise::new(p.clone()); - let (task_source, canceller) = self - .global() - .as_window() - .task_manager() - .networking_task_source_with_canceller(); + let task_source = self.global().task_manager().networking_task_source(); self.controller .borrow_mut() .as_ref() @@ -679,23 +643,20 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { .set_local_description( desc.clone(), Box::new(move || { - let _ = task_source.queue_with_canceller( - task!(local_description_set: move || { - // XXXManishearth spec actually asks for an intricate - // dance between pending/current local/remote descriptions - let this = this.root(); - let desc = desc.convert(); - let desc = RTCSessionDescription::Constructor( - this.global().as_window(), - None, - CanGc::note(), - &desc, - ).unwrap(); - this.local_description.set(Some(&desc)); - trusted_promise.root().resolve_native(&()) - }), - &canceller, - ); + let _ = task_source.queue(task!(local_description_set: move || { + // XXXManishearth spec actually asks for an intricate + // dance between pending/current local/remote descriptions + let this = this.root(); + let desc = desc.convert(); + let desc = RTCSessionDescription::Constructor( + this.global().as_window(), + None, + CanGc::note(), + &desc, + ).unwrap(); + this.local_description.set(Some(&desc)); + trusted_promise.root().resolve_native(&()) + })); }), ); p @@ -713,11 +674,7 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { let this = Trusted::new(self); let desc: SessionDescription = desc.convert(); let trusted_promise = TrustedPromise::new(p.clone()); - let (task_source, canceller) = self - .global() - .as_window() - .task_manager() - .networking_task_source_with_canceller(); + let task_source = self.global().task_manager().networking_task_source(); self.controller .borrow_mut() .as_ref() @@ -725,23 +682,20 @@ impl RTCPeerConnectionMethods for RTCPeerConnection { .set_remote_description( desc.clone(), Box::new(move || { - let _ = task_source.queue_with_canceller( - task!(remote_description_set: move || { - // XXXManishearth spec actually asks for an intricate - // dance between pending/current local/remote descriptions - let this = this.root(); - let desc = desc.convert(); - let desc = RTCSessionDescription::Constructor( - this.global().as_window(), - None, - CanGc::note(), - &desc, - ).unwrap(); - this.remote_description.set(Some(&desc)); - trusted_promise.root().resolve_native(&()) - }), - &canceller, - ); + let _ = task_source.queue(task!(remote_description_set: move || { + // XXXManishearth spec actually asks for an intricate + // dance between pending/current local/remote descriptions + let this = this.root(); + let desc = desc.convert(); + let desc = RTCSessionDescription::Constructor( + this.global().as_window(), + None, + CanGc::note(), + &desc, + ).unwrap(); + this.remote_description.set(Some(&desc)); + trusted_promise.root().resolve_native(&()) + })); }), ); p diff --git a/components/script/dom/selection.rs b/components/script/dom/selection.rs index ae2beee74d5..be7d6c2ee6c 100644 --- a/components/script/dom/selection.rs +++ b/components/script/dom/selection.rs @@ -88,8 +88,8 @@ impl Selection { return; } let this = Trusted::new(self); - let window = self.document.window(); - window + self.document + .window() .task_manager() .user_interaction_task_source() // w3c/selection-api#117 .queue( @@ -97,8 +97,7 @@ impl Selection { let this = this.root(); this.task_queued.set(false); this.document.upcast::().fire_event(atom!("selectionchange"), CanGc::note()); - }), - window.upcast(), + }) ) .expect("Couldn't queue selectionchange task!"); self.task_queued.set(true); diff --git a/components/script/dom/serviceworkercontainer.rs b/components/script/dom/serviceworkercontainer.rs index 7d71f81c5fd..a443c67f3ce 100644 --- a/components/script/dom/serviceworkercontainer.rs +++ b/components/script/dom/serviceworkercontainer.rs @@ -26,8 +26,7 @@ use crate::dom::serviceworker::ServiceWorker; use crate::dom::serviceworkerregistration::ServiceWorkerRegistration; use crate::realms::{enter_realm, InRealm}; use crate::script_runtime::CanGc; -use crate::task::TaskCanceller; -use crate::task_source::{TaskSource, TaskSourceName}; +use crate::task_source::TaskSource; #[dom_struct] pub struct ServiceWorkerContainer { @@ -141,15 +140,10 @@ impl ServiceWorkerContainerMethods 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.task_manager().dom_manipulation_task_source(), - global.task_canceller(TaskSourceName::DOMManipulation), - ); - + let task_source = global.task_manager().dom_manipulation_task_source(); let mut handler = RegisterJobResultHandler { trusted_promise: Some(TrustedPromise::new(promise.clone())), task_source, - task_canceller, }; let (job_result_sender, job_result_receiver) = ipc::channel().expect("ipc channel failure"); @@ -190,7 +184,6 @@ impl ServiceWorkerContainerMethods for ServiceWorkerContai struct RegisterJobResultHandler { trusted_promise: Option, task_source: TaskSource, - task_canceller: TaskCanceller, } impl RegisterJobResultHandler { @@ -206,7 +199,7 @@ impl RegisterJobResultHandler { .expect("No promise to resolve for SW Register job."); // Step 1 - let _ = self.task_source.queue_with_canceller( + let _ = self.task_source.queue( task!(reject_promise_with_security_error: move || { let promise = promise.root(); let _ac = enter_realm(&*promise.global()); @@ -219,8 +212,7 @@ impl RegisterJobResultHandler { }, } - }), - &self.task_canceller, + }) ); // TODO: step 2, handle equivalent jobs. @@ -232,35 +224,32 @@ impl RegisterJobResultHandler { .expect("No promise to resolve for SW Register job."); // Step 1 - let _ = self.task_source.queue_with_canceller( - task!(resolve_promise: move || { - let promise = promise.root(); - let global = promise.global(); - let _ac = enter_realm(&*global); + let _ = self.task_source.queue(task!(resolve_promise: move || { + let promise = promise.root(); + let global = promise.global(); + let _ac = enter_realm(&*global); - // Step 1.1 - let JobResultValue::Registration { - id, - installing_worker, - waiting_worker, - active_worker, - } = value; + // Step 1.1 + let JobResultValue::Registration { + id, + installing_worker, + waiting_worker, + active_worker, + } = value; - // Step 1.2 (Job type is "register"). - let registration = global.get_serviceworker_registration( - &job.script_url, - &job.scope_url, - id, - installing_worker, - waiting_worker, - active_worker, - ); + // Step 1.2 (Job type is "register"). + let registration = global.get_serviceworker_registration( + &job.script_url, + &job.scope_url, + id, + installing_worker, + waiting_worker, + active_worker, + ); - // Step 1.4 - promise.resolve_native(&*registration); - }), - &self.task_canceller, - ); + // Step 1.4 + promise.resolve_native(&*registration); + })); // TODO: step 2, handle equivalent jobs. }, diff --git a/components/script/dom/serviceworkerglobalscope.rs b/components/script/dom/serviceworkerglobalscope.rs index d875d4c6f53..a7e699fee08 100644 --- a/components/script/dom/serviceworkerglobalscope.rs +++ b/components/script/dom/serviceworkerglobalscope.rs @@ -412,7 +412,7 @@ impl ServiceWorkerGlobalScope { } }, reporter_name, - scope.script_chan(), + global.event_loop_sender(), CommonScriptMsg::CollectReports, ); @@ -485,7 +485,7 @@ impl ServiceWorkerGlobalScope { } } - pub fn script_chan(&self) -> Box { + pub(crate) fn event_loop_sender(&self) -> Box { Box::new(ServiceWorkerChan { sender: self.own_sender.clone(), }) diff --git a/components/script/dom/storage.rs b/components/script/dom/storage.rs index a5865ff72c0..82e065a995e 100644 --- a/components/script/dom/storage.rs +++ b/components/script/dom/storage.rs @@ -209,29 +209,25 @@ impl Storage { let global = self.global(); let this = Trusted::new(self); global - .as_window() .task_manager() .dom_manipulation_task_source() - .queue( - task!(send_storage_notification: move || { - let this = this.root(); - let global = this.global(); - let event = StorageEvent::new( - global.as_window(), - atom!("storage"), - EventBubbles::DoesNotBubble, - EventCancelable::NotCancelable, - key.map(DOMString::from), - old_value.map(DOMString::from), - new_value.map(DOMString::from), - DOMString::from(url.into_string()), - Some(&this), - CanGc::note() - ); - event.upcast::().fire(global.upcast(), CanGc::note()); - }), - global.upcast(), - ) + .queue(task!(send_storage_notification: move || { + let this = this.root(); + let global = this.global(); + let event = StorageEvent::new( + global.as_window(), + atom!("storage"), + EventBubbles::DoesNotBubble, + EventCancelable::NotCancelable, + key.map(DOMString::from), + old_value.map(DOMString::from), + new_value.map(DOMString::from), + DOMString::from(url.into_string()), + Some(&this), + CanGc::note() + ); + event.upcast::().fire(global.upcast(), CanGc::note()); + })) .unwrap(); } } diff --git a/components/script/dom/subtlecrypto.rs b/components/script/dom/subtlecrypto.rs index 344643ef3ce..077e367f394 100644 --- a/components/script/dom/subtlecrypto.rs +++ b/components/script/dom/subtlecrypto.rs @@ -40,7 +40,6 @@ use crate::dom::bindings::codegen::UnionTypes::{ }; use crate::dom::bindings::error::{Error, Fallible}; use crate::dom::bindings::import::module::SafeJSContext; -use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::{Trusted, TrustedPromise}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::DomRoot; @@ -49,12 +48,8 @@ use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::cryptokey::{CryptoKey, Handle}; use crate::dom::globalscope::GlobalScope; use crate::dom::promise::Promise; -use crate::dom::window::Window; -use crate::dom::workerglobalscope::WorkerGlobalScope; use crate::realms::InRealm; use crate::script_runtime::{CanGc, JSContext}; -use crate::task::TaskCanceller; -use crate::task_source::TaskSource; // String constants for algorithms/curves const ALG_AES_CBC: &str = "AES-CBC"; @@ -140,20 +135,6 @@ impl SubtleCrypto { CanGc::note(), ) } - - fn task_source_with_canceller(&self) -> (TaskSource, TaskCanceller) { - if let Some(window) = self.global().downcast::() { - window - .task_manager() - .dom_manipulation_task_source_with_canceller() - } else if let Some(worker_global) = self.global().downcast::() { - let task_source = worker_global.task_manager().dom_manipulation_task_source(); - let canceller = worker_global.task_canceller(); - (task_source, canceller) - } else { - unreachable!("Couldn't downcast to Window or WorkerGlobalScope!"); - } - } } impl SubtleCryptoMethods for SubtleCrypto { @@ -181,13 +162,13 @@ impl SubtleCryptoMethods for SubtleCrypto { ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(), }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_key = Trusted::new(key); let key_alg = key.algorithm(); let valid_usage = key.usages().contains(&KeyUsage::Encrypt); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(encrypt: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -206,8 +187,7 @@ impl SubtleCryptoMethods for SubtleCrypto { return; } promise.resolve_native(&*array_buffer_ptr.handle()); - }), - &canceller, + }) ); promise @@ -237,13 +217,13 @@ impl SubtleCryptoMethods for SubtleCrypto { ArrayBufferViewOrArrayBuffer::ArrayBuffer(buffer) => buffer.to_vec(), }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_key = Trusted::new(key); let key_alg = key.algorithm(); let valid_usage = key.usages().contains(&KeyUsage::Decrypt); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(decrypt: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -262,8 +242,7 @@ impl SubtleCryptoMethods for SubtleCrypto { } promise.resolve_native(&*array_buffer_ptr.handle()); - }), - &canceller, + }) ); promise @@ -304,51 +283,48 @@ impl SubtleCryptoMethods for SubtleCrypto { // NOTE: We did that in preparation of Step 4. // Step 6. Return promise and perform the remaining steps in parallel. - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_key = Trusted::new(key); - let _ = task_source.queue_with_canceller( - task!(sign: move || { - // Step 7. If the following steps or referenced procedures say to throw an error, reject promise - // with the returned error and then terminate the algorithm. - let promise = trusted_promise.root(); - let key = trusted_key.root(); + let _ = task_source.queue(task!(sign: move || { + // Step 7. If the following steps or referenced procedures say to throw an error, reject promise + // with the returned error and then terminate the algorithm. + let promise = trusted_promise.root(); + let key = trusted_key.root(); - // Step 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the - // [[algorithm]] internal slot of key then throw an InvalidAccessError. - if normalized_algorithm.name() != key.algorithm() { - promise.reject_error(Error::InvalidAccess); + // Step 8. If the name member of normalizedAlgorithm is not equal to the name attribute of the + // [[algorithm]] internal slot of key then throw an InvalidAccessError. + if normalized_algorithm.name() != key.algorithm() { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", + // then throw an InvalidAccessError. + if !key.usages().contains(&KeyUsage::Sign) { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm + // using key and algorithm and with data as message. + let cx = GlobalScope::get_cx(); + let result = match normalized_algorithm.sign(cx, &key, &data) { + Ok(signature) => signature, + Err(e) => { + promise.reject_error(e); return; } + }; - // Step 9. If the [[usages]] internal slot of key does not contain an entry that is "sign", - // then throw an InvalidAccessError. - if !key.usages().contains(&KeyUsage::Sign) { - promise.reject_error(Error::InvalidAccess); - return; - } + rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::()); + create_buffer_source::(cx, &result, array_buffer_ptr.handle_mut()) + .expect("failed to create buffer source for exported key."); - // Step 10. Let result be the result of performing the sign operation specified by normalizedAlgorithm - // using key and algorithm and with data as message. - let cx = GlobalScope::get_cx(); - let result = match normalized_algorithm.sign(cx, &key, &data) { - Ok(signature) => signature, - Err(e) => { - promise.reject_error(e); - return; - } - }; - - rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::()); - create_buffer_source::(cx, &result, array_buffer_ptr.handle_mut()) - .expect("failed to create buffer source for exported key."); - - // Step 9. Resolve promise with result. - promise.resolve_native(&*array_buffer_ptr); - }), - &canceller, - ); + // Step 9. Resolve promise with result. + promise.resolve_native(&*array_buffer_ptr); + })); promise } @@ -397,47 +373,44 @@ impl SubtleCryptoMethods for SubtleCrypto { // NOTE: We did that in preparation of Step 6. // Step 7. Return promise and perform the remaining steps in parallel. - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_key = Trusted::new(key); - let _ = task_source.queue_with_canceller( - task!(sign: move || { - // Step 8. If the following steps or referenced procedures say to throw an error, reject promise - // with the returned error and then terminate the algorithm. - let promise = trusted_promise.root(); - let key = trusted_key.root(); + let _ = task_source.queue(task!(sign: move || { + // Step 8. If the following steps or referenced procedures say to throw an error, reject promise + // with the returned error and then terminate the algorithm. + let promise = trusted_promise.root(); + let key = trusted_key.root(); - // Step 9. If the name member of normalizedAlgorithm is not equal to the name attribute of the - // [[algorithm]] internal slot of key then throw an InvalidAccessError. - if normalized_algorithm.name() != key.algorithm() { - promise.reject_error(Error::InvalidAccess); + // Step 9. If the name member of normalizedAlgorithm is not equal to the name attribute of the + // [[algorithm]] internal slot of key then throw an InvalidAccessError. + if normalized_algorithm.name() != key.algorithm() { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", + // then throw an InvalidAccessError. + if !key.usages().contains(&KeyUsage::Verify) { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 1. Let result be the result of performing the verify operation specified by normalizedAlgorithm + // using key, algorithm and signature and with data as message. + let cx = GlobalScope::get_cx(); + let result = match normalized_algorithm.verify(cx, &key, &data, &signature) { + Ok(result) => result, + Err(e) => { + promise.reject_error(e); return; } + }; - // Step 10. If the [[usages]] internal slot of key does not contain an entry that is "verify", - // then throw an InvalidAccessError. - if !key.usages().contains(&KeyUsage::Verify) { - promise.reject_error(Error::InvalidAccess); - return; - } - - // Step 1. Let result be the result of performing the verify operation specified by normalizedAlgorithm - // using key, algorithm and signature and with data as message. - let cx = GlobalScope::get_cx(); - let result = match normalized_algorithm.verify(cx, &key, &data, &signature) { - Ok(result) => result, - Err(e) => { - promise.reject_error(e); - return; - } - }; - - // Step 9. Resolve promise with result. - promise.resolve_native(&result); - }), - &canceller, - ); + // Step 9. Resolve promise with result. + promise.resolve_native(&result); + })); promise } @@ -476,10 +449,10 @@ impl SubtleCryptoMethods for SubtleCrypto { // NOTE: We did that in preparation of Step 4. // Step 6. Return promise and perform the remaining steps in parallel. - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(generate_key: move || { // Step 7. If the following steps or referenced procedures say to throw an error, reject promise // with the returned error and then terminate the algorithm. @@ -503,8 +476,7 @@ impl SubtleCryptoMethods for SubtleCrypto { // Step 9. Resolve promise with result. promise.resolve_native(&*array_buffer_ptr); - }), - &canceller, + }) ); promise @@ -529,22 +501,19 @@ impl SubtleCryptoMethods for SubtleCrypto { }, }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( - task!(generate_key: move || { - let subtle = this.root(); - let promise = trusted_promise.root(); - let key = normalized_algorithm.generate_key(&subtle, key_usages, extractable); + let _ = task_source.queue(task!(generate_key: move || { + let subtle = this.root(); + let promise = trusted_promise.root(); + let key = normalized_algorithm.generate_key(&subtle, key_usages, extractable); - match key { - Ok(key) => promise.resolve_native(&key), - Err(e) => promise.reject_error(e), - } - }), - &canceller, - ); + match key { + Ok(key) => promise.resolve_native(&key), + Err(e) => promise.reject_error(e), + } + })); promise } @@ -604,11 +573,11 @@ impl SubtleCryptoMethods for SubtleCrypto { // NOTE: We created the promise earlier, after Step 1. // Step 9. Return promise and perform the remaining steps in parallel. - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_base_key = Trusted::new(base_key); let this = Trusted::new(self); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(derive_key: move || { // Step 10. If the following steps or referenced procedures say to throw an error, reject promise // with the returned error and then terminate the algorithm. @@ -674,7 +643,6 @@ impl SubtleCryptoMethods for SubtleCrypto { // Step 17. Resolve promise with result. promise.resolve_native(&*result); }), - &canceller, ); promise @@ -709,47 +677,44 @@ impl SubtleCryptoMethods for SubtleCrypto { // NOTE: We did that in preparation of Step 3. // Step 5. Return promise and perform the remaining steps in parallel. - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let trusted_promise = TrustedPromise::new(promise.clone()); let trusted_base_key = Trusted::new(base_key); - let _ = task_source.queue_with_canceller( - task!(import_key: move || { - // Step 6. If the following steps or referenced procedures say to throw an error, - // reject promise with the returned error and then terminate the algorithm. + let _ = task_source.queue(task!(import_key: move || { + // Step 6. If the following steps or referenced procedures say to throw an error, + // reject promise with the returned error and then terminate the algorithm. - // TODO Step 7. If the name member of normalizedAlgorithm is not equal to the name attribute - // of the [[algorithm]] internal slot of baseKey then throw an InvalidAccessError. - let promise = trusted_promise.root(); - let base_key = trusted_base_key.root(); + // TODO Step 7. If the name member of normalizedAlgorithm is not equal to the name attribute + // of the [[algorithm]] internal slot of baseKey then throw an InvalidAccessError. + let promise = trusted_promise.root(); + let base_key = trusted_base_key.root(); - // Step 8. If the [[usages]] internal slot of baseKey does not contain an entry that - // is "deriveBits", then throw an InvalidAccessError. - if !base_key.usages().contains(&KeyUsage::DeriveBits) { - promise.reject_error(Error::InvalidAccess); + // Step 8. If the [[usages]] internal slot of baseKey does not contain an entry that + // is "deriveBits", then throw an InvalidAccessError. + if !base_key.usages().contains(&KeyUsage::DeriveBits) { + promise.reject_error(Error::InvalidAccess); + return; + } + + // Step 9. Let result be the result of creating an ArrayBuffer containing the result of performing the + // derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length. + let cx = GlobalScope::get_cx(); + rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::()); + let result = match normalized_algorithm.derive_bits(&base_key, length) { + Ok(derived_bits) => derived_bits, + Err(e) => { + promise.reject_error(e); return; } + }; - // Step 9. Let result be the result of creating an ArrayBuffer containing the result of performing the - // derive bits operation specified by normalizedAlgorithm using baseKey, algorithm and length. - let cx = GlobalScope::get_cx(); - rooted!(in(*cx) let mut array_buffer_ptr = ptr::null_mut::()); - let result = match normalized_algorithm.derive_bits(&base_key, length) { - Ok(derived_bits) => derived_bits, - Err(e) => { - promise.reject_error(e); - return; - } - }; + create_buffer_source::(cx, &result, array_buffer_ptr.handle_mut()) + .expect("failed to create buffer source for derived bits."); - create_buffer_source::(cx, &result, array_buffer_ptr.handle_mut()) - .expect("failed to create buffer source for derived bits."); - - // Step 10. Resolve promise with result. - promise.resolve_native(&*array_buffer_ptr); - }), - &canceller, - ); + // Step 10. Resolve promise with result. + promise.resolve_native(&*array_buffer_ptr); + })); promise } @@ -801,10 +766,10 @@ impl SubtleCryptoMethods for SubtleCrypto { }, }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(import_key: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -814,7 +779,6 @@ impl SubtleCryptoMethods for SubtleCrypto { Err(e) => promise.reject_error(e), }; }), - &canceller, ); promise @@ -830,11 +794,11 @@ impl SubtleCryptoMethods for SubtleCrypto { ) -> Rc { let promise = Promise::new_in_current_realm(comp, can_gc); - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_key = Trusted::new(key); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(export_key: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -872,7 +836,6 @@ impl SubtleCryptoMethods for SubtleCrypto { Err(e) => promise.reject_error(e), } }), - &canceller, ); promise @@ -898,12 +861,12 @@ impl SubtleCryptoMethods for SubtleCrypto { }, }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_key = Trusted::new(key); let trusted_wrapping_key = Trusted::new(wrapping_key); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(wrap_key: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -996,7 +959,6 @@ impl SubtleCryptoMethods for SubtleCrypto { Err(e) => promise.reject_error(e), } }), - &canceller ); promise @@ -1037,11 +999,11 @@ impl SubtleCryptoMethods for SubtleCrypto { }, }; - let (task_source, canceller) = self.task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); let trusted_key = Trusted::new(unwrapping_key); let trusted_promise = TrustedPromise::new(promise.clone()); - let _ = task_source.queue_with_canceller( + let _ = task_source.queue( task!(unwrap_key: move || { let subtle = this.root(); let promise = trusted_promise.root(); @@ -1103,7 +1065,6 @@ impl SubtleCryptoMethods for SubtleCrypto { Err(e) => promise.reject_error(e), } }), - &canceller ); promise diff --git a/components/script/dom/textcontrol.rs b/components/script/dom/textcontrol.rs index 7e94e404d40..6fab849a17c 100644 --- a/components/script/dom/textcontrol.rs +++ b/components/script/dom/textcontrol.rs @@ -300,8 +300,8 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> { // Step 6 if textinput.selection_state() != original_selection_state { - let window = self.element.owner_window(); - window + self.element + .owner_window() .task_manager() .user_interaction_task_source() .queue_event( @@ -309,7 +309,6 @@ impl<'a, E: TextControlElement> TextControlSelection<'a, E> { atom!("select"), EventBubbles::Bubbles, EventCancelable::NotCancelable, - &window, ); } diff --git a/components/script/dom/texttracklist.rs b/components/script/dom/texttracklist.rs index eae7b136cc2..df84fce256f 100644 --- a/components/script/dom/texttracklist.rs +++ b/components/script/dom/texttracklist.rs @@ -63,38 +63,30 @@ impl TextTrackList { self.dom_tracks.borrow_mut().push(Dom::from_ref(track)); let this = Trusted::new(self); - let (source, canceller) = &self - .global() - .as_window() - .task_manager() - .media_element_task_source_with_canceller(); + let task_source = self.global().task_manager().media_element_task_source(); - let idx = match self.find(track) { - Some(t) => t, - None => return, + let Some(idx) = self.find(track) else { + return; }; - let _ = source.queue_with_canceller( - task!(track_event_queue: move || { - let this = this.root(); + let _ = task_source.queue(task!(track_event_queue: move || { + let this = this.root(); - if let Some(track) = this.item(idx) { - let event = TrackEvent::new( - &this.global(), - atom!("addtrack"), - false, - false, - &Some(VideoTrackOrAudioTrackOrTextTrack::TextTrack( - DomRoot::from_ref(&track) - )), - CanGc::note() - ); + if let Some(track) = this.item(idx) { + let event = TrackEvent::new( + &this.global(), + atom!("addtrack"), + false, + false, + &Some(VideoTrackOrAudioTrackOrTextTrack::TextTrack( + DomRoot::from_ref(&track) + )), + CanGc::note() + ); - event.upcast::().fire(this.upcast::(), CanGc::note()); - } - }), - canceller, - ); + event.upcast::().fire(this.upcast::(), CanGc::note()); + } + })); track.add_track_list(self); } } diff --git a/components/script/dom/videotracklist.rs b/components/script/dom/videotracklist.rs index 52a8d212bce..d42bcb24a59 100644 --- a/components/script/dom/videotracklist.rs +++ b/components/script/dom/videotracklist.rs @@ -81,12 +81,8 @@ impl VideoTrackList { return; } - let global = &self.global(); let this = Trusted::new(self); - let (source, canceller) = global - .as_window() - .task_manager() - .media_element_task_source_with_canceller(); + let task_source = self.global().task_manager().media_element_task_source(); if let Some(current) = self.selected_index() { self.tracks.borrow()[current].set_selected(false); @@ -97,13 +93,10 @@ impl VideoTrackList { media_element.set_video_track(idx, value); } - let _ = source.queue_with_canceller( - task!(media_track_change: move || { - let this = this.root(); - this.upcast::().fire_event(atom!("change"), CanGc::note()); - }), - &canceller, - ); + let _ = task_source.queue(task!(media_track_change: move || { + let this = this.root(); + this.upcast::().fire_event(atom!("change"), CanGc::note()); + })); } pub fn add(&self, track: &VideoTrack) { diff --git a/components/script/dom/webglquery.rs b/components/script/dom/webglquery.rs index 1f416a3837d..54d070da6d6 100644 --- a/components/script/dom/webglquery.rs +++ b/components/script/dom/webglquery.rs @@ -171,12 +171,10 @@ impl WebGLQuery { this.update_results(&context); }); - let global = self.global(); - global - .as_window() + self.global() .task_manager() .dom_manipulation_task_source() - .queue(task, global.upcast()) + .queue(task) .unwrap(); } diff --git a/components/script/dom/webglsync.rs b/components/script/dom/webglsync.rs index 5f07c0620a5..1cd3bdf379a 100644 --- a/components/script/dom/webglsync.rs +++ b/components/script/dom/webglsync.rs @@ -59,7 +59,6 @@ impl WebGLSync { ) -> Option { match self.client_wait_status.get() { Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => { - let global = self.global(); let this = Trusted::new(self); let context = Trusted::new(context); let task = task!(request_client_wait_status: move || { @@ -74,11 +73,10 @@ impl WebGLSync { )); this.client_wait_status.set(Some(receiver.recv().unwrap())); }); - global - .as_window() + self.global() .task_manager() .dom_manipulation_task_source() - .queue(task, global.upcast()) + .queue(task) .unwrap(); }, _ => {}, @@ -101,7 +99,6 @@ impl WebGLSync { pub fn get_sync_status(&self, pname: u32, context: &WebGLRenderingContext) -> Option { match self.sync_status.get() { Some(constants::UNSIGNALED) | None => { - let global = self.global(); let this = Trusted::new(self); let context = Trusted::new(context); let task = task!(request_sync_status: move || { @@ -111,11 +108,10 @@ impl WebGLSync { context.send_command(WebGLCommand::GetSyncParameter(this.sync_id, pname, sender)); this.sync_status.set(Some(receiver.recv().unwrap())); }); - global - .as_window() + self.global() .task_manager() .dom_manipulation_task_source() - .queue(task, global.upcast()) + .queue(task) .unwrap(); }, _ => {}, diff --git a/components/script/dom/webgpu/gpu.rs b/components/script/dom/webgpu/gpu.rs index ba4ce6be221..8b1a2dd46a8 100644 --- a/components/script/dom/webgpu/gpu.rs +++ b/components/script/dom/webgpu/gpu.rs @@ -25,7 +25,6 @@ use crate::dom::promise::Promise; use crate::dom::webgpu::gpuadapter::GPUAdapter; use crate::realms::InRealm; use crate::script_runtime::CanGc; -use crate::task_source::TaskSourceName; #[dom_struct] #[allow(clippy::upper_case_acronyms)] @@ -73,9 +72,6 @@ pub fn response_async( .global() .task_manager() .dom_manipulation_task_source(); - let canceller = receiver - .global() - .task_canceller(TaskSourceName::DOMManipulation); let mut trusted: Option = Some(TrustedPromise::new(promise.clone())); let trusted_receiver = Trusted::new(receiver); ROUTER.add_typed_route( @@ -92,12 +88,9 @@ pub fn response_async( trusted, receiver: trusted_receiver.clone(), }; - let result = task_source.queue_with_canceller( - task!(process_webgpu_task: move|| { - context.response(message.unwrap(), CanGc::note()); - }), - &canceller, - ); + let result = task_source.queue(task!(process_webgpu_task: move|| { + context.response(message.unwrap(), CanGc::note()); + })); if let Err(err) = result { error!("Failed to queue GPU listener-task: {:?}", err); } diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 9aa293c29f3..580a7553bf6 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -39,8 +39,8 @@ use crate::dom::eventtarget::EventTarget; use crate::dom::globalscope::GlobalScope; use crate::dom::messageevent::MessageEvent; use crate::script_runtime::CanGc; -use crate::task::{TaskCanceller, TaskOnce}; -use crate::task_source::{TaskSource, TaskSourceName}; +use crate::task::TaskOnce; +use crate::task_source::TaskSource; #[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)] enum WebSocketRequestState { @@ -71,7 +71,6 @@ mod close_code { fn close_the_websocket_connection( address: Trusted, task_source: &TaskSource, - canceller: &TaskCanceller, code: Option, reason: String, ) { @@ -81,21 +80,17 @@ fn close_the_websocket_connection( code, reason: Some(reason), }; - let _ = task_source.queue_with_canceller(close_task, canceller); + let _ = task_source.queue(close_task); } -fn fail_the_websocket_connection( - address: Trusted, - task_source: &TaskSource, - canceller: &TaskCanceller, -) { +fn fail_the_websocket_connection(address: Trusted, task_source: &TaskSource) { let close_task = CloseTask { address, failed: true, code: Some(close_code::ABNORMAL), reason: None, }; - let _ = task_source.queue_with_canceller(close_task, canceller); + let _ = task_source.queue(close_task); } #[dom_struct] @@ -276,7 +271,6 @@ impl WebSocketMethods for WebSocket { .send(CoreResourceMsg::Fetch(request, channels)); 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() { @@ -285,26 +279,20 @@ impl WebSocketMethods for WebSocket { address: address.clone(), protocol_in_use, }; - let _ = task_source.queue_with_canceller(open_thread, &canceller); + let _ = task_source.queue(open_thread); }, WebSocketNetworkEvent::MessageReceived(message) => { let message_thread = MessageReceivedTask { address: address.clone(), message, }; - let _ = task_source.queue_with_canceller(message_thread, &canceller); + let _ = task_source.queue(message_thread); }, WebSocketNetworkEvent::Fail => { - fail_the_websocket_connection(address.clone(), &task_source, &canceller); + fail_the_websocket_connection(address.clone(), &task_source); }, WebSocketNetworkEvent::Close(code, reason) => { - close_the_websocket_connection( - address.clone(), - &task_source, - &canceller, - code, - reason, - ); + close_the_websocket_connection(address.clone(), &task_source, code, reason); }, }), ); @@ -439,15 +427,8 @@ impl WebSocketMethods for WebSocket { self.ready_state.set(WebSocketRequestState::Closing); let address = Trusted::new(self); - // 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().task_manager().websocket_task_source(); - fail_the_websocket_connection( - address, - &task_source, - &self.global().task_canceller(TaskSourceName::WebSocket), - ); + fail_the_websocket_connection(address, &task_source); }, WebSocketRequestState::Open => { self.ready_state.set(WebSocketRequestState::Closing); diff --git a/components/script/dom/webxr/fakexrdevice.rs b/components/script/dom/webxr/fakexrdevice.rs index 04440086f90..a6f194b74a7 100644 --- a/components/script/dom/webxr/fakexrdevice.rs +++ b/components/script/dom/webxr/fakexrdevice.rs @@ -306,10 +306,7 @@ impl FakeXRDeviceMethods for FakeXRDevice { let global = self.global(); let p = Promise::new(&global, can_gc); let mut trusted = Some(TrustedPromise::new(p.clone())); - let (task_source, canceller) = global - .as_window() - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); ROUTER.add_typed_route( @@ -318,7 +315,7 @@ impl FakeXRDeviceMethods for FakeXRDevice { let trusted = trusted .take() .expect("disconnect callback called multiple times"); - let _ = task_source.queue_with_canceller(trusted.resolve_task(()), &canceller); + let _ = task_source.queue(trusted.resolve_task(())); }), ); self.disconnect(sender); diff --git a/components/script/dom/webxr/xrsession.rs b/components/script/dom/webxr/xrsession.rs index f3b8a3ce32c..278a6b34ce7 100644 --- a/components/script/dom/webxr/xrsession.rs +++ b/components/script/dom/webxr/xrsession.rs @@ -201,22 +201,16 @@ impl XRSession { fn setup_raf_loop(&self, frame_receiver: IpcReceiver) { let this = Trusted::new(self); let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); ROUTER.add_typed_route( frame_receiver, Box::new(move |message| { let frame: Frame = message.unwrap(); let time = CrossProcessInstant::now(); let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(xr_raf_callback: move || { - this.root().raf_callback(frame, time); - }), - &canceller, - ); + let _ = task_source.queue(task!(xr_raf_callback: move || { + this.root().raf_callback(frame, time); + })); }), ); @@ -230,22 +224,16 @@ impl XRSession { fn attach_event_handler(&self) { let this = Trusted::new(self); let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); ROUTER.add_typed_route( receiver.to_ipc_receiver(), Box::new(move |message| { let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(xr_event_callback: move || { - this.root().event_callback(message.unwrap(), CanGc::note()); - }), - &canceller, - ); + let _ = task_source.queue(task!(xr_event_callback: move || { + this.root().event_callback(message.unwrap(), CanGc::note()); + })); }), ); @@ -266,21 +254,14 @@ impl XRSession { return; } - let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = self.global().task_manager().dom_manipulation_task_source(); let this = Trusted::new(self); // Queue a task so that it runs after resolve()'s microtasks complete // so that content has a chance to attach a listener for inputsourceschange - let _ = task_source.queue_with_canceller( - task!(session_initial_inputs: move || { - let this = this.root(); - this.input_sources.add_input_sources(&this, &initial_inputs, CanGc::note()); - }), - &canceller, - ); + let _ = task_source.queue(task!(session_initial_inputs: move || { + let this = this.root(); + this.input_sources.add_input_sources(&this, &initial_inputs, CanGc::note()); + })); } fn event_callback(&self, event: XREvent, can_gc: CanGc) { @@ -1055,26 +1036,20 @@ impl XRSessionMethods for XRSession { let this = Trusted::new(self); let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); ROUTER.add_typed_route( receiver.to_ipc_receiver(), Box::new(move |message| { let this = this.clone(); - let _ = task_source.queue_with_canceller( - task!(update_session_framerate: move || { - let session = this.root(); - session.apply_nominal_framerate(message.unwrap(), CanGc::note()); - if let Some(promise) = session.update_framerate_promise.borrow_mut().take() { - promise.resolve_native(&()); - }; - }), - &canceller, - ); + let _ = task_source.queue(task!(update_session_framerate: move || { + let session = this.root(); + session.apply_nominal_framerate(message.unwrap(), CanGc::note()); + if let Some(promise) = session.update_framerate_promise.borrow_mut().take() { + promise.resolve_native(&()); + }; + })); }), ); diff --git a/components/script/dom/webxr/xrsystem.rs b/components/script/dom/webxr/xrsystem.rs index 82bf4e5d37e..079ade9c0d5 100644 --- a/components/script/dom/webxr/xrsystem.rs +++ b/components/script/dom/webxr/xrsystem.rs @@ -118,10 +118,7 @@ impl XRSystemMethods for XRSystem { let promise = Promise::new(&self.global(), can_gc); let mut trusted = Some(TrustedPromise::new(promise.clone())); let global = self.global(); - let window = global.as_window(); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); ROUTER.add_typed_route( receiver.to_ipc_receiver(), @@ -140,15 +137,13 @@ impl XRSystemMethods for XRSystem { return; }; if let Ok(()) = message { - let _ = - task_source.queue_with_canceller(trusted.resolve_task(true), &canceller); + let _ = task_source.queue(trusted.resolve_task(true)); } else { - let _ = - task_source.queue_with_canceller(trusted.resolve_task(false), &canceller); + let _ = task_source.queue(trusted.resolve_task(false)); }; }), ); - if let Some(mut r) = window.webxr_registry() { + if let Some(mut r) = global.as_window().webxr_registry() { r.supports_session(mode.convert(), sender); } @@ -239,9 +234,7 @@ impl XRSystemMethods for XRSystem { let mut trusted = Some(TrustedPromise::new(promise.clone())); let this = Trusted::new(self); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); let (frame_sender, frame_receiver) = ipc_crate::channel().unwrap(); let mut frame_receiver = Some(frame_receiver); @@ -258,12 +251,9 @@ impl XRSystemMethods for XRSystem { error!("requestSession callback given incorrect payload"); return; }; - let _ = task_source.queue_with_canceller( - task!(request_session: move || { - this.root().session_obtained(message, trusted.root(), mode, frame_receiver); - }), - &canceller, - ); + let _ = task_source.queue(task!(request_session: move || { + this.root().session_obtained(message, trusted.root(), mode, frame_receiver); + })); }), ); if let Some(mut r) = window.webxr_registry() { @@ -314,9 +304,7 @@ impl XRSystem { // https://github.com/immersive-web/navigation/issues/10 pub fn dispatch_sessionavailable(&self) { let xr = Trusted::new(self); - let global = self.global(); - let window = global.as_window(); - window + self.global() .task_manager() .dom_manipulation_task_source() .queue( @@ -327,8 +315,7 @@ impl XRSystem { ScriptThread::set_user_interacting(true); xr.upcast::().fire_bubbling_event(atom!("sessionavailable"), CanGc::note()); ScriptThread::set_user_interacting(interacting); - }), - window.upcast(), + }) ) .unwrap(); } diff --git a/components/script/dom/webxr/xrtest.rs b/components/script/dom/webxr/xrtest.rs index b56049b6dff..9f40f92fda9 100644 --- a/components/script/dom/webxr/xrtest.rs +++ b/components/script/dom/webxr/xrtest.rs @@ -147,13 +147,10 @@ impl XRTestMethods for XRTest { }; let global = self.global(); - let window = global.as_window(); let this = Trusted::new(self); let mut trusted = Some(TrustedPromise::new(p.clone())); - let (task_source, canceller) = window - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); let (sender, receiver) = ipc::channel(global.time_profiler_chan().clone()).unwrap(); ROUTER.add_typed_route( @@ -166,15 +163,12 @@ impl XRTestMethods for XRTest { let message = message.expect("SimulateDeviceConnection callback given incorrect payload"); - let _ = task_source.queue_with_canceller( - task!(request_session: move || { - this.root().device_obtained(message, trusted); - }), - &canceller, - ); + let _ = task_source.queue(task!(request_session: move || { + this.root().device_obtained(message, trusted); + })); }), ); - if let Some(mut r) = window.webxr_registry() { + if let Some(mut r) = global.as_window().webxr_registry() { r.simulate_device_connection(init, sender); } @@ -206,10 +200,7 @@ impl XRTestMethods for XRTest { devices.clear(); let mut trusted = Some(TrustedPromise::new(p.clone())); - let (task_source, canceller) = global - .as_window() - .task_manager() - .dom_manipulation_task_source_with_canceller(); + let task_source = global.task_manager().dom_manipulation_task_source(); ROUTER.add_typed_route( receiver.to_ipc_receiver(), @@ -219,8 +210,7 @@ impl XRTestMethods for XRTest { let trusted = trusted .take() .expect("DisconnectAllDevices disconnected more devices than expected"); - let _ = - task_source.queue_with_canceller(trusted.resolve_task(()), &canceller); + let _ = task_source.queue(trusted.resolve_task(())); } }), ); diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 2e2645b72ea..90e221b0ec2 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -11,7 +11,6 @@ use std::default::Default; use std::io::{stderr, stdout, Write}; use std::ptr::NonNull; use std::rc::Rc; -use std::sync::atomic::Ordering; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; @@ -153,12 +152,9 @@ use crate::messaging::{ }; use crate::microtask::MicrotaskQueue; use crate::realms::{enter_realm, InRealm}; -use crate::script_runtime::{ - CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptPort, ScriptThreadEventCategory, -}; +use crate::script_runtime::{CanGc, JSContext, Runtime, ScriptChan, ScriptPort}; use crate::script_thread::ScriptThread; use crate::task_manager::TaskManager; -use crate::task_source::TaskSourceName; use crate::timers::{IsInterval, TimerCallback}; use crate::unminify::unminified_path; use crate::webdriver_handlers::jsval_to_webdriver; @@ -208,7 +204,6 @@ pub struct Window { globalscope: GlobalScope, #[ignore_malloc_size_of = "trait objects are hard"] script_chan: MainThreadScriptChan, - task_manager: TaskManager, #[no_trace] #[ignore_malloc_size_of = "TODO: Add MallocSizeOf support to layout"] layout: RefCell>, @@ -383,10 +378,6 @@ pub struct Window { } impl Window { - pub fn task_manager(&self) -> &TaskManager { - &self.task_manager - } - pub fn layout(&self) -> Ref> { self.layout.borrow() } @@ -411,7 +402,8 @@ impl Window { *self.js_runtime.borrow_for_script_deallocation() = None; self.window_proxy.set(None); self.current_state.set(WindowState::Zombie); - self.ignore_all_tasks(); + self.task_manager() + .cancel_all_tasks_and_ignore_future_tasks(); } } @@ -426,16 +418,8 @@ impl Window { // Step 4 of https://html.spec.whatwg.org/multipage/#discard-a-document // Other steps performed when the `PipelineExit` message // is handled by the ScriptThread. - self.ignore_all_tasks(); - } - - /// Cancel all current, and ignore all subsequently queued, tasks. - pub fn ignore_all_tasks(&self) { - let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut(); - for task_source_name in TaskSourceName::all() { - let flag = ignore_flags.entry(*task_source_name).or_default(); - flag.store(true, Ordering::SeqCst); - } + self.task_manager() + .cancel_all_tasks_and_ignore_future_tasks(); } /// Get a sender to the time profiler thread. @@ -572,6 +556,10 @@ impl Window { pub fn dispatch_event_with_target_override(&self, event: &Event, can_gc: CanGc) -> EventStatus { event.dispatch(self.upcast(), true, can_gc) } + + pub(crate) fn task_manager(&self) -> &TaskManager { + self.upcast::().task_manager() + } } // https://html.spec.whatwg.org/multipage/#atob @@ -825,9 +813,10 @@ impl WindowMethods for Window { window.send_to_constellation(ScriptMsg::DiscardTopLevelBrowsingContext); } }); - self.task_manager() + self.global() + .task_manager() .dom_manipulation_task_source() - .queue(task, self.upcast::()) + .queue(task) .expect("Queuing window_close_browsing_context task to work"); } } @@ -1657,29 +1646,6 @@ impl Window { self.document.get().is_some() } - /// Cancels all the tasks associated with that window. - /// - /// This sets the current `task_manager.task_cancellers` sentinel value to - /// `true` and replaces it with a brand new one for future tasks. - pub fn cancel_all_tasks(&self) { - let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut(); - for task_source_name in TaskSourceName::all() { - let flag = ignore_flags.entry(*task_source_name).or_default(); - let cancelled = std::mem::take(&mut *flag); - cancelled.store(true, Ordering::SeqCst); - } - } - - /// Cancels all the tasks from a given task source. - /// This sets the current sentinel value to - /// `true` and replaces it with a brand new one for future tasks. - pub fn cancel_all_tasks_from_source(&self, task_source_name: TaskSourceName) { - let mut ignore_flags = self.task_manager.task_cancellers.borrow_mut(); - let flag = ignore_flags.entry(task_source_name).or_default(); - let cancelled = std::mem::take(&mut *flag); - cancelled.store(true, Ordering::SeqCst); - } - pub fn clear_js_runtime(&self) { self.upcast::() .remove_web_messaging_and_dedicated_workers_infra(); @@ -1721,7 +1687,8 @@ impl Window { if let Some(performance) = self.performance.get() { performance.clear_and_disable_performance_entry_buffer(); } - self.ignore_all_tasks(); + self.task_manager() + .cancel_all_tasks_and_ignore_future_tasks(); } /// @@ -2368,17 +2335,10 @@ impl Window { CanGc::note()); event.upcast::().fire(this.upcast::(), CanGc::note()); }); - // FIXME(nox): Why are errors silenced here? - let _ = self.script_chan.send(CommonScriptMsg::Task( - ScriptThreadEventCategory::DomEvent, - Box::new( - self.task_manager - .task_canceller(TaskSourceName::DOMManipulation) - .wrap_task(task), - ), - Some(self.pipeline_id()), - TaskSourceName::DOMManipulation, - )); + let _ = self + .task_manager() + .dom_manipulation_task_source() + .queue(task); doc.set_url(load_data.url.clone()); return; } @@ -2715,7 +2675,6 @@ impl Window { pub(crate) fn new( runtime: Rc, script_chan: MainThreadScriptChan, - task_manager: TaskManager, layout: Box, image_cache_chan: Sender, image_cache: Arc, @@ -2726,7 +2685,7 @@ impl Window { devtools_chan: Option>, constellation_chan: ScriptToConstellationChan, control_chan: IpcSender, - pipelineid: PipelineId, + pipeline_id: PipelineId, parent_info: Option, window_size: WindowSizeData, origin: MutableOrigin, @@ -2751,7 +2710,7 @@ impl Window { inherited_secure_context: Option, ) -> DomRoot { let error_reporter = CSSErrorReporter { - pipelineid, + pipelineid: pipeline_id, script_chan: Arc::new(Mutex::new(control_chan)), }; @@ -2762,7 +2721,7 @@ impl Window { let win = Box::new(Self { globalscope: GlobalScope::new_inherited( - pipelineid, + pipeline_id, devtools_chan, mem_profiler_chan, time_profiler_chan, @@ -2779,7 +2738,6 @@ impl Window { unminify_js, ), script_chan, - task_manager, layout: RefCell::new(layout), image_cache_chan, image_cache, @@ -2840,6 +2798,10 @@ impl Window { unsafe { WindowBinding::Wrap(JSContext::from_ptr(runtime.cx()), win) } } + pub(crate) fn event_loop_sender(&self) -> Box { + Box::new(self.script_chan.clone()) + } + pub fn pipeline_id(&self) -> PipelineId { self.upcast::().pipeline_id() } @@ -2983,19 +2945,11 @@ impl Window { ); } }); - // FIXME(nox): Why are errors silenced here? // TODO(#12718): Use the "posted message task source". - // TODO: When switching to the right task source, update the task_canceller call too. - let _ = self.script_chan.send(CommonScriptMsg::Task( - ScriptThreadEventCategory::DomEvent, - Box::new( - self.task_manager - .task_canceller(TaskSourceName::DOMManipulation) - .wrap_task(task), - ), - Some(self.pipeline_id()), - TaskSourceName::DOMManipulation, - )); + let _ = self + .task_manager() + .dom_manipulation_task_source() + .queue(task); } } diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index db9d7e978bf..b2400341809 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -220,12 +220,15 @@ impl WorkerMethods for Worker { let (control_sender, control_receiver) = unbounded(); let (context_sender, context_receiver) = unbounded(); + let event_loop_sender = global + .event_loop_sender() + .expect("Tried to create a worker in a worker while not handling a message?"); let join_handle = DedicatedWorkerGlobalScope::run_worker_scope( init, worker_url, devtools_receiver, worker_ref, - global.script_chan(), + event_loop_sender, sender, receiver, worker_load_origin, diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index abe993ad06a..8e12f182924 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -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::{OnceCell, RefCell, RefMut}; +use std::cell::{RefCell, RefMut}; use std::default::Default; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; @@ -44,13 +44,12 @@ 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::{CustomTraceable, RootedTraceableBox}; +use crate::dom::bindings::trace::RootedTraceableBox; use crate::dom::crypto::Crypto; use crate::dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use crate::dom::globalscope::GlobalScope; use crate::dom::performance::Performance; use crate::dom::promise::Promise; -use crate::dom::serviceworkerglobalscope::ServiceWorkerGlobalScope; #[cfg(feature = "webgpu")] use crate::dom::webgpu::identityhub::IdentityHub; use crate::dom::window::{base64_atob, base64_btoa}; @@ -60,7 +59,6 @@ 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_manager::TaskManager; use crate::timers::{IsInterval, TimerCallback}; pub fn prepare_workerscope_init( @@ -124,13 +122,10 @@ pub struct WorkerGlobalScope { navigation_start: CrossProcessInstant, performance: MutNullableDom, - /// A [`TimerScheduler`] used to schedule timers for this [`ServiceWorkerGlobalScope`]. + /// A [`TimerScheduler`] used to schedule timers for this [`WorkerGlobalScope`]. /// Timers are handled in the service worker event loop. #[no_trace] timer_scheduler: RefCell, - - /// A [`TaskManager`] for this [`WorkerGlobalScope`]. - task_manager: OnceCell, } impl WorkerGlobalScope { @@ -185,7 +180,6 @@ impl WorkerGlobalScope { navigation_start: CrossProcessInstant::now(), performance: Default::default(), timer_scheduler: RefCell::default(), - task_manager: Default::default(), } } @@ -232,12 +226,6 @@ impl WorkerGlobalScope { self.worker_id } - pub fn task_canceller(&self) -> TaskCanceller { - TaskCanceller { - cancelled: self.closing.clone(), - } - } - pub fn pipeline_id(&self) -> PipelineId { self.globalscope.pipeline_id() } @@ -250,6 +238,14 @@ impl WorkerGlobalScope { pub(crate) fn timer_scheduler(&self) -> RefMut { self.timer_scheduler.borrow_mut() } + + /// Return a copy to the shared task canceller that is used to cancel all tasks + /// when this worker is closing. + pub(crate) fn shared_task_canceller(&self) -> TaskCanceller { + TaskCanceller { + cancelled: self.closing.clone(), + } + } } impl WorkerGlobalScopeMethods for WorkerGlobalScope { @@ -495,23 +491,6 @@ impl WorkerGlobalScope { } } - pub fn script_chan(&self) -> Box { - let dedicated = self.downcast::(); - let service_worker = self.downcast::(); - if let Some(dedicated) = dedicated { - dedicated.script_chan() - } else if let Some(service_worker) = service_worker { - return service_worker.script_chan(); - } else { - panic!("need to implement a sender for SharedWorker") - } - } - - 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, Box) { let dedicated = self.downcast::(); if let Some(dedicated) = dedicated { @@ -542,5 +521,8 @@ impl WorkerGlobalScope { pub fn close(&self) { self.closing.store(true, Ordering::SeqCst); + self.upcast::() + .task_manager() + .cancel_all_tasks_and_ignore_future_tasks(); } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index d27fc3c06ca..c833366060f 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -1566,6 +1566,7 @@ impl XMLHttpRequest { sender, pipeline_id: global.pipeline_id(), name: TaskSourceName::Networking, + canceller: Default::default(), }, Some(receiver), ) diff --git a/components/script/image_listener.rs b/components/script/image_listener.rs index b2e5c9e8b80..1f44778172e 100644 --- a/components/script/image_listener.rs +++ b/components/script/image_listener.rs @@ -26,10 +26,7 @@ pub fn generate_cache_listener_for_element< let trusted_node = Trusted::new(elem); let (responder_sender, responder_receiver) = ipc::channel().unwrap(); - let window = elem.owner_window(); - let (task_source, canceller) = window - .task_manager() - .networking_task_source_with_canceller(); + let task_source = elem.owner_window().task_manager().networking_task_source(); let generation = elem.generation_id(); ROUTER.add_typed_route( @@ -38,16 +35,13 @@ pub fn generate_cache_listener_for_element< let element = trusted_node.clone(); let image: PendingImageResponse = message.unwrap(); debug!("Got image {:?}", image); - let _ = task_source.queue_with_canceller( - task!(process_image_response: move || { - let element = element.root(); - // Ignore any image response for a previous request that has been discarded. - if generation == element.generation_id() { - element.process_image_response(image.response, CanGc::note()); - } - }), - &canceller, - ); + let _ = task_source.queue(task!(process_image_response: move || { + let element = element.root(); + // Ignore any image response for a previous request that has been discarded. + if generation == element.generation_id() { + element.process_image_response(image.response, CanGc::note()); + } + })); }), ); diff --git a/components/script/links.rs b/components/script/links.rs index 3dec6c639f9..c7db4105417 100644 --- a/components/script/links.rs +++ b/components/script/links.rs @@ -434,7 +434,7 @@ pub fn follow_hyperlink( target_window .task_manager() .dom_manipulation_task_source() - .queue(task, target_window.upcast()) + .queue(task) .unwrap(); }; } diff --git a/components/script/network_listener.rs b/components/script/network_listener.rs index 407765ddb4b..607dab912c3 100644 --- a/components/script/network_listener.rs +++ b/components/script/network_listener.rs @@ -16,7 +16,7 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::performanceentry::PerformanceEntry; use crate::dom::performanceresourcetiming::{InitiatorType, PerformanceResourceTiming}; use crate::script_runtime::CanGc; -use crate::task::{TaskCanceller, TaskOnce}; +use crate::task::TaskOnce; use crate::task_source::TaskSource; /// An off-thread sink for async network event tasks. All such events are forwarded to @@ -24,7 +24,6 @@ use crate::task_source::TaskSource; pub struct NetworkListener { pub context: Arc>, pub task_source: TaskSource, - pub canceller: Option, } pub trait ResourceTimingListener { @@ -75,15 +74,11 @@ pub fn submit_timing_data( impl NetworkListener { pub fn notify + Send + 'static>(&self, action: A) { - let task = ListenerTask { + let result = self.task_source.queue(ListenerTask { context: self.context.clone(), action, - }; - let result = if let Some(ref canceller) = self.canceller { - self.task_source.queue_with_canceller(task, canceller) - } else { - self.task_source.queue_unconditionally(task) - }; + }); + if let Err(err) = result { warn!("failed to deliver network data: {:?}", err); } diff --git a/components/script/script_module.rs b/components/script/script_module.rs index 63b9527c4e4..8512a3a2c1e 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -75,7 +75,6 @@ use crate::network_listener::{self, NetworkListener, PreInvoke, ResourceTimingLi use crate::realms::{enter_realm, AlreadyInRealm, InRealm}; use crate::script_runtime::{CanGc, JSContext as SafeJSContext}; use crate::task::TaskBox; -use crate::task_source::TaskSourceName; #[allow(unsafe_code)] unsafe fn gen_type_error(global: &GlobalScope, string: String) -> RethrowError { @@ -1768,13 +1767,9 @@ fn fetch_single_module_script( resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), })); - let task_source = global.task_manager().networking_task_source(); - let canceller = global.task_canceller(TaskSourceName::Networking); - let network_listener = NetworkListener { context, - task_source, - canceller: Some(canceller), + task_source: global.task_manager().networking_task_source(), }; match document { Some(document) => { diff --git a/components/script/script_runtime.rs b/components/script/script_runtime.rs index 5c5f3ec8187..ee73a067443 100644 --- a/components/script/script_runtime.rs +++ b/components/script/script_runtime.rs @@ -399,8 +399,7 @@ unsafe extern "C" fn promise_rejection_tracker( ); event.upcast::().fire(&target, CanGc::note()); - }), - global.upcast(), + }) ).unwrap(); }, }; @@ -455,7 +454,7 @@ unsafe extern "C" fn content_security_policy_allows( global .task_manager() .dom_manipulation_task_source() - .queue(task, &global) + .queue(task) .unwrap(); } } @@ -529,8 +528,7 @@ pub fn notify_about_rejected_promises(global: &GlobalScope) { target.global().add_consumed_rejection(promise.reflector().get_jsobject().into_handle()); } } - }), - global.upcast(), + }) ).unwrap(); } } diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index f970d351d35..18f67c5d86c 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -152,7 +152,6 @@ use crate::script_runtime::{ CanGc, CommonScriptMsg, JSContext, Runtime, ScriptChan, ScriptThreadEventCategory, ThreadSafeJSContext, }; -use crate::task_manager::TaskManager; use crate::task_queue::TaskQueue; use crate::task_source::{TaskSource, TaskSourceName}; use crate::{devtools, webdriver_handlers}; @@ -693,7 +692,7 @@ impl ScriptThread { global .task_manager() .dom_manipulation_task_source() - .queue(task, global.upcast()) + .queue(task) .expect("Enqueing navigate js task on the DOM manipulation task source failed"); } else { if let Some(ref sender) = script_thread.senders.devtools_server_sender { @@ -907,6 +906,7 @@ impl ScriptThread { sender: self_sender.as_boxed(), pipeline_id: state.id, name: TaskSourceName::Networking, + canceller: Default::default(), })); let cx = runtime.cx(); @@ -1033,8 +1033,10 @@ impl ScriptThread { fn prepare_for_shutdown_inner(&self) { let docs = self.documents.borrow(); for (_, document) in docs.iter() { - let window = document.window(); - window.ignore_all_tasks(); + document + .window() + .task_manager() + .cancel_all_tasks_and_ignore_future_tasks(); } } @@ -1407,6 +1409,7 @@ impl ScriptThread { // // This task is empty because any new IPC messages in the ScriptThread trigger a // rendering update when animations are not running. + let _realm = enter_realm(&*document); let rendering_task_source = document.window().task_manager().rendering_task_source(); let _ = rendering_task_source.queue_unconditionally(task!(update_the_rendering: move || { })); @@ -3129,10 +3132,6 @@ impl ScriptThread { pipeline_id: incomplete.pipeline_id, }; - let task_manager = TaskManager::new( - Box::new(self.senders.self_sender.clone()), - incomplete.pipeline_id, - ); let paint_time_metrics = PaintTimeMetrics::new( incomplete.pipeline_id, self.senders.time_profiler_sender.clone(), @@ -3161,7 +3160,6 @@ impl ScriptThread { let window = Window::new( self.js_runtime.clone(), self.senders.self_sender.clone(), - task_manager, self.layout_factory.create(layout_config), self.senders.image_cache_sender.clone(), self.image_cache.clone(), diff --git a/components/script/task.rs b/components/script/task.rs index b3200e23afe..ba7c06f00ec 100644 --- a/components/script/task.rs +++ b/components/script/task.rs @@ -67,15 +67,15 @@ impl fmt::Debug for dyn TaskBox { } /// Encapsulated state required to create cancellable tasks from non-script threads. -#[derive(Clone)] +#[derive(Clone, Default, JSTraceable, MallocSizeOf)] pub struct TaskCanceller { + #[ignore_malloc_size_of = "This is difficult, because only one of them should be measured"] pub cancelled: Arc, } impl TaskCanceller { - /// Returns a wrapped `task` that will be cancelled if the `TaskCanceller` - /// says so. - pub fn wrap_task(&self, task: T) -> impl TaskOnce + /// Returns a wrapped `task` that will be cancelled if the `TaskCanceller` says so. + pub(crate) fn wrap_task(&self, task: T) -> impl TaskOnce where T: TaskOnce, { diff --git a/components/script/task_manager.rs b/components/script/task_manager.rs index adcca1c58d6..0bacbbd8bcd 100644 --- a/components/script/task_manager.rs +++ b/components/script/task_manager.rs @@ -2,110 +2,148 @@ * 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 core::cell::RefCell; +use core::sync::atomic::Ordering; use std::collections::HashMap; -use std::sync::atomic::AtomicBool; -use std::sync::Arc; use base::id::PipelineId; -use crate::dom::bindings::cell::DomRefCell; use crate::script_runtime::ScriptChan; use crate::task::TaskCanceller; use crate::task_source::{TaskSource, TaskSourceName}; -macro_rules! task_source_functions { - ($self:ident, $task_source:ident) => { - pub(crate) fn $task_source(&$self) -> TaskSource { - $self.$task_source.clone() - } - }; - ($self:ident, $with_canceller:ident, $task_source:ident) => { - pub(crate) fn $with_canceller(&$self) -> (TaskSource, TaskCanceller) { - ($self.$task_source.clone(), $self.task_canceller($self.$task_source.name)) - } +#[derive(JSTraceable, MallocSizeOf)] +enum TaskCancellers { + /// A shared canceller that is used for workers, which can create multiple TaskManagers, but all + /// of them need to have the same canceller flag for all task sources. + Shared(TaskCanceller), + /// For `Window` each `TaskSource` has its own canceller. + OnePerTaskSource(RefCell>), +} +impl TaskCancellers { + fn get(&self, name: TaskSourceName) -> TaskCanceller { + match self { + Self::Shared(canceller) => canceller.clone(), + Self::OnePerTaskSource(map) => map.borrow_mut().entry(name).or_default().clone(), + } + } + + fn cancel_all_tasks_and_ignore_future_tasks(&self) { + match self { + Self::Shared(canceller) => canceller.cancelled.store(true, Ordering::SeqCst), + Self::OnePerTaskSource(..) => { + // We must create the canceller if they aren't created because we want future + // tasks to be ignored completely. + for task_source_name in TaskSourceName::all() { + self.get(*task_source_name) + .cancelled + .store(true, Ordering::SeqCst) + } + }, + } + } + + fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) { + let Self::OnePerTaskSource(map) = self else { + unreachable!( + "It isn't possible to cancel pending tasks for Worker \ + TaskManager's without ignoring future tasks." + ) + }; + + // Remove the canceller from the map so that the next time a task like this is + // queued, it has a fresh, uncancelled canceller. + if let Some(canceller) = map.borrow_mut().remove(&task_source_name) { + // Cancel any tasks that use the current canceller. + canceller.cancelled.store(true, Ordering::SeqCst); + } + } +} + +macro_rules! task_source_functions { + ($self:ident, $task_source:ident, $task_source_name:ident) => { pub(crate) fn $task_source(&$self) -> TaskSource { - $self.$task_source.clone() + $self.task_source_for_task_source_name(TaskSourceName::$task_source_name) } }; } #[derive(JSTraceable, MallocSizeOf)] pub struct TaskManager { - #[ignore_malloc_size_of = "task sources are hard"] - pub task_cancellers: DomRefCell>>, - dom_manipulation_task_source: TaskSource, - file_reading_task_source: TaskSource, - gamepad_task_source: TaskSource, - history_traversal_task_source: TaskSource, - media_element_task_source: TaskSource, - networking_task_source: TaskSource, - performance_timeline_task_source: TaskSource, - port_message_queue: TaskSource, - user_interaction_task_source: TaskSource, - remote_event_task_source: TaskSource, - rendering_task_source: TaskSource, - timer_task_source: TaskSource, - websocket_task_source: TaskSource, + #[ignore_malloc_size_of = "We need to push the measurement of this down into the ScriptChan trait"] + sender: RefCell>>, + #[no_trace] + pipeline_id: PipelineId, + cancellers: TaskCancellers, } impl TaskManager { - #[allow(clippy::too_many_arguments)] - pub(crate) fn new(sender: Box, pipeline_id: PipelineId) -> Self { - let task_source = |name| TaskSource { - sender: sender.as_boxed(), - pipeline_id, - name, + pub(crate) fn new( + sender: Option>, + pipeline_id: PipelineId, + shared_canceller: Option, + ) -> Self { + let cancellers = match shared_canceller { + Some(shared_canceller) => TaskCancellers::Shared(shared_canceller), + None => TaskCancellers::OnePerTaskSource(Default::default()), }; + let sender = RefCell::new(sender); TaskManager { - dom_manipulation_task_source: task_source(TaskSourceName::DOMManipulation), - file_reading_task_source: task_source(TaskSourceName::FileReading), - gamepad_task_source: task_source(TaskSourceName::Gamepad), - history_traversal_task_source: task_source(TaskSourceName::HistoryTraversal), - media_element_task_source: task_source(TaskSourceName::MediaElement), - networking_task_source: task_source(TaskSourceName::Networking), - performance_timeline_task_source: task_source(TaskSourceName::PerformanceTimeline), - port_message_queue: task_source(TaskSourceName::PortMessage), - user_interaction_task_source: task_source(TaskSourceName::UserInteraction), - remote_event_task_source: task_source(TaskSourceName::RemoteEvent), - rendering_task_source: task_source(TaskSourceName::Rendering), - timer_task_source: task_source(TaskSourceName::Timer), - websocket_task_source: task_source(TaskSourceName::WebSocket), - task_cancellers: Default::default(), + sender, + pipeline_id, + cancellers, } } - task_source_functions!( - self, - dom_manipulation_task_source_with_canceller, - dom_manipulation_task_source - ); - task_source_functions!(self, gamepad_task_source); - task_source_functions!( - self, - media_element_task_source_with_canceller, - media_element_task_source - ); - task_source_functions!(self, user_interaction_task_source); - task_source_functions!( - self, - networking_task_source_with_canceller, - networking_task_source - ); - task_source_functions!(self, file_reading_task_source); - task_source_functions!(self, performance_timeline_task_source); - task_source_functions!(self, port_message_queue); - task_source_functions!(self, remote_event_task_source); - task_source_functions!(self, rendering_task_source); - task_source_functions!(self, timer_task_source); - task_source_functions!(self, websocket_task_source); + fn task_source_for_task_source_name(&self, name: TaskSourceName) -> TaskSource { + let Some(sender) = self + .sender + .borrow() + .as_ref() + .map(|sender| sender.as_boxed()) + else { + unreachable!("Tried to enqueue task for DedicatedWorker while not handling a message.") + }; - pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller { - let mut flags = self.task_cancellers.borrow_mut(); - let cancel_flag = flags.entry(name).or_default(); - TaskCanceller { - cancelled: cancel_flag.clone(), + TaskSource { + sender, + pipeline_id: self.pipeline_id, + name, + canceller: self.cancellers.get(name), } } + + /// Update the sender for this [`TaskSource`]. This is used by dedicated workers, which only have a + /// sender while handling messages (as their sender prevents the main thread Worker object from being + /// garbage collected). + pub(crate) fn set_sender(&self, sender: Option>) { + *self.sender.borrow_mut() = sender; + } + + /// Cancel all queued but unexecuted tasks and ignore all subsequently queued tasks. + pub(crate) fn cancel_all_tasks_and_ignore_future_tasks(&self) { + self.cancellers.cancel_all_tasks_and_ignore_future_tasks(); + } + + /// Cancel all queued but unexecuted tasks for the given task source, but subsequently queued + /// tasks will not be ignored. + pub(crate) fn cancel_pending_tasks_for_source(&self, task_source_name: TaskSourceName) { + self.cancellers + .cancel_pending_tasks_for_source(task_source_name); + } + + task_source_functions!(self, dom_manipulation_task_source, DOMManipulation); + task_source_functions!(self, file_reading_task_source, FileReading); + task_source_functions!(self, gamepad_task_source, Gamepad); + task_source_functions!(self, media_element_task_source, MediaElement); + task_source_functions!(self, networking_task_source, Networking); + task_source_functions!(self, performance_timeline_task_source, PerformanceTimeline); + task_source_functions!(self, port_message_queue, PortMessage); + task_source_functions!(self, remote_event_task_source, RemoteEvent); + task_source_functions!(self, rendering_task_source, Rendering); + task_source_functions!(self, timer_task_source, Timer); + task_source_functions!(self, user_interaction_task_source, UserInteraction); + task_source_functions!(self, websocket_task_source, WebSocket); } diff --git a/components/script/task_source.rs b/components/script/task_source.rs index 224357c4f67..733e01c931c 100644 --- a/components/script/task_source.rs +++ b/components/script/task_source.rs @@ -9,12 +9,9 @@ use base::id::PipelineId; use malloc_size_of_derive::MallocSizeOf; use servo_atoms::Atom; -use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::refcounted::Trusted; use crate::dom::event::{EventBubbles, EventCancelable, EventTask, SimpleEventTask}; use crate::dom::eventtarget::EventTarget; -use crate::dom::types::GlobalScope; -use crate::dom::window::Window; use crate::script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory}; use crate::task::{TaskCanceller, TaskOnce}; @@ -92,34 +89,23 @@ pub(crate) struct TaskSource { #[no_trace] pub pipeline_id: PipelineId, pub name: TaskSourceName, + pub canceller: TaskCanceller, } impl TaskSource { - pub(crate) fn queue_with_canceller( - &self, - task: T, - canceller: &TaskCanceller, - ) -> Result<(), ()> + pub(crate) fn queue(&self, task: T) -> Result<(), ()> where T: TaskOnce + 'static, { let msg = CommonScriptMsg::Task( self.name.into(), - Box::new(canceller.wrap_task(task)), + Box::new(self.canceller.wrap_task(task)), Some(self.pipeline_id), self.name, ); self.sender.send(msg).map_err(|_| ()) } - pub(crate) fn queue(&self, task: T, global: &GlobalScope) -> Result<(), ()> - where - T: TaskOnce + 'static, - { - let canceller = global.task_canceller(self.name); - self.queue_with_canceller(task, &canceller) - } - /// This queues a task that will not be cancelled when its associated global scope gets destroyed. pub(crate) fn queue_unconditionally(&self, task: T) -> Result<(), ()> where @@ -133,9 +119,9 @@ impl TaskSource { )) } - pub(crate) fn queue_simple_event(&self, target: &EventTarget, name: Atom, window: &Window) { + pub(crate) fn queue_simple_event(&self, target: &EventTarget, name: Atom) { let target = Trusted::new(target); - let _ = self.queue(SimpleEventTask { target, name }, window.upcast()); + let _ = self.queue(SimpleEventTask { target, name }); } pub(crate) fn queue_event( @@ -144,16 +130,14 @@ impl TaskSource { name: Atom, bubbles: EventBubbles, cancelable: EventCancelable, - window: &Window, ) { let target = Trusted::new(target); - let task = EventTask { + let _ = self.queue(EventTask { target, name, bubbles, cancelable, - }; - let _ = self.queue(task, window.upcast()); + }); } } @@ -163,6 +147,7 @@ impl Clone for TaskSource { sender: self.sender.as_boxed(), pipeline_id: self.pipeline_id, name: self.name, + canceller: self.canceller.clone(), } } }