aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/abstractworkerglobalscope.rs
diff options
context:
space:
mode:
authorGregory Terzian <gterzian@users.noreply.github.com>2018-08-18 20:28:42 +0200
committerGregory Terzian <gterzian@users.noreply.github.com>2018-08-31 02:10:45 +0800
commit029715aba6f4a4c62b5a2759d47dda57954cc433 (patch)
treeed529c6a3c958f04b489882818884e10b0d3a11d /components/script/dom/abstractworkerglobalscope.rs
parentca6306c4306b0d13a7e886f4308ee703fcb1b2b3 (diff)
downloadservo-029715aba6f4a4c62b5a2759d47dda57954cc433.tar.gz
servo-029715aba6f4a4c62b5a2759d47dda57954cc433.zip
introduce a generic worker event-loop
Diffstat (limited to 'components/script/dom/abstractworkerglobalscope.rs')
-rw-r--r--components/script/dom/abstractworkerglobalscope.rs94
1 files changed, 92 insertions, 2 deletions
diff --git a/components/script/dom/abstractworkerglobalscope.rs b/components/script/dom/abstractworkerglobalscope.rs
index 99c08dc2c38..45c594dbaee 100644
--- a/components/script/dom/abstractworkerglobalscope.rs
+++ b/components/script/dom/abstractworkerglobalscope.rs
@@ -2,11 +2,17 @@
* 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 devtools_traits::DevtoolScriptControlMsg;
use dom::abstractworker::WorkerScriptMsg;
-use dom::dedicatedworkerglobalscope::DedicatedWorkerScriptMsg;
+use dom::bindings::conversions::DerivedFrom;
+use dom::bindings::reflector::DomObject;
+use dom::dedicatedworkerglobalscope::{AutoWorkerReset, DedicatedWorkerScriptMsg};
+use dom::globalscope::GlobalScope;
use dom::worker::TrustedWorkerAddress;
+use dom::workerglobalscope::WorkerGlobalScope;
use script_runtime::{ScriptChan, CommonScriptMsg, ScriptPort};
-use std::sync::mpsc::{Receiver, Sender};
+use std::sync::mpsc::{Receiver, Select, Sender};
+use task_queue::{QueuedTaskConversion, TaskQueue};
/// A ScriptChan that can be cloned freely and will silently send a TrustedWorkerAddress with
/// common event loop messages. While this SendableWorkerScriptChan is alive, the associated
@@ -69,3 +75,87 @@ impl ScriptPort for Receiver<DedicatedWorkerScriptMsg> {
}
}
}
+
+pub trait WorkerEventLoopMethods {
+ type TimerMsg: Send;
+ type WorkerMsg: QueuedTaskConversion + Send;
+ type Event;
+ fn timer_event_port(&self) -> &Receiver<Self::TimerMsg>;
+ fn task_queue(&self) -> &TaskQueue<Self::WorkerMsg>;
+ fn handle_event(&self, event: Self::Event);
+ fn handle_worker_post_event(&self, worker: &TrustedWorkerAddress) -> Option<AutoWorkerReset>;
+ fn from_worker_msg(&self, msg: Self::WorkerMsg) -> Self::Event;
+ fn from_timer_msg(&self, msg: Self::TimerMsg) -> Self::Event;
+ fn from_devtools_msg(&self, msg: DevtoolScriptControlMsg) -> Self::Event;
+}
+
+#[allow(unsafe_code)]
+// https://html.spec.whatwg.org/multipage/#worker-event-loop
+pub fn run_worker_event_loop<T, TimerMsg, WorkerMsg, Event>(worker_scope: &T,
+ worker: Option<&TrustedWorkerAddress>)
+where
+ TimerMsg: Send,
+ WorkerMsg: QueuedTaskConversion + Send,
+ T: WorkerEventLoopMethods<TimerMsg = TimerMsg, WorkerMsg = WorkerMsg, Event = Event>
+ + DerivedFrom<WorkerGlobalScope> + DerivedFrom<GlobalScope>
+ + DomObject {
+ let scope = worker_scope.upcast::<WorkerGlobalScope>();
+ let timer_event_port = worker_scope.timer_event_port();
+ let devtools_port = scope.from_devtools_receiver();
+ let task_queue = worker_scope.task_queue();
+ let sel = Select::new();
+ let mut worker_handle = sel.handle(task_queue.select());
+ 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();
+ let event = {
+ if ret == worker_handle.id() {
+ task_queue.take_tasks();
+ worker_scope.from_worker_msg(task_queue.recv().unwrap())
+ } else if ret == timer_event_handle.id() {
+ worker_scope.from_timer_msg(timer_event_port.recv().unwrap())
+ } else if ret == devtools_handle.id() {
+ worker_scope.from_devtools_msg(devtools_port.recv().unwrap())
+ } else {
+ panic!("unexpected select result!")
+ }
+ };
+ let mut sequential = vec![];
+ sequential.push(event);
+ // https://html.spec.whatwg.org/multipage/#worker-event-loop
+ // Once the WorkerGlobalScope's closing flag is set to true,
+ // the event loop's task queues must discard any further tasks
+ // that would be added to them
+ // (tasks already on the queue are unaffected except where otherwise specified).
+ while !scope.is_closing() {
+ // Batch all events that are ready.
+ // The task queue will throttle non-priority tasks if necessary.
+ match task_queue.try_recv() {
+ Err(_) => match timer_event_port.try_recv() {
+ Err(_) => match devtools_port.try_recv() {
+ Err(_) => break,
+ Ok(ev) => sequential.push(worker_scope.from_devtools_msg(ev)),
+ },
+ Ok(ev) => sequential.push(worker_scope.from_timer_msg(ev)),
+ },
+ Ok(ev) => sequential.push(worker_scope.from_worker_msg(ev)),
+ }
+ }
+ // Step 3
+ for event in sequential {
+ worker_scope.handle_event(event);
+ // Step 6
+ let _ar = match worker {
+ Some(worker) => worker_scope.handle_worker_post_event(worker),
+ None => None
+ };
+ worker_scope.upcast::<GlobalScope>().perform_a_microtask_checkpoint();
+ }
+}