introduce "per task source" ignoring of tasks

This commit is contained in:
Gregory Terzian 2018-07-05 12:33:09 +08:00
parent ce430566cd
commit 671627e97e
21 changed files with 127 additions and 34 deletions

21
Cargo.lock generated
View file

@ -861,6 +861,24 @@ dependencies = [
"libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"enum-iterator-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum-iterator-derive"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "enum_primitive"
version = "0.1.1"
@ -2587,6 +2605,7 @@ dependencies = [
"domobject_derive 0.0.1",
"embedder_traits 0.0.1",
"encoding_rs 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"enum-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"gleam 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3893,6 +3912,8 @@ dependencies = [
"checksum energymon-builder 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
"checksum energymon-default-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
"checksum energymon-sys 0.3.0 (git+https://github.com/energymon/energymon-sys.git)" = "<none>"
"checksum enum-iterator 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85012092e543e198a02f3ac3d587798253e8ec374bc9c3d7da5319cf579ea4c6"
"checksum enum-iterator-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "719423964c7a03e4ce4c67115d6e44a5b2dd9b51789a575dfbad68b490b0f0a0"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0561146661ae44c579e993456bc76d11ce1e0c7d745e57b2fa7146b6e49fa2ad"
"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"

View file

@ -44,6 +44,7 @@ dom_struct = {path = "../dom_struct"}
domobject_derive = {path = "../domobject_derive"}
embedder_traits = {path = "../embedder_traits"}
encoding_rs = "0.7"
enum-iterator = "0.2.0"
euclid = "0.17"
fnv = "1.0"
gleam = "0.5"

View file

@ -34,7 +34,7 @@ use std::cell::Cell;
use std::mem;
use std::str::{Chars, FromStr};
use std::sync::{Arc, Mutex};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
use timers::OneshotTimerCallback;
use utf8;
@ -482,10 +482,12 @@ impl EventSource {
data: String::new(),
last_event_id: String::new(),
};
// TODO: use the "remote event task source", and canceller.
// https://html.spec.whatwg.org/multipage/#remote-event-task-source
let listener = NetworkListener {
context: Arc::new(Mutex::new(context)),
task_source: global.networking_task_source(),
canceller: Some(global.task_canceller())
canceller: Some(global.task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -35,7 +35,7 @@ use std::ptr;
use std::sync::Arc;
use std::thread;
use task::TaskCanceller;
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
use task_source::file_reading::{FileReadingTask, FileReadingTaskSource};
#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
@ -452,7 +452,7 @@ impl FileReader {
let gen_id = self.generation_id.get();
let global = self.global();
let canceller = global.task_canceller();
let canceller = global.task_canceller(TaskSourceName::FileReading);
let task_source = global.file_reading_task_source();
thread::Builder::new()

View file

@ -52,6 +52,7 @@ use std::rc::Rc;
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use task::TaskCanceller;
use task_source::TaskSourceName;
use task_source::file_reading::FileReadingTaskSource;
use task_source::networking::NetworkingTaskSource;
use task_source::performance_timeline::PerformanceTimelineTaskSource;
@ -508,11 +509,14 @@ impl GlobalScope {
/// 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) -> TaskCanceller {
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller {
if let Some(window) = self.downcast::<Window>() {
return window.task_canceller();
return window.task_canceller(name);
}
if let Some(worker) = self.downcast::<WorkerGlobalScope>() {
// 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!();

View file

@ -58,7 +58,7 @@ use std::i32;
use std::sync::{Arc, Mutex};
use style::attr::{AttrValue, LengthOrPercentageOrAuto, parse_double, parse_unsigned_integer};
use style::str::is_ascii_digit;
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
enum ParseState {
InDescriptor,
@ -185,7 +185,7 @@ impl HTMLImageElement {
let window = window_from_node(elem);
let task_source = window.networking_task_source();
let task_canceller = window.task_canceller();
let task_canceller = window.task_canceller(TaskSourceName::Networking);
let generation = elem.generation.get();
ROUTER.add_route(responder_receiver.to_opaque(), Box::new(move |message| {
debug!("Got image {:?}", message);
@ -253,7 +253,7 @@ impl HTMLImageElement {
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller()),
canceller: Some(window.task_canceller(TaskSourceName::Networking)),
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -46,7 +46,7 @@ use std::collections::VecDeque;
use std::mem;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
use time::{self, Timespec, Duration};
#[dom_struct]
@ -608,7 +608,7 @@ impl HTMLMediaElement {
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller())
canceller: Some(window.task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -41,6 +41,7 @@ use std::path::PathBuf;
use std::process::{Command, Stdio};
use std::sync::{Arc, Mutex};
use style::str::{HTML_SPACE_CHARACTERS, StaticStringVec};
use task_source::TaskSourceName;
use uuid::Uuid;
#[dom_struct]
@ -273,7 +274,7 @@ fn fetch_a_classic_script(script: &HTMLScriptElement,
let listener = NetworkListener {
context: context,
task_source: doc.window().networking_task_source(),
canceller: Some(doc.window().task_canceller())
canceller: Some(doc.window().task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {

View file

@ -39,7 +39,7 @@ use std::cell::Cell;
use std::ptr;
use std::thread;
use task::{TaskOnce, TaskCanceller};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
use task_source::networking::NetworkingTaskSource;
#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
@ -199,8 +199,11 @@ impl WebSocket {
};
let _ = global.core_resource_thread().send(CoreResourceMsg::Fetch(request, channels));
// 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 = global.networking_task_source();
let canceller = global.task_canceller();
let canceller = global.task_canceller(TaskSourceName::Networking);
thread::spawn(move || {
while let Ok(event) = dom_event_receiver.recv() {
match event {
@ -391,8 +394,13 @@ 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().networking_task_source();
fail_the_websocket_connection(address, &task_source, &self.global().task_canceller());
fail_the_websocket_connection(address,
&task_source,
&self.global().task_canceller(TaskSourceName::Networking));
}
WebSocketRequestState::Open => {
self.ready_state.set(WebSocketRequestState::Closing);

View file

@ -109,6 +109,7 @@ use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::CssRuleType;
use style_traits::{CSSPixel, DevicePixel, ParsingMode};
use task::TaskCanceller;
use task_source::TaskSourceName;
use task_source::dom_manipulation::DOMManipulationTaskSource;
use task_source::file_reading::FileReadingTaskSource;
use task_source::history_traversal::HistoryTraversalTaskSource;
@ -246,9 +247,9 @@ pub struct Window {
current_viewport: Cell<Rect<Au>>,
/// A flag to prevent async events from attempting to interact with this window.
/// A map of flags to prevent events from a given task source from attempting to interact with this window.
#[ignore_malloc_size_of = "defined in std"]
ignore_further_async_events: DomRefCell<Arc<AtomicBool>>,
ignore_further_async_events: DomRefCell<HashMap<TaskSourceName, Arc<AtomicBool>>>,
error_reporter: CSSErrorReporter,
@ -308,7 +309,15 @@ impl Window {
*self.js_runtime.borrow_for_script_deallocation() = None;
self.window_proxy.set(None);
self.current_state.set(WindowState::Zombie);
self.ignore_further_async_events.borrow().store(true, Ordering::Relaxed);
self.ignore_all_events();
}
}
fn ignore_all_events(&self) {
let mut ignore_flags = self.ignore_further_async_events.borrow_mut();
for task_source_name in TaskSourceName::all() {
let flag = ignore_flags.entry(task_source_name).or_insert(Default::default());
flag.store(true, Ordering::Relaxed);
}
}
@ -1065,9 +1074,11 @@ impl Window {
self.paint_worklet.or_init(|| self.new_paint_worklet())
}
pub fn task_canceller(&self) -> TaskCanceller {
pub fn task_canceller(&self, name: TaskSourceName) -> TaskCanceller {
let mut flags = self.ignore_further_async_events.borrow_mut();
let cancel_flag = flags.entry(name).or_insert(Default::default());
TaskCanceller {
cancelled: Some(self.ignore_further_async_events.borrow().clone()),
cancelled: Some(cancel_flag.clone()),
}
}
@ -1084,8 +1095,12 @@ impl Window {
/// This sets the current `ignore_further_async_events` sentinel value to
/// `true` and replaces it with a brand new one for future tasks.
pub fn cancel_all_tasks(&self) {
let cancelled = mem::replace(&mut *self.ignore_further_async_events.borrow_mut(), Default::default());
cancelled.store(true, Ordering::Relaxed);
let mut ignore_flags = self.ignore_further_async_events.borrow_mut();
for task_source_name in TaskSourceName::all() {
let mut flag = ignore_flags.entry(task_source_name).or_insert(Default::default());
let cancelled = mem::replace(&mut *flag, Default::default());
cancelled.store(true, Ordering::Relaxed);
}
}
pub fn clear_js_runtime(&self) {
@ -1117,7 +1132,7 @@ impl Window {
self.current_state.set(WindowState::Zombie);
*self.js_runtime.borrow_mut() = None;
self.window_proxy.set(None);
self.ignore_further_async_events.borrow().store(true, Ordering::SeqCst);
self.ignore_all_events();
}
/// <https://drafts.csswg.org/cssom-view/#dom-window-scroll>
@ -1998,9 +2013,10 @@ 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_canceller().wrap_task(task)),
Box::new(self.task_canceller(TaskSourceName::DOMManipulation).wrap_task(task)),
self.pipeline_id()
));
}

View file

@ -70,6 +70,7 @@ use std::ptr::NonNull;
use std::slice;
use std::str;
use std::sync::{Arc, Mutex};
use task_source::TaskSourceName;
use task_source::networking::NetworkingTaskSource;
use time;
use timers::{OneshotTimerCallback, OneshotTimerHandle};
@ -268,7 +269,7 @@ impl XMLHttpRequest {
let listener = NetworkListener {
context: context,
task_source: task_source,
canceller: Some(global.task_canceller())
canceller: Some(global.task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -31,6 +31,7 @@ use servo_url::ServoUrl;
use std::mem;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
use task_source::TaskSourceName;
struct FetchContext {
fetch_promise: Option<TrustedPromise>,
@ -154,7 +155,7 @@ pub fn Fetch(global: &GlobalScope, input: RequestInfo, init: RootedTraceableBox<
let listener = NetworkListener {
context: fetch_context,
task_source: global.networking_task_source(),
canceller: Some(global.task_canceller())
canceller: Some(global.task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {

View file

@ -17,6 +17,7 @@ use net_traits::request::{Destination, RequestInit as FetchRequestInit};
use network_listener::{NetworkListener, PreInvoke};
use servo_url::ServoUrl;
use std::sync::{Arc, Mutex};
use task_source::TaskSourceName;
struct LayoutImageContext {
id: PendingImageId,
@ -62,7 +63,7 @@ pub fn fetch_image_for_layout(url: ServoUrl,
let listener = NetworkListener {
context: context,
task_source: window.networking_task_source(),
canceller: Some(window.task_canceller()),
canceller: Some(window.task_canceller(TaskSourceName::Networking)),
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -37,6 +37,7 @@ extern crate dom_struct;
extern crate domobject_derive;
extern crate embedder_traits;
extern crate encoding_rs;
#[macro_use] extern crate enum_iterator;
extern crate euclid;
extern crate fnv;
extern crate gleam;

View file

@ -35,6 +35,7 @@ use style::stylesheets::{CssRules, ImportRule, Namespaces, Stylesheet, Styleshee
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
use style::stylesheets::import_rule::ImportSheet;
use style::values::CssUrl;
use task_source::TaskSourceName;
pub trait StylesheetOwner {
/// Returns whether this element was inserted by the parser (i.e., it should
@ -228,7 +229,7 @@ impl<'a> StylesheetLoader<'a> {
let listener = NetworkListener {
context: context,
task_source: document.window().networking_task_source(),
canceller: Some(document.window().task_canceller())
canceller: Some(document.window().task_canceller(TaskSourceName::Networking))
};
ROUTER.add_route(action_receiver.to_opaque(), Box::new(move |message| {
listener.notify_fetch(message.to().unwrap());

View file

@ -15,7 +15,7 @@ use std::fmt;
use std::result::Result;
use std::sync::mpsc::Sender;
use task::{TaskCanceller, TaskOnce};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
#[derive(Clone, JSTraceable)]
pub struct DOMManipulationTaskSource(pub Sender<MainThreadScriptMsg>, pub PipelineId);
@ -27,6 +27,8 @@ impl fmt::Debug for DOMManipulationTaskSource {
}
impl TaskSource for DOMManipulationTaskSource {
const NAME: TaskSourceName = TaskSourceName::DOMManipulation;
fn queue_with_canceller<T>(
&self,
task: T,

View file

@ -8,7 +8,7 @@ use msg::constellation_msg::PipelineId;
use script_runtime::{CommonScriptMsg, ScriptThreadEventCategory, ScriptChan};
use std::sync::Arc;
use task::{TaskCanceller, TaskOnce};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
#[derive(JSTraceable)]
pub struct FileReadingTaskSource(pub Box<ScriptChan + Send + 'static>, pub PipelineId);
@ -20,6 +20,8 @@ impl Clone for FileReadingTaskSource {
}
impl TaskSource for FileReadingTaskSource {
const NAME: TaskSourceName = TaskSourceName::FileReading;
fn queue_with_canceller<T>(
&self,
task: T,

View file

@ -2,6 +2,7 @@
* 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/. */
pub mod dom_manipulation;
pub mod file_reading;
pub mod history_traversal;
@ -10,10 +11,33 @@ pub mod performance_timeline;
pub mod user_interaction;
use dom::globalscope::GlobalScope;
use enum_iterator::IntoEnumIterator;
use std::result::Result;
use task::{TaskCanceller, TaskOnce};
// The names of all task sources, used to differentiate TaskCancellers.
// Note: When adding a task source, update this enum.
// Note: The HistoryTraversalTaskSource is not part of this,
// because it doesn't implement TaskSource.
#[derive(Eq, Hash, IntoEnumIterator, JSTraceable, PartialEq)]
pub enum TaskSourceName {
DOMManipulation,
FileReading,
HistoryTraversal,
Networking,
PerformanceTimeline,
UserInteraction
}
impl TaskSourceName {
pub fn all() -> Vec<TaskSourceName> {
TaskSourceName::into_enum_iter().collect()
}
}
pub trait TaskSource {
const NAME: TaskSourceName;
fn queue_with_canceller<T>(
&self,
task: T,
@ -26,6 +50,7 @@ pub trait TaskSource {
where
T: TaskOnce + 'static,
{
self.queue_with_canceller(task, &global.task_canceller())
let canceller = global.task_canceller(Self::NAME);
self.queue_with_canceller(task, &canceller)
}
}

View file

@ -5,7 +5,7 @@
use msg::constellation_msg::PipelineId;
use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use task::{TaskCanceller, TaskOnce};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
#[derive(JSTraceable)]
pub struct NetworkingTaskSource(pub Box<ScriptChan + Send + 'static>, pub PipelineId);
@ -17,6 +17,8 @@ impl Clone for NetworkingTaskSource {
}
impl TaskSource for NetworkingTaskSource {
const NAME: TaskSourceName = TaskSourceName::Networking;
fn queue_with_canceller<T>(
&self,
task: T,

View file

@ -13,7 +13,7 @@ use script_runtime::{CommonScriptMsg, ScriptChan, ScriptThreadEventCategory};
use std::fmt;
use std::result::Result;
use task::{TaskCanceller, TaskOnce};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
#[derive(JSTraceable)]
pub struct PerformanceTimelineTaskSource(pub Box<ScriptChan + Send + 'static>, pub PipelineId);
@ -31,6 +31,8 @@ impl fmt::Debug for PerformanceTimelineTaskSource {
}
impl TaskSource for PerformanceTimelineTaskSource {
const NAME: TaskSourceName = TaskSourceName::PerformanceTimeline;
fn queue_with_canceller<T>(
&self,
task: T,

View file

@ -15,7 +15,7 @@ use std::fmt;
use std::result::Result;
use std::sync::mpsc::Sender;
use task::{TaskCanceller, TaskOnce};
use task_source::TaskSource;
use task_source::{TaskSource, TaskSourceName};
#[derive(Clone, JSTraceable)]
pub struct UserInteractionTaskSource(pub Sender<MainThreadScriptMsg>, pub PipelineId);
@ -27,6 +27,8 @@ impl fmt::Debug for UserInteractionTaskSource {
}
impl TaskSource for UserInteractionTaskSource {
const NAME: TaskSourceName = TaskSourceName::UserInteraction;
fn queue_with_canceller<T>(
&self,
task: T,