servo: Merge #12277 - Make network listener runnable cancellable (from cbrewster:network_listener_cancellable); r=Manishearth
authorConnor Brewster <connor.brewster@eagles.oc.edu>
Fri, 08 Jul 2016 09:56:31 -0700
changeset 339246 a77e642115df79703e77c50ce47f4ccaaca75bf7
parent 339245 d1ccc5b02bd171c220a7b136305ceac977274c19
child 339247 1e1b6706a4c8f1032bf6894686c794b28fba26c9
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
servo: Merge #12277 - Make network listener runnable cancellable (from cbrewster:network_listener_cancellable); r=Manishearth <!-- Please describe your changes on the following line: --> This keeps scripts from executing after its script thread has been shut down. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [x] These changes fix (maybe) #12048 (github issue number if applicable). <!-- Either: --> - [X] There are tests for these changes OR - [ ] These changes do not require tests because _____ <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> Source-Repo: https://github.com/servo/servo Source-Revision: 12260b24d0e97ee33116d4b730203e5a2619a499
servo/components/script/dom/htmllinkelement.rs
servo/components/script/dom/htmlmediaelement.rs
servo/components/script/dom/htmlscriptelement.rs
servo/components/script/dom/window.rs
servo/components/script/dom/xmlhttprequest.rs
servo/components/script/network_listener.rs
servo/components/script/script_thread.rs
--- a/servo/components/script/dom/htmllinkelement.rs
+++ b/servo/components/script/dom/htmllinkelement.rs
@@ -221,16 +221,17 @@ impl HTMLLinkElement {
                     metadata: None,
                     url: url.clone(),
                 }));
 
                 let (action_sender, action_receiver) = ipc::channel().unwrap();
                 let listener = NetworkListener {
                     context: context,
                     script_chan: document.window().networking_task_source(),
+                    wrapper: Some(document.window().get_runnable_wrapper()),
                 };
                 let response_target = AsyncResponseTarget {
                     sender: action_sender,
                 };
                 ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
                     listener.notify_action(message.to().unwrap());
                 });
 
--- a/servo/components/script/dom/htmlmediaelement.rs
+++ b/servo/components/script/dom/htmlmediaelement.rs
@@ -468,20 +468,22 @@ impl HTMLMediaElement {
 
                 // TODO 4.1.5-7 (state for load that initiates later)
                 return;
             }
 
             // 4.2
             let context = Arc::new(Mutex::new(HTMLMediaElementContext::new(self, url.clone())));
             let (action_sender, action_receiver) = ipc::channel().unwrap();
-            let script_chan = window_from_node(self).networking_task_source();
+            let window = window_from_node(self);
+            let script_chan = window.networking_task_source();
             let listener = box NetworkListener {
                 context: context,
                 script_chan: script_chan,
+                wrapper: Some(window.get_runnable_wrapper()),
             };
 
             let response_target = AsyncResponseTarget {
                 sender: action_sender,
             };
             ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
                 listener.notify_action(message.to().unwrap());
             });
--- a/servo/components/script/dom/htmlscriptelement.rs
+++ b/servo/components/script/dom/htmlscriptelement.rs
@@ -303,16 +303,17 @@ impl HTMLScriptElement {
                     url: url.clone(),
                     status: Ok(())
                 }));
 
                 let (action_sender, action_receiver) = ipc::channel().unwrap();
                 let listener = NetworkListener {
                     context: context,
                     script_chan: doc.window().networking_task_source(),
+                    wrapper: Some(doc.window().get_runnable_wrapper()),
                 };
                 let response_target = AsyncResponseTarget {
                     sender: action_sender,
                 };
                 ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
                     listener.notify_action(message.to().unwrap());
                 });
 
--- a/servo/components/script/dom/window.rs
+++ b/servo/components/script/dom/window.rs
@@ -944,17 +944,17 @@ impl Window {
         // send a message to free their layout data to the
         // layout thread when the script thread is dropped,
         // which causes a panic!
         self.Gc();
 
         self.current_state.set(WindowState::Zombie);
         *self.js_runtime.borrow_mut() = None;
         self.browsing_context.set(None);
-        self.ignore_further_async_events.store(true, Ordering::Relaxed);
+        self.ignore_further_async_events.store(true, Ordering::SeqCst);
     }
 
     /// https://drafts.csswg.org/cssom-view/#dom-window-scroll
     pub fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) {
         // Step 3
         let xfinite = if x_.is_finite() { x_ } else { 0.0f64 };
         let yfinite = if y_.is_finite() { y_ } else { 0.0f64 };
 
--- a/servo/components/script/dom/xmlhttprequest.rs
+++ b/servo/components/script/dom/xmlhttprequest.rs
@@ -253,16 +253,17 @@ impl XMLHttpRequest {
                 self.xhr.root().generation_id.get() == self.gen_id
             }
         }
 
         let (action_sender, action_receiver) = ipc::channel().unwrap();
         let listener = NetworkListener {
             context: context,
             script_chan: script_chan,
+            wrapper: None,
         };
         ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
             listener.notify_fetch(message.to().unwrap());
         });
         core_resource_thread.send(Fetch(init, action_sender)).unwrap();
     }
 }
 
--- a/servo/components/script/network_listener.rs
+++ b/servo/components/script/network_listener.rs
@@ -1,33 +1,43 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use net_traits::{Action, AsyncResponseListener, FetchResponseListener};
 use net_traits::{FetchResponseMsg, ResponseAction};
 use script_runtime::ScriptThreadEventCategory::NetworkEvent;
 use script_runtime::{CommonScriptMsg, ScriptChan};
-use script_thread::Runnable;
+use script_thread::{Runnable, RunnableWrapper};
 use std::sync::{Arc, Mutex};
 
 /// An off-thread sink for async network event runnables. All such events are forwarded to
 /// a target thread, where they are invoked on the provided context object.
 pub struct NetworkListener<Listener: PreInvoke + Send + 'static> {
     pub context: Arc<Mutex<Listener>>,
     pub script_chan: Box<ScriptChan + Send>,
+    pub wrapper: Option<RunnableWrapper>,
 }
 
 impl<Listener: PreInvoke + Send + 'static> NetworkListener<Listener> {
     pub fn notify<A: Action<Listener> + Send + 'static>(&self, action: A) {
-        if let Err(err) = self.script_chan.send(CommonScriptMsg::RunnableMsg(NetworkEvent, box ListenerRunnable {
+        let runnable = ListenerRunnable {
             context: self.context.clone(),
             action: action,
-        })) {
-            warn!("failed to deliver network data: {:?}", err);
+        };
+        if let Some(ref wrapper) = self.wrapper {
+            if let Err(err) = self.script_chan.send(
+                CommonScriptMsg::RunnableMsg(NetworkEvent, wrapper.wrap_runnable(runnable))) {
+                warn!("failed to deliver network data: {:?}", err);
+            }
+        } else {
+            if let Err(err) = self.script_chan.send(
+                CommonScriptMsg::RunnableMsg(NetworkEvent, box runnable)) {
+                warn!("failed to deliver network data: {:?}", err);
+            }
         }
     }
 }
 
 // helps type inference
 impl<Listener: AsyncResponseListener + PreInvoke + Send + 'static> NetworkListener<Listener> {
     pub fn notify_action(&self, action: ResponseAction) {
         self.notify(action);
--- a/servo/components/script/script_thread.rs
+++ b/servo/components/script/script_thread.rs
@@ -185,17 +185,17 @@ impl RunnableWrapper {
 /// A runnable that can be discarded by toggling a shared flag.
 pub struct CancellableRunnable<T: Runnable + Send> {
     cancelled: Arc<AtomicBool>,
     inner: Box<T>,
 }
 
 impl<T: Runnable + Send> Runnable for CancellableRunnable<T> {
     fn is_cancelled(&self) -> bool {
-        self.cancelled.load(Ordering::Relaxed)
+        self.cancelled.load(Ordering::SeqCst)
     }
 
     fn handler(self: Box<CancellableRunnable<T>>) {
         self.inner.handler()
     }
 }
 
 pub trait Runnable {
@@ -2050,16 +2050,17 @@ impl ScriptThread {
         let id = incomplete.pipeline_id.clone();
         let subpage = incomplete.parent_info.clone().map(|p| p.1);
 
         let context = Arc::new(Mutex::new(ParserContext::new(id, subpage, load_data.url.clone())));
         let (action_sender, action_receiver) = ipc::channel().unwrap();
         let listener = NetworkListener {
             context: context,
             script_chan: self.chan.clone(),
+            wrapper: None,
         };
         ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
             listener.notify_action(message.to().unwrap());
         });
         let response_target = AsyncResponseTarget {
             sender: action_sender,
         };