diff options
-rw-r--r-- | src/components/script/dom/bindings/js.rs | 10 | ||||
-rw-r--r-- | src/components/script/dom/dedicatedworkerglobalscope.rs | 34 | ||||
-rw-r--r-- | src/components/script/dom/worker.rs | 61 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 4 |
4 files changed, 99 insertions, 10 deletions
diff --git a/src/components/script/dom/bindings/js.rs b/src/components/script/dom/bindings/js.rs index 6a57b45449f..ab8b3e3c7f5 100644 --- a/src/components/script/dom/bindings/js.rs +++ b/src/components/script/dom/bindings/js.rs @@ -48,6 +48,7 @@ use dom::bindings::utils::{Reflector, Reflectable}; use dom::node::Node; use dom::xmlhttprequest::{XMLHttpRequest, TrustedXHRAddress}; +use dom::worker::{Worker, TrustedWorkerAddress}; use js::jsapi::JSObject; use layout_interface::TrustedNodeAddress; use script_task::StackRoots; @@ -143,6 +144,15 @@ impl JS<XMLHttpRequest> { } } +impl JS<Worker> { + pub unsafe fn from_trusted_worker_address(inner: TrustedWorkerAddress) -> JS<Worker> { + let TrustedWorkerAddress(addr) = inner; + JS { + ptr: addr as *const Worker + } + } +} + impl<T: Reflectable> JS<T> { /// Create a new JS-owned value wrapped from a raw Rust pointer. pub unsafe fn from_raw(raw: *const T) -> JS<T> { diff --git a/src/components/script/dom/dedicatedworkerglobalscope.rs b/src/components/script/dom/dedicatedworkerglobalscope.rs index a3757bf3b0b..654183757f6 100644 --- a/src/components/script/dom/dedicatedworkerglobalscope.rs +++ b/src/components/script/dom/dedicatedworkerglobalscope.rs @@ -12,10 +12,12 @@ use dom::bindings::utils::{Reflectable, Reflector}; use dom::eventtarget::EventTarget; use dom::eventtarget::WorkerGlobalScopeTypeId; use dom::messageevent::MessageEvent; +use dom::worker::{Worker, TrustedWorkerAddress}; use dom::workerglobalscope::DedicatedGlobalScope; use dom::workerglobalscope::WorkerGlobalScope; use dom::xmlhttprequest::XMLHttpRequest; -use script_task::{ScriptTask, ScriptChan, ScriptMsg, DOMMessage, XHRProgressMsg}; +use script_task::{ScriptTask, ScriptChan}; +use script_task::{ScriptMsg, DOMMessage, XHRProgressMsg, WorkerRelease}; use script_task::StackRootTLS; use servo_net::resource_task::{ResourceTask, load_whole_resource}; @@ -31,10 +33,12 @@ use url::Url; pub struct DedicatedWorkerGlobalScope { workerglobalscope: WorkerGlobalScope, receiver: Untraceable<Receiver<ScriptMsg>>, + worker: Untraceable<TrustedWorkerAddress>, } impl DedicatedWorkerGlobalScope { pub fn new_inherited(worker_url: Url, + worker: TrustedWorkerAddress, cx: Rc<Cx>, receiver: Receiver<ScriptMsg>, resource_task: ResourceTask, @@ -45,23 +49,27 @@ impl DedicatedWorkerGlobalScope { DedicatedGlobalScope, worker_url, cx, resource_task, script_chan), receiver: Untraceable::new(receiver), + worker: Untraceable::new(worker), } } pub fn new(worker_url: Url, + worker: TrustedWorkerAddress, cx: Rc<Cx>, receiver: Receiver<ScriptMsg>, resource_task: ResourceTask, script_chan: ScriptChan) -> Temporary<DedicatedWorkerGlobalScope> { let scope = box DedicatedWorkerGlobalScope::new_inherited( - worker_url, cx.clone(), receiver, resource_task, script_chan); + worker_url, worker, cx.clone(), receiver, resource_task, + script_chan); DedicatedWorkerGlobalScopeBinding::Wrap(cx.ptr, scope) } } impl DedicatedWorkerGlobalScope { pub fn run_worker_scope(worker_url: Url, + worker: TrustedWorkerAddress, resource_task: ResourceTask, receiver: Receiver<ScriptMsg>, sender: ScriptChan) { @@ -84,13 +92,14 @@ impl DedicatedWorkerGlobalScope { let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx(); let global = DedicatedWorkerGlobalScope::new( - worker_url, js_context.clone(), receiver, resource_task, + worker_url, worker, js_context.clone(), receiver, resource_task, sender).root(); match js_context.evaluate_script( global.reflector().get_jsobject(), source, url.serialize(), 1) { Ok(_) => (), Err(_) => println!("evaluate_script failed") } + global.delayed_release_worker(); let scope: &JSRef<WorkerGlobalScope> = WorkerGlobalScopeCast::from_ref(&*global); @@ -99,11 +108,15 @@ impl DedicatedWorkerGlobalScope { loop { match global.receiver.recv_opt() { Ok(DOMMessage(message)) => { - MessageEvent::dispatch(target, &Worker(*scope), message) + MessageEvent::dispatch(target, &Worker(*scope), message); + global.delayed_release_worker(); }, Ok(XHRProgressMsg(addr, progress)) => { XMLHttpRequest::handle_xhr_progress(addr, progress) }, + Ok(WorkerRelease(addr)) => { + Worker::handle_release(addr) + }, Ok(_) => fail!("Unexpected message"), Err(_) => break, } @@ -115,6 +128,19 @@ impl DedicatedWorkerGlobalScope { pub trait DedicatedWorkerGlobalScopeMethods { } +trait PrivateDedicatedWorkerGlobalScopeHelpers { + fn delayed_release_worker(&self); +} + +impl<'a> PrivateDedicatedWorkerGlobalScopeHelpers for JSRef<'a, DedicatedWorkerGlobalScope> { + fn delayed_release_worker(&self) { + let scope: &JSRef<WorkerGlobalScope> = + WorkerGlobalScopeCast::from_ref(self); + let ScriptChan(ref sender) = *scope.script_chan(); + sender.send(WorkerRelease(*self.worker)); + } +} + impl Reflectable for DedicatedWorkerGlobalScope { fn reflector<'a>(&'a self) -> &'a Reflector { self.workerglobalscope.reflector() diff --git a/src/components/script/dom/worker.rs b/src/components/script/dom/worker.rs index 5007f212f9a..ff41b09e273 100644 --- a/src/components/script/dom/worker.rs +++ b/src/components/script/dom/worker.rs @@ -5,32 +5,43 @@ use dom::bindings::codegen::Bindings::WorkerBinding; 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::global::{GlobalRef, GlobalField}; +use dom::bindings::js::{JS, JSRef, Temporary}; 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 js::jsapi::{JS_AddObjectRoot, JS_RemoveObjectRoot}; use url::UrlParser; +use libc::c_void; +use std::cell::Cell; + +pub struct TrustedWorkerAddress(pub *const c_void); + #[deriving(Encodable)] pub struct Worker { eventtarget: EventTarget, + refcount: Cell<uint>, + global: GlobalField, sender: ScriptChan, } impl Worker { - pub fn new_inherited(sender: ScriptChan) -> Worker { + pub fn new_inherited(global: &GlobalRef, sender: ScriptChan) -> Worker { Worker { eventtarget: EventTarget::new_inherited(WorkerTypeId), + refcount: Cell::new(0), + global: GlobalField::from_rooted(global), sender: sender, } } pub fn new(global: &GlobalRef, sender: ScriptChan) -> Temporary<Worker> { - reflect_dom_object(box Worker::new_inherited(sender), + reflect_dom_object(box Worker::new_inherited(global, sender), global, WorkerBinding::Wrap) } @@ -46,14 +57,52 @@ impl Worker { let resource_task = global.resource_task(); let (receiver, sender) = ScriptChan::new(); + + let worker = Worker::new(global, sender.clone()).root(); + let worker_ref = worker.addref(); + DedicatedWorkerGlobalScope::run_worker_scope( - worker_url, resource_task, receiver, sender.clone()); - Ok(Worker::new(global, sender)) + worker_url, worker_ref, resource_task, receiver, sender); + + Ok(Temporary::from_rooted(&*worker)) + } +} + +impl Worker { + // Creates a trusted address to the object, and roots it. Always pair this with a release() + pub fn addref(&self) -> TrustedWorkerAddress { + let refcount = self.refcount.get(); + if refcount == 0 { + let cx = self.global.root().root_ref().get_cx(); + unsafe { + JS_AddObjectRoot(cx, self.reflector().rootable()); + } + } + self.refcount.set(refcount + 1); + TrustedWorkerAddress(self as *const Worker as *const c_void) + } + + pub fn release(&self) { + let refcount = self.refcount.get(); + assert!(refcount > 0) + self.refcount.set(refcount - 1); + if refcount == 1 { + let cx = self.global.root().root_ref().get_cx(); + unsafe { + JS_RemoveObjectRoot(cx, self.reflector().rootable()); + } + } + } + + pub fn handle_release(address: TrustedWorkerAddress) { + let worker = unsafe { JS::from_trusted_worker_address(address).root() }; + worker.release(); } } impl<'a> WorkerMethods for JSRef<'a, Worker> { fn PostMessage(&self, message: DOMString) { + self.addref(); let ScriptChan(ref sender) = self.sender; sender.send(DOMMessage(message)); } diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs index ba6cd12c372..090cf38ee47 100644 --- a/src/components/script/script_task.rs +++ b/src/components/script/script_task.rs @@ -20,6 +20,7 @@ use dom::eventtarget::{EventTarget, EventTargetHelpers}; use dom::node; use dom::node::{ElementNodeTypeId, Node, NodeHelpers}; use dom::window::{TimerId, Window, WindowHelpers}; +use dom::worker::{Worker, TrustedWorkerAddress}; use dom::xmlhttprequest::{TrustedXHRAddress, XMLHttpRequest, XHRProgress}; use html::hubbub_html_parser::HtmlParserResult; use html::hubbub_html_parser::{HtmlDiscoveredStyle, HtmlDiscoveredScript}; @@ -86,6 +87,8 @@ pub enum ScriptMsg { /// Message sent through Worker.postMessage (only dispatched to /// DedicatedWorkerGlobalScope). DOMMessage(DOMString), + /// Releases one reference to the Worker object (dispatched to all tasks). + WorkerRelease(TrustedWorkerAddress), } /// Encapsulates internal communication within the script task. @@ -441,6 +444,7 @@ impl ScriptTask { FromConstellation(ResizeMsg(..)) => fail!("should have handled ResizeMsg already"), FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_xhr_progress(addr, progress), FromScript(DOMMessage(..)) => fail!("unexpected message"), + FromScript(WorkerRelease(addr)) => Worker::handle_release(addr), } } |