dom/workers/MessagePort.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "MessagePort.h"
michael@0 7
michael@0 8 #include "mozilla/EventDispatcher.h"
michael@0 9 #include "mozilla/dom/MessagePortBinding.h"
michael@0 10 #include "nsIDOMEvent.h"
michael@0 11
michael@0 12 #include "SharedWorker.h"
michael@0 13 #include "WorkerPrivate.h"
michael@0 14 #include "WorkerRunnable.h"
michael@0 15
michael@0 16 using mozilla::dom::EventHandlerNonNull;
michael@0 17 using mozilla::dom::MessagePortBase;
michael@0 18 using mozilla::dom::Optional;
michael@0 19 using mozilla::dom::Sequence;
michael@0 20 using namespace mozilla;
michael@0 21
michael@0 22 USING_WORKERS_NAMESPACE
michael@0 23
michael@0 24 namespace {
michael@0 25
michael@0 26 class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable
michael@0 27 {
michael@0 28 nsRefPtr<MessagePort> mMessagePort;
michael@0 29 nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
michael@0 30
michael@0 31 public:
michael@0 32 DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
michael@0 33 TargetAndBusyBehavior aBehavior,
michael@0 34 MessagePort* aMessagePort,
michael@0 35 nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
michael@0 36 : WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
michael@0 37 {
michael@0 38 AssertIsOnMainThread();
michael@0 39 MOZ_ASSERT(aMessagePort);
michael@0 40 MOZ_ASSERT(aEvents.Length());
michael@0 41
michael@0 42 mEvents.SwapElements(aEvents);
michael@0 43 }
michael@0 44
michael@0 45 bool
michael@0 46 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
michael@0 47 };
michael@0 48
michael@0 49 } // anonymous namespace
michael@0 50
michael@0 51 MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
michael@0 52 uint64_t aSerial)
michael@0 53 : MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
michael@0 54 mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
michael@0 55 {
michael@0 56 AssertIsOnMainThread();
michael@0 57 MOZ_ASSERT(aSharedWorker);
michael@0 58 SetIsDOMBinding();
michael@0 59 }
michael@0 60
michael@0 61 MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
michael@0 62 : mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
michael@0 63 {
michael@0 64 aWorkerPrivate->AssertIsOnWorkerThread();
michael@0 65 SetIsDOMBinding();
michael@0 66 }
michael@0 67
michael@0 68 MessagePort::~MessagePort()
michael@0 69 {
michael@0 70 Close();
michael@0 71 }
michael@0 72
michael@0 73 void
michael@0 74 MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
michael@0 75 const Optional<Sequence<JS::Value>>& aTransferable,
michael@0 76 ErrorResult& aRv)
michael@0 77 {
michael@0 78 AssertCorrectThread();
michael@0 79
michael@0 80 if (IsClosed()) {
michael@0 81 aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
michael@0 82 return;
michael@0 83 }
michael@0 84
michael@0 85 if (mSharedWorker) {
michael@0 86 mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
michael@0 87 }
michael@0 88 else {
michael@0 89 mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
michael@0 90 aTransferable, aRv);
michael@0 91 }
michael@0 92 }
michael@0 93
michael@0 94 void
michael@0 95 MessagePort::Start()
michael@0 96 {
michael@0 97 AssertCorrectThread();
michael@0 98
michael@0 99 if (IsClosed()) {
michael@0 100 NS_WARNING("Called start() after calling close()!");
michael@0 101 return;
michael@0 102 }
michael@0 103
michael@0 104 if (mStarted) {
michael@0 105 return;
michael@0 106 }
michael@0 107
michael@0 108 mStarted = true;
michael@0 109
michael@0 110 if (!mQueuedEvents.IsEmpty()) {
michael@0 111 WorkerPrivate* workerPrivate;
michael@0 112 WorkerRunnable::TargetAndBusyBehavior behavior;
michael@0 113
michael@0 114 if (mWorkerPrivate) {
michael@0 115 workerPrivate = mWorkerPrivate;
michael@0 116 behavior = WorkerRunnable::WorkerThreadModifyBusyCount;
michael@0 117 }
michael@0 118 else {
michael@0 119 workerPrivate = mSharedWorker->GetWorkerPrivate();
michael@0 120 MOZ_ASSERT(workerPrivate);
michael@0 121
michael@0 122 behavior = WorkerRunnable::ParentThreadUnchangedBusyCount;
michael@0 123 }
michael@0 124
michael@0 125 nsRefPtr<DelayedEventRunnable> runnable =
michael@0 126 new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents);
michael@0 127 runnable->Dispatch(nullptr);
michael@0 128 }
michael@0 129 }
michael@0 130
michael@0 131 void
michael@0 132 MessagePort::Close()
michael@0 133 {
michael@0 134 AssertCorrectThread();
michael@0 135
michael@0 136 if (!IsClosed()) {
michael@0 137 CloseInternal();
michael@0 138 }
michael@0 139 }
michael@0 140
michael@0 141 void
michael@0 142 MessagePort::QueueEvent(nsIDOMEvent* aEvent)
michael@0 143 {
michael@0 144 AssertCorrectThread();
michael@0 145 MOZ_ASSERT(aEvent);
michael@0 146 MOZ_ASSERT(!IsClosed());
michael@0 147 MOZ_ASSERT(!mStarted);
michael@0 148
michael@0 149 mQueuedEvents.AppendElement(aEvent);
michael@0 150 }
michael@0 151
michael@0 152 EventHandlerNonNull*
michael@0 153 MessagePort::GetOnmessage()
michael@0 154 {
michael@0 155 AssertCorrectThread();
michael@0 156
michael@0 157 return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
michael@0 158 : GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
michael@0 159 }
michael@0 160
michael@0 161 void
michael@0 162 MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
michael@0 163 {
michael@0 164 AssertCorrectThread();
michael@0 165
michael@0 166 if (NS_IsMainThread()) {
michael@0 167 SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
michael@0 168 }
michael@0 169 else {
michael@0 170 SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
michael@0 171 }
michael@0 172
michael@0 173 Start();
michael@0 174 }
michael@0 175
michael@0 176 already_AddRefed<MessagePortBase>
michael@0 177 MessagePort::Clone()
michael@0 178 {
michael@0 179 NS_WARNING("Haven't implemented structured clone for these ports yet!");
michael@0 180 return nullptr;
michael@0 181 }
michael@0 182
michael@0 183 void
michael@0 184 MessagePort::CloseInternal()
michael@0 185 {
michael@0 186 AssertCorrectThread();
michael@0 187 MOZ_ASSERT(!IsClosed());
michael@0 188 MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
michael@0 189
michael@0 190 NS_WARN_IF_FALSE(mStarted, "Called close() before start()!");
michael@0 191
michael@0 192 if (!mStarted) {
michael@0 193 mQueuedEvents.Clear();
michael@0 194 }
michael@0 195
michael@0 196 mSharedWorker = nullptr;
michael@0 197 mWorkerPrivate = nullptr;
michael@0 198 }
michael@0 199
michael@0 200 #ifdef DEBUG
michael@0 201 void
michael@0 202 MessagePort::AssertCorrectThread() const
michael@0 203 {
michael@0 204 if (IsClosed()) {
michael@0 205 return; // Can't assert anything if we nulled out our pointers.
michael@0 206 }
michael@0 207
michael@0 208 MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
michael@0 209 !(mSharedWorker && mWorkerPrivate));
michael@0 210
michael@0 211 if (mSharedWorker) {
michael@0 212 AssertIsOnMainThread();
michael@0 213 }
michael@0 214 else {
michael@0 215 mWorkerPrivate->AssertIsOnWorkerThread();
michael@0 216 }
michael@0 217 }
michael@0 218 #endif
michael@0 219
michael@0 220 NS_IMPL_ADDREF_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
michael@0 221 NS_IMPL_RELEASE_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
michael@0 222
michael@0 223 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
michael@0 224 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
michael@0 225
michael@0 226 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
michael@0 227
michael@0 228 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
michael@0 229 DOMEventTargetHelper)
michael@0 230 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker)
michael@0 231 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents)
michael@0 232 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 233
michael@0 234 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
michael@0 235 DOMEventTargetHelper)
michael@0 236 tmp->Close();
michael@0 237 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 238
michael@0 239 JSObject*
michael@0 240 MessagePort::WrapObject(JSContext* aCx)
michael@0 241 {
michael@0 242 AssertCorrectThread();
michael@0 243
michael@0 244 return MessagePortBinding::Wrap(aCx, this);
michael@0 245 }
michael@0 246
michael@0 247 nsresult
michael@0 248 MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor)
michael@0 249 {
michael@0 250 AssertCorrectThread();
michael@0 251
michael@0 252 nsIDOMEvent*& event = aVisitor.mDOMEvent;
michael@0 253
michael@0 254 if (event) {
michael@0 255 bool preventDispatch = false;
michael@0 256
michael@0 257 if (IsClosed()) {
michael@0 258 preventDispatch = true;
michael@0 259 } else if (NS_IsMainThread() && mSharedWorker->IsSuspended()) {
michael@0 260 mSharedWorker->QueueEvent(event);
michael@0 261 preventDispatch = true;
michael@0 262 } else if (!mStarted) {
michael@0 263 QueueEvent(event);
michael@0 264 preventDispatch = true;
michael@0 265 }
michael@0 266
michael@0 267 if (preventDispatch) {
michael@0 268 aVisitor.mCanHandle = false;
michael@0 269 aVisitor.mParentTarget = nullptr;
michael@0 270 return NS_OK;
michael@0 271 }
michael@0 272 }
michael@0 273
michael@0 274 return DOMEventTargetHelper::PreHandleEvent(aVisitor);
michael@0 275 }
michael@0 276
michael@0 277 bool
michael@0 278 DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
michael@0 279 {
michael@0 280 MOZ_ASSERT(mMessagePort);
michael@0 281 mMessagePort->AssertCorrectThread();
michael@0 282 MOZ_ASSERT(mEvents.Length());
michael@0 283
michael@0 284 bool ignored;
michael@0 285 for (uint32_t i = 0; i < mEvents.Length(); i++) {
michael@0 286 mMessagePort->DispatchEvent(mEvents[i], &ignored);
michael@0 287 }
michael@0 288
michael@0 289 return true;
michael@0 290 }

mercurial