aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/dedicatedworkerglobalscope.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/dedicatedworkerglobalscope.rs')
-rw-r--r--components/script/dom/dedicatedworkerglobalscope.rs202
1 files changed, 141 insertions, 61 deletions
diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs
index 1c8c2316dde..c582177f42e 100644
--- a/components/script/dom/dedicatedworkerglobalscope.rs
+++ b/components/script/dom/dedicatedworkerglobalscope.rs
@@ -6,6 +6,7 @@ use devtools;
use devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::{SimpleWorkerErrorHandler, WorkerScriptMsg};
use dom::abstractworkerglobalscope::{SendableWorkerScriptChan, WorkerThreadWorkerChan};
+use dom::abstractworkerglobalscope::{WorkerEventLoopMethods, run_worker_event_loop};
use dom::bindings::cell::DomRefCell;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding;
use dom::bindings::codegen::Bindings::DedicatedWorkerGlobalScopeBinding::DedicatedWorkerGlobalScopeMethods;
@@ -40,15 +41,17 @@ use servo_url::ServoUrl;
use std::mem::replace;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
-use std::sync::mpsc::{Receiver, RecvError, Select, Sender, channel};
+use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use style::thread_state::{self, ThreadState};
+use task_queue::{QueuedTask, QueuedTaskConversion, TaskQueue};
+use task_source::TaskSourceName;
/// Set the `worker` field of a related DedicatedWorkerGlobalScope object to a particular
/// value for the duration of this object's lifetime. This ensures that the related Worker
/// object only lives as long as necessary (ie. while events are being executed), while
/// providing a reference that can be cloned freely.
-struct AutoWorkerReset<'a> {
+pub struct AutoWorkerReset<'a> {
workerscope: &'a DedicatedWorkerGlobalScope,
old_worker: Option<TrustedWorkerAddress>,
}
@@ -70,20 +73,85 @@ impl<'a> Drop for AutoWorkerReset<'a> {
}
}
-enum MixedMessage {
- FromWorker((TrustedWorkerAddress, WorkerScriptMsg)),
+pub enum DedicatedWorkerScriptMsg {
+ /// Standard message from a worker.
+ CommonWorker(TrustedWorkerAddress, WorkerScriptMsg),
+ /// Wake-up call from the task queue.
+ WakeUp,
+}
+
+pub enum MixedMessage {
+ FromWorker(DedicatedWorkerScriptMsg),
FromScheduler((TrustedWorkerAddress, TimerEvent)),
FromDevtools(DevtoolScriptControlMsg)
}
+impl QueuedTaskConversion for DedicatedWorkerScriptMsg {
+ fn task_source_name(&self) -> Option<&TaskSourceName> {
+ let common_worker_msg = match self {
+ DedicatedWorkerScriptMsg::CommonWorker(_, common_worker_msg) => common_worker_msg,
+ _ => return None,
+ };
+ let script_msg = match common_worker_msg {
+ WorkerScriptMsg::Common(ref script_msg) => script_msg,
+ _ => return None,
+ };
+ match script_msg {
+ CommonScriptMsg::Task(_category, _boxed, _pipeline_id, source_name) => Some(&source_name),
+ _ => return None,
+ }
+ }
+
+ fn into_queued_task(self) -> Option<QueuedTask> {
+ let (worker, common_worker_msg) = match self {
+ DedicatedWorkerScriptMsg::CommonWorker(worker, common_worker_msg) => (worker, common_worker_msg),
+ _ => return None,
+ };
+ let script_msg = match common_worker_msg {
+ WorkerScriptMsg::Common(script_msg) => script_msg,
+ _ => return None,
+ };
+ let (category, boxed, pipeline_id, task_source) = match script_msg {
+ CommonScriptMsg::Task(category, boxed, pipeline_id, task_source) =>
+ (category, boxed, pipeline_id, task_source),
+ _ => return None,
+ };
+ Some((Some(worker), category, boxed, pipeline_id, task_source))
+ }
+
+ fn from_queued_task(queued_task: QueuedTask) -> Self {
+ let (worker, category, boxed, pipeline_id, task_source) = queued_task;
+ let script_msg = CommonScriptMsg::Task(
+ category,
+ boxed,
+ pipeline_id,
+ task_source
+ );
+ DedicatedWorkerScriptMsg::CommonWorker(worker.unwrap(), WorkerScriptMsg::Common(script_msg))
+ }
+
+ fn wake_up_msg() -> Self {
+ DedicatedWorkerScriptMsg::WakeUp
+ }
+
+ fn is_wake_up(&self) -> bool {
+ match self {
+ DedicatedWorkerScriptMsg::WakeUp => true,
+ _ => false,
+ }
+ }
+}
+
+unsafe_no_jsmanaged_fields!(TaskQueue<DedicatedWorkerScriptMsg>);
+
// https://html.spec.whatwg.org/multipage/#dedicatedworkerglobalscope
#[dom_struct]
pub struct DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
#[ignore_malloc_size_of = "Defined in std"]
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ task_queue: TaskQueue<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
#[ignore_malloc_size_of = "Defined in std"]
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
#[ignore_malloc_size_of = "Trusted<T> has unclear ownership like Dom<T>"]
@@ -93,14 +161,49 @@ pub struct DedicatedWorkerGlobalScope {
parent_sender: Box<ScriptChan + Send>,
}
+impl WorkerEventLoopMethods for DedicatedWorkerGlobalScope {
+ type TimerMsg = (TrustedWorkerAddress, TimerEvent);
+ type WorkerMsg = DedicatedWorkerScriptMsg;
+ type Event = MixedMessage;
+
+ fn timer_event_port(&self) -> &Receiver<(TrustedWorkerAddress, TimerEvent)> {
+ &self.timer_event_port
+ }
+
+ fn task_queue(&self) -> &TaskQueue<DedicatedWorkerScriptMsg> {
+ &self.task_queue
+ }
+
+ fn handle_event(&self, event: MixedMessage) {
+ self.handle_mixed_message(event);
+ }
+
+ fn handle_worker_post_event(&self, worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset> {
+ let ar = AutoWorkerReset::new(&self, worker.clone());
+ Some(ar)
+ }
+
+ fn from_worker_msg(&self, msg: DedicatedWorkerScriptMsg) -> MixedMessage {
+ MixedMessage::FromWorker(msg)
+ }
+
+ fn from_timer_msg(&self, msg: (TrustedWorkerAddress, TimerEvent)) -> MixedMessage {
+ MixedMessage::FromScheduler(msg)
+ }
+
+ fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> MixedMessage {
+ MixedMessage::FromDevtools(msg)
+ }
+}
+
impl DedicatedWorkerGlobalScope {
fn new_inherited(init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>)
@@ -112,7 +215,7 @@ impl DedicatedWorkerGlobalScope {
from_devtools_receiver,
timer_event_chan,
Some(closing)),
- receiver: receiver,
+ task_queue: TaskQueue::new(receiver, own_sender.clone()),
own_sender: own_sender,
timer_event_port: timer_event_port,
parent_sender: parent_sender,
@@ -126,8 +229,8 @@ impl DedicatedWorkerGlobalScope {
from_devtools_receiver: Receiver<DevtoolScriptControlMsg>,
runtime: Runtime,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
timer_event_chan: IpcSender<TimerEvent>,
timer_event_port: Receiver<(TrustedWorkerAddress, TimerEvent)>,
closing: Arc<AtomicBool>)
@@ -151,13 +254,14 @@ impl DedicatedWorkerGlobalScope {
}
#[allow(unsafe_code)]
+ // https://html.spec.whatwg.org/multipage/#run-a-worker
pub fn run_worker_scope(init: WorkerGlobalScopeInit,
worker_url: ServoUrl,
from_devtools_receiver: IpcReceiver<DevtoolScriptControlMsg>,
worker: TrustedWorkerAddress,
parent_sender: Box<ScriptChan + Send>,
- own_sender: Sender<(TrustedWorkerAddress, WorkerScriptMsg)>,
- receiver: Receiver<(TrustedWorkerAddress, WorkerScriptMsg)>,
+ own_sender: Sender<DedicatedWorkerScriptMsg>,
+ receiver: Receiver<DedicatedWorkerScriptMsg>,
worker_load_origin: WorkerScriptLoadOrigin,
closing: Arc<AtomicBool>) {
let serialized_worker_url = worker_url.to_string();
@@ -196,7 +300,8 @@ impl DedicatedWorkerGlobalScope {
parent_sender.send(CommonScriptMsg::Task(
WorkerEvent,
Box::new(SimpleWorkerErrorHandler::new(worker)),
- pipeline_id
+ pipeline_id,
+ TaskSourceName::DOMManipulation,
)).unwrap();
return;
}
@@ -242,17 +347,11 @@ impl DedicatedWorkerGlobalScope {
let reporter_name = format!("dedicated-worker-reporter-{}", random::<u64>());
scope.upcast::<GlobalScope>().mem_profiler_chan().run_with_memory_reporting(|| {
- // https://html.spec.whatwg.org/multipage/#event-loop-processing-model
- // Step 1
- while let Ok(event) = global.receive_event() {
- if scope.is_closing() {
- break;
- }
- // Step 3
- global.handle_event(event);
- // Step 6
- let _ar = AutoWorkerReset::new(&global, worker.clone());
- global.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
+ // Step 29, Run the responsible event loop specified by inside settings until it is destroyed.
+ // The worker processing model remains on this step until the event loop is destroyed,
+ // which happens after the closing flag is set to true.
+ while !scope.is_closing() {
+ run_worker_event_loop(&*global, Some(&worker));
}
}, reporter_name, parent_sender, CommonScriptMsg::CollectReports);
}).expect("Thread spawning failed");
@@ -274,36 +373,6 @@ impl DedicatedWorkerGlobalScope {
(chan, Box::new(rx))
}
- #[allow(unsafe_code)]
- fn receive_event(&self) -> Result<MixedMessage, RecvError> {
- let scope = self.upcast::<WorkerGlobalScope>();
- let worker_port = &self.receiver;
- let timer_event_port = &self.timer_event_port;
- let devtools_port = scope.from_devtools_receiver();
-
- let sel = Select::new();
- let mut worker_handle = sel.handle(worker_port);
- let mut timer_event_handle = sel.handle(timer_event_port);
- let mut devtools_handle = sel.handle(devtools_port);
- unsafe {
- worker_handle.add();
- timer_event_handle.add();
- if scope.from_devtools_sender().is_some() {
- devtools_handle.add();
- }
- }
- let ret = sel.wait();
- if ret == worker_handle.id() {
- Ok(MixedMessage::FromWorker(worker_port.recv()?))
- } else if ret == timer_event_handle.id() {
- Ok(MixedMessage::FromScheduler(timer_event_port.recv()?))
- } else if ret == devtools_handle.id() {
- Ok(MixedMessage::FromDevtools(devtools_port.recv()?))
- } else {
- panic!("unexpected select result!")
- }
- }
-
fn handle_script_event(&self, msg: WorkerScriptMsg) {
match msg {
WorkerScriptMsg::DOMMessage(data) => {
@@ -321,8 +390,8 @@ impl DedicatedWorkerGlobalScope {
}
}
- fn handle_event(&self, event: MixedMessage) {
- match event {
+ fn handle_mixed_message(&self, msg: MixedMessage) {
+ match msg {
MixedMessage::FromDevtools(msg) => {
match msg {
DevtoolScriptControlMsg::EvaluateJS(_pipe_id, string, sender) =>
@@ -346,10 +415,11 @@ impl DedicatedWorkerGlobalScope {
}
}
}
- MixedMessage::FromWorker((linked_worker, msg)) => {
+ MixedMessage::FromWorker(DedicatedWorkerScriptMsg::CommonWorker(linked_worker, msg)) => {
let _ar = AutoWorkerReset::new(self, linked_worker);
self.handle_script_event(msg);
}
+ MixedMessage::FromWorker(DedicatedWorkerScriptMsg::WakeUp) => {},
}
}
@@ -382,8 +452,12 @@ impl DedicatedWorkerGlobalScope {
global.report_an_error(error_info, HandleValue::null());
}
}));
- // TODO: Should use the DOM manipulation task source.
- self.parent_sender.send(CommonScriptMsg::Task(WorkerEvent, task, Some(pipeline_id))).unwrap();
+ self.parent_sender.send(CommonScriptMsg::Task(
+ WorkerEvent,
+ task,
+ Some(pipeline_id),
+ TaskSourceName::DOMManipulation,
+ )).unwrap();
}
}
@@ -408,7 +482,13 @@ impl DedicatedWorkerGlobalScopeMethods for DedicatedWorkerGlobalScope {
let task = Box::new(task!(post_worker_message: move || {
Worker::handle_message(worker, data);
}));
- self.parent_sender.send(CommonScriptMsg::Task(WorkerEvent, task, Some(pipeline_id))).unwrap();
+ // TODO: Change this task source to a new `unshipped-port-message-queue` task source
+ self.parent_sender.send(CommonScriptMsg::Task(
+ WorkerEvent,
+ task,
+ Some(pipeline_id),
+ TaskSourceName::DOMManipulation,
+ )).unwrap();
Ok(())
}