From b3e85472eda2a017334a9faa3b33a3b4e0184e53 Mon Sep 17 00:00:00 2001 From: Agustin Chiappe Berrini Date: Sat, 8 Sep 2018 18:02:00 -0400 Subject: [PATCH] Fix space leak when pipeline is closed Add a new control message to drop remove worklets. Implement `Drop` for `Worklet` and get the worklet thread pool. Use that pool to send `ExitWorklet` to all the threads with the id of the `Worklet` that it's dropping. --- components/script/dom/worklet.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/components/script/dom/worklet.rs b/components/script/dom/worklet.rs index d1b7ba9c44ad..68efd51b4853 100644 --- a/components/script/dom/worklet.rs +++ b/components/script/dom/worklet.rs @@ -147,6 +147,13 @@ impl WorkletMethods for Worklet { } } +impl Drop for Worklet { + fn drop(&mut self) { + let script_thread = ScriptThread::worklet_thread_pool(); + script_thread.exit_worklet(self.worklet_id); + } +} + /// A guid for worklets. #[derive(Clone, Copy, Debug, Eq, Hash, JSTraceable, PartialEq)] pub struct WorkletId(Uuid); @@ -301,10 +308,14 @@ impl WorkletThreadPool { promise: TrustedPromise::new(promise.clone()), }); } - // If any of the threads are blocked waiting on data, wake them up. - let _ = self.cold_backup_sender.send(WorkletData::WakeUp); - let _ = self.hot_backup_sender.send(WorkletData::WakeUp); - let _ = self.primary_sender.send(WorkletData::WakeUp); + self.wake_threads(); + } + + pub(crate) fn exit_worklet(&self, worklet_id: WorkletId) { + for sender in &[&self.control_sender_0, &self.control_sender_1, &self.control_sender_2] { + let _ = sender.send(WorkletControl::ExitWorklet(worklet_id)); + } + self.wake_threads(); } /// For testing. @@ -314,6 +325,13 @@ impl WorkletThreadPool { let _ = self.primary_sender.send(msg); receiver.recv().expect("Test worklet has died?") } + + fn wake_threads(&self) { + // If any of the threads are blocked waiting on data, wake them up. + let _ = self.cold_backup_sender.send(WorkletData::WakeUp); + let _ = self.hot_backup_sender.send(WorkletData::WakeUp); + let _ = self.primary_sender.send(WorkletData::WakeUp); + } } /// The data messages sent to worklet threads @@ -327,6 +345,7 @@ enum WorkletData { /// The control message sent to worklet threads enum WorkletControl { + ExitWorklet(WorkletId), FetchAndInvokeAWorkletScript { pipeline_id: PipelineId, worklet_id: WorkletId, @@ -621,6 +640,9 @@ impl WorkletThread { /// Process a control message. fn process_control(&mut self, control: WorkletControl) { match control { + WorkletControl::ExitWorklet(worklet_id) => { + self.global_scopes.remove(&worklet_id); + }, WorkletControl::FetchAndInvokeAWorkletScript { pipeline_id, worklet_id, global_type, origin, base_url, script_url, credentials, pending_tasks_struct, promise,