Give workers their own ScriptChan and use it for postMessage.

This ensures that XHR callbacks for XHR objects in workers are called on the
worker thread rather than the main thread.
This commit is contained in:
Ms2ger 2014-08-11 16:41:16 +02:00
parent 8e59706933
commit 96aad42a5d
3 changed files with 39 additions and 29 deletions

View file

@ -14,11 +14,11 @@ use dom::eventtarget::WorkerGlobalScopeTypeId;
use dom::messageevent::MessageEvent;
use dom::workerglobalscope::DedicatedGlobalScope;
use dom::workerglobalscope::WorkerGlobalScope;
use script_task::{ScriptTask, ScriptChan};
use dom::xmlhttprequest::XMLHttpRequest;
use script_task::{ScriptTask, ScriptChan, ScriptMsg, DOMMessage, XHRProgressMsg};
use script_task::StackRootTLS;
use servo_net::resource_task::{ResourceTask, load_whole_resource};
use servo_util::str::DOMString;
use js::rust::Cx;
@ -30,13 +30,13 @@ use url::Url;
#[deriving(Encodable)]
pub struct DedicatedWorkerGlobalScope {
workerglobalscope: WorkerGlobalScope,
receiver: Untraceable<Receiver<DOMString>>,
receiver: Untraceable<Receiver<ScriptMsg>>,
}
impl DedicatedWorkerGlobalScope {
pub fn new_inherited(worker_url: Url,
cx: Rc<Cx>,
receiver: Receiver<DOMString>,
receiver: Receiver<ScriptMsg>,
resource_task: ResourceTask,
script_chan: ScriptChan)
-> DedicatedWorkerGlobalScope {
@ -50,7 +50,7 @@ impl DedicatedWorkerGlobalScope {
pub fn new(worker_url: Url,
cx: Rc<Cx>,
receiver: Receiver<DOMString>,
receiver: Receiver<ScriptMsg>,
resource_task: ResourceTask,
script_chan: ScriptChan)
-> Temporary<DedicatedWorkerGlobalScope> {
@ -62,9 +62,9 @@ impl DedicatedWorkerGlobalScope {
impl DedicatedWorkerGlobalScope {
pub fn run_worker_scope(worker_url: Url,
receiver: Receiver<DOMString>,
resource_task: ResourceTask,
script_chan: ScriptChan) {
resource_task: ResourceTask) -> ScriptChan {
let (receiver, sender) = ScriptChan::new();
let sender_clone = sender.clone();
TaskBuilder::new()
.native()
.named(format!("Web Worker at {}", worker_url.serialize()))
@ -85,7 +85,7 @@ impl DedicatedWorkerGlobalScope {
let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx();
let global = DedicatedWorkerGlobalScope::new(
worker_url, js_context.clone(), receiver, resource_task,
script_chan).root();
sender).root();
match js_context.evaluate_script(
global.reflector().get_jsobject(), source, url.serialize(), 1) {
Ok(_) => (),
@ -98,13 +98,18 @@ impl DedicatedWorkerGlobalScope {
EventTargetCast::from_ref(&*global);
loop {
match global.receiver.recv_opt() {
Ok(message) => {
Ok(DOMMessage(message)) => {
MessageEvent::dispatch(target, &Worker(*scope), message)
},
Ok(XHRProgressMsg(addr, progress)) => {
XMLHttpRequest::handle_xhr_progress(addr, progress)
},
Ok(_) => fail!("Unexpected message"),
Err(_) => break,
}
}
});
return sender_clone;
}
}

View file

@ -7,10 +7,10 @@ use dom::bindings::codegen::Bindings::WorkerBinding::WorkerMethods;
use dom::bindings::error::{Fallible, Syntax};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::trace::Untraceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope;
use dom::eventtarget::{EventTarget, WorkerTypeId};
use script_task::{ScriptChan, DOMMessage};
use servo_util::str::DOMString;
use url::UrlParser;
@ -18,18 +18,18 @@ use url::UrlParser;
#[deriving(Encodable)]
pub struct Worker {
eventtarget: EventTarget,
sender: Untraceable<Sender<DOMString>>,
sender: ScriptChan,
}
impl Worker {
pub fn new_inherited(sender: Sender<DOMString>) -> Worker {
pub fn new_inherited(sender: ScriptChan) -> Worker {
Worker {
eventtarget: EventTarget::new_inherited(WorkerTypeId),
sender: Untraceable::new(sender),
sender: sender,
}
}
pub fn new(global: &GlobalRef, sender: Sender<DOMString>) -> Temporary<Worker> {
pub fn new(global: &GlobalRef, sender: ScriptChan) -> Temporary<Worker> {
reflect_dom_object(box Worker::new_inherited(sender),
global,
WorkerBinding::Wrap)
@ -44,17 +44,17 @@ impl Worker {
Err(_) => return Err(Syntax),
};
let (sender, receiver) = channel();
let resource_task = global.resource_task();
DedicatedWorkerGlobalScope::run_worker_scope(
worker_url, receiver, resource_task, global.script_chan().clone());
let sender = DedicatedWorkerGlobalScope::run_worker_scope(
worker_url, resource_task);
Ok(Worker::new(global, sender))
}
}
impl<'a> WorkerMethods for JSRef<'a, Worker> {
fn PostMessage(&self, message: DOMString) {
self.sender.send(message);
let ScriptChan(ref sender) = self.sender;
sender.send(DOMMessage(message));
}
}

View file

@ -31,12 +31,6 @@ use layout_interface::ContentChangedDocumentDamage;
use layout_interface;
use page::{Page, IterablePage, Frame};
use geom::point::Point2D;
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
use js::jsapi::{JSContext, JSRuntime};
use js::rust::{Cx, RtUtils};
use js::rust::with_compartment;
use js;
use script_traits::{CompositorEvent, ResizeEvent, ReflowEvent, ClickEvent, MouseDownEvent};
use script_traits::{MouseMoveEvent, MouseUpEvent, ConstellationControlMsg, ScriptTaskFactory};
use script_traits::{ResizeMsg, AttachLayoutMsg, LoadMsg, SendEventMsg, ResizeInactiveMsg};
@ -50,15 +44,23 @@ use servo_msg::constellation_msg;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::geometry::to_frac_px;
use servo_util::str::DOMString;
use servo_util::task::spawn_named_with_send_on_failure;
use geom::point::Point2D;
use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC};
use js::jsapi::{JSContext, JSRuntime};
use js::rust::{Cx, RtUtils};
use js::rust::with_compartment;
use js;
use url::Url;
use serialize::{Encoder, Encodable};
use std::any::{Any, AnyRefExt};
use std::cell::RefCell;
use std::comm::{channel, Sender, Receiver, Select};
use std::mem::replace;
use std::rc::Rc;
use url::Url;
use serialize::{Encoder, Encodable};
local_data_key!(pub StackRoots: *const RootCollection)
@ -75,7 +77,9 @@ pub enum ScriptMsg {
/// Notifies the script that a window associated with a particular pipeline should be closed.
ExitWindowMsg(PipelineId),
/// Notifies the script of progress on a fetch
XHRProgressMsg(TrustedXHRAddress, XHRProgress)
XHRProgressMsg(TrustedXHRAddress, XHRProgress),
/// Message sent through postMessage
DOMMessage(DOMString),
}
/// Encapsulates internal communication within the script task.
@ -430,6 +434,7 @@ impl ScriptTask {
FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id),
FromConstellation(ResizeMsg(..)) => fail!("should have handled ResizeMsg already"),
FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_xhr_progress(addr, progress),
FromScript(DOMMessage(..)) => fail!("unexpected message"),
}
}