1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/workers/MessagePort.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,290 @@ 1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.7 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "MessagePort.h" 1.10 + 1.11 +#include "mozilla/EventDispatcher.h" 1.12 +#include "mozilla/dom/MessagePortBinding.h" 1.13 +#include "nsIDOMEvent.h" 1.14 + 1.15 +#include "SharedWorker.h" 1.16 +#include "WorkerPrivate.h" 1.17 +#include "WorkerRunnable.h" 1.18 + 1.19 +using mozilla::dom::EventHandlerNonNull; 1.20 +using mozilla::dom::MessagePortBase; 1.21 +using mozilla::dom::Optional; 1.22 +using mozilla::dom::Sequence; 1.23 +using namespace mozilla; 1.24 + 1.25 +USING_WORKERS_NAMESPACE 1.26 + 1.27 +namespace { 1.28 + 1.29 +class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable 1.30 +{ 1.31 + nsRefPtr<MessagePort> mMessagePort; 1.32 + nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents; 1.33 + 1.34 +public: 1.35 + DelayedEventRunnable(WorkerPrivate* aWorkerPrivate, 1.36 + TargetAndBusyBehavior aBehavior, 1.37 + MessagePort* aMessagePort, 1.38 + nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents) 1.39 + : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort) 1.40 + { 1.41 + AssertIsOnMainThread(); 1.42 + MOZ_ASSERT(aMessagePort); 1.43 + MOZ_ASSERT(aEvents.Length()); 1.44 + 1.45 + mEvents.SwapElements(aEvents); 1.46 + } 1.47 + 1.48 + bool 1.49 + WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate); 1.50 +}; 1.51 + 1.52 +} // anonymous namespace 1.53 + 1.54 +MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker, 1.55 + uint64_t aSerial) 1.56 +: MessagePortBase(aWindow), mSharedWorker(aSharedWorker), 1.57 + mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false) 1.58 +{ 1.59 + AssertIsOnMainThread(); 1.60 + MOZ_ASSERT(aSharedWorker); 1.61 + SetIsDOMBinding(); 1.62 +} 1.63 + 1.64 +MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial) 1.65 +: mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false) 1.66 +{ 1.67 + aWorkerPrivate->AssertIsOnWorkerThread(); 1.68 + SetIsDOMBinding(); 1.69 +} 1.70 + 1.71 +MessagePort::~MessagePort() 1.72 +{ 1.73 + Close(); 1.74 +} 1.75 + 1.76 +void 1.77 +MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage, 1.78 + const Optional<Sequence<JS::Value>>& aTransferable, 1.79 + ErrorResult& aRv) 1.80 +{ 1.81 + AssertCorrectThread(); 1.82 + 1.83 + if (IsClosed()) { 1.84 + aRv = NS_ERROR_DOM_INVALID_STATE_ERR; 1.85 + return; 1.86 + } 1.87 + 1.88 + if (mSharedWorker) { 1.89 + mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv); 1.90 + } 1.91 + else { 1.92 + mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage, 1.93 + aTransferable, aRv); 1.94 + } 1.95 +} 1.96 + 1.97 +void 1.98 +MessagePort::Start() 1.99 +{ 1.100 + AssertCorrectThread(); 1.101 + 1.102 + if (IsClosed()) { 1.103 + NS_WARNING("Called start() after calling close()!"); 1.104 + return; 1.105 + } 1.106 + 1.107 + if (mStarted) { 1.108 + return; 1.109 + } 1.110 + 1.111 + mStarted = true; 1.112 + 1.113 + if (!mQueuedEvents.IsEmpty()) { 1.114 + WorkerPrivate* workerPrivate; 1.115 + WorkerRunnable::TargetAndBusyBehavior behavior; 1.116 + 1.117 + if (mWorkerPrivate) { 1.118 + workerPrivate = mWorkerPrivate; 1.119 + behavior = WorkerRunnable::WorkerThreadModifyBusyCount; 1.120 + } 1.121 + else { 1.122 + workerPrivate = mSharedWorker->GetWorkerPrivate(); 1.123 + MOZ_ASSERT(workerPrivate); 1.124 + 1.125 + behavior = WorkerRunnable::ParentThreadUnchangedBusyCount; 1.126 + } 1.127 + 1.128 + nsRefPtr<DelayedEventRunnable> runnable = 1.129 + new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents); 1.130 + runnable->Dispatch(nullptr); 1.131 + } 1.132 +} 1.133 + 1.134 +void 1.135 +MessagePort::Close() 1.136 +{ 1.137 + AssertCorrectThread(); 1.138 + 1.139 + if (!IsClosed()) { 1.140 + CloseInternal(); 1.141 + } 1.142 +} 1.143 + 1.144 +void 1.145 +MessagePort::QueueEvent(nsIDOMEvent* aEvent) 1.146 +{ 1.147 + AssertCorrectThread(); 1.148 + MOZ_ASSERT(aEvent); 1.149 + MOZ_ASSERT(!IsClosed()); 1.150 + MOZ_ASSERT(!mStarted); 1.151 + 1.152 + mQueuedEvents.AppendElement(aEvent); 1.153 +} 1.154 + 1.155 +EventHandlerNonNull* 1.156 +MessagePort::GetOnmessage() 1.157 +{ 1.158 + AssertCorrectThread(); 1.159 + 1.160 + return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString()) 1.161 + : GetEventHandler(nullptr, NS_LITERAL_STRING("message")); 1.162 +} 1.163 + 1.164 +void 1.165 +MessagePort::SetOnmessage(EventHandlerNonNull* aCallback) 1.166 +{ 1.167 + AssertCorrectThread(); 1.168 + 1.169 + if (NS_IsMainThread()) { 1.170 + SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); 1.171 + } 1.172 + else { 1.173 + SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback); 1.174 + } 1.175 + 1.176 + Start(); 1.177 +} 1.178 + 1.179 +already_AddRefed<MessagePortBase> 1.180 +MessagePort::Clone() 1.181 +{ 1.182 + NS_WARNING("Haven't implemented structured clone for these ports yet!"); 1.183 + return nullptr; 1.184 +} 1.185 + 1.186 +void 1.187 +MessagePort::CloseInternal() 1.188 +{ 1.189 + AssertCorrectThread(); 1.190 + MOZ_ASSERT(!IsClosed()); 1.191 + MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty()); 1.192 + 1.193 + NS_WARN_IF_FALSE(mStarted, "Called close() before start()!"); 1.194 + 1.195 + if (!mStarted) { 1.196 + mQueuedEvents.Clear(); 1.197 + } 1.198 + 1.199 + mSharedWorker = nullptr; 1.200 + mWorkerPrivate = nullptr; 1.201 +} 1.202 + 1.203 +#ifdef DEBUG 1.204 +void 1.205 +MessagePort::AssertCorrectThread() const 1.206 +{ 1.207 + if (IsClosed()) { 1.208 + return; // Can't assert anything if we nulled out our pointers. 1.209 + } 1.210 + 1.211 + MOZ_ASSERT((mSharedWorker || mWorkerPrivate) && 1.212 + !(mSharedWorker && mWorkerPrivate)); 1.213 + 1.214 + if (mSharedWorker) { 1.215 + AssertIsOnMainThread(); 1.216 + } 1.217 + else { 1.218 + mWorkerPrivate->AssertIsOnWorkerThread(); 1.219 + } 1.220 +} 1.221 +#endif 1.222 + 1.223 +NS_IMPL_ADDREF_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper) 1.224 +NS_IMPL_RELEASE_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper) 1.225 + 1.226 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort) 1.227 +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) 1.228 + 1.229 +NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort) 1.230 + 1.231 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort, 1.232 + DOMEventTargetHelper) 1.233 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker) 1.234 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents) 1.235 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.236 + 1.237 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort, 1.238 + DOMEventTargetHelper) 1.239 + tmp->Close(); 1.240 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.241 + 1.242 +JSObject* 1.243 +MessagePort::WrapObject(JSContext* aCx) 1.244 +{ 1.245 + AssertCorrectThread(); 1.246 + 1.247 + return MessagePortBinding::Wrap(aCx, this); 1.248 +} 1.249 + 1.250 +nsresult 1.251 +MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor) 1.252 +{ 1.253 + AssertCorrectThread(); 1.254 + 1.255 + nsIDOMEvent*& event = aVisitor.mDOMEvent; 1.256 + 1.257 + if (event) { 1.258 + bool preventDispatch = false; 1.259 + 1.260 + if (IsClosed()) { 1.261 + preventDispatch = true; 1.262 + } else if (NS_IsMainThread() && mSharedWorker->IsSuspended()) { 1.263 + mSharedWorker->QueueEvent(event); 1.264 + preventDispatch = true; 1.265 + } else if (!mStarted) { 1.266 + QueueEvent(event); 1.267 + preventDispatch = true; 1.268 + } 1.269 + 1.270 + if (preventDispatch) { 1.271 + aVisitor.mCanHandle = false; 1.272 + aVisitor.mParentTarget = nullptr; 1.273 + return NS_OK; 1.274 + } 1.275 + } 1.276 + 1.277 + return DOMEventTargetHelper::PreHandleEvent(aVisitor); 1.278 +} 1.279 + 1.280 +bool 1.281 +DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) 1.282 +{ 1.283 + MOZ_ASSERT(mMessagePort); 1.284 + mMessagePort->AssertCorrectThread(); 1.285 + MOZ_ASSERT(mEvents.Length()); 1.286 + 1.287 + bool ignored; 1.288 + for (uint32_t i = 0; i < mEvents.Length(); i++) { 1.289 + mMessagePort->DispatchEvent(mEvents[i], &ignored); 1.290 + } 1.291 + 1.292 + return true; 1.293 +}