diff options
Diffstat (limited to 'components/script/dom/dedicatedworkerglobalscope.rs')
-rw-r--r-- | components/script/dom/dedicatedworkerglobalscope.rs | 202 |
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(()) } |