Backed out changesets 73f3ce609c23 and 990a21978a2d (bug 951431) because they were...
[gecko.git] / dom / workers / MessagePort.cpp
blobbf8012d0e0b90b4635bbfed53ae74d6843b951e0
1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "MessagePort.h"
8 #include "mozilla/dom/MessagePortBinding.h"
9 #include "nsDOMEvent.h"
10 #include "nsEventDispatcher.h"
12 #include "SharedWorker.h"
13 #include "WorkerPrivate.h"
15 using mozilla::dom::EventHandlerNonNull;
16 using mozilla::dom::MessagePortBase;
17 using mozilla::dom::Optional;
18 using mozilla::dom::Sequence;
20 USING_WORKERS_NAMESPACE
22 namespace {
24 class DelayedEventRunnable MOZ_FINAL : public WorkerRunnable
26 nsRefPtr<MessagePort> mMessagePort;
27 nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
29 public:
30 DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
31 Target aTarget,
32 MessagePort* aMessagePort,
33 nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
34 : WorkerRunnable(aWorkerPrivate, aTarget,
35 aTarget == WorkerThread ? ModifyBusyCount : UnchangedBusyCount,
36 SkipWhenClearing),
37 mMessagePort(aMessagePort)
39 AssertIsOnMainThread();
40 MOZ_ASSERT(aMessagePort);
41 MOZ_ASSERT(aEvents.Length());
43 mEvents.SwapElements(aEvents);
46 bool
47 WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
50 } // anonymous namespace
52 MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
53 uint64_t aSerial)
54 : MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
55 mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
57 AssertIsOnMainThread();
58 MOZ_ASSERT(aSharedWorker);
59 SetIsDOMBinding();
62 MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
63 : mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
65 aWorkerPrivate->AssertIsOnWorkerThread();
66 SetIsDOMBinding();
69 MessagePort::~MessagePort()
71 Close();
74 void
75 MessagePort::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
76 const Optional<Sequence<JS::Value>>& aTransferable,
77 ErrorResult& aRv)
79 AssertCorrectThread();
81 if (IsClosed()) {
82 aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
83 return;
86 if (mSharedWorker) {
87 mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
89 else {
90 mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
91 aTransferable, aRv);
95 void
96 MessagePort::Start()
98 AssertCorrectThread();
100 if (IsClosed()) {
101 NS_WARNING("Called start() after calling close()!");
102 return;
105 if (mStarted) {
106 return;
109 mStarted = true;
111 if (!mQueuedEvents.IsEmpty()) {
112 WorkerRunnable::Target target = WorkerRunnable::WorkerThread;
113 WorkerPrivate* workerPrivate = mWorkerPrivate;
115 if (!workerPrivate) {
116 target = WorkerRunnable::ParentThread;
117 workerPrivate = mSharedWorker->GetWorkerPrivate();
120 nsRefPtr<DelayedEventRunnable> runnable =
121 new DelayedEventRunnable(workerPrivate, target, this, mQueuedEvents);
122 runnable->Dispatch(nullptr);
126 void
127 MessagePort::Close()
129 AssertCorrectThread();
131 if (!IsClosed()) {
132 CloseInternal();
136 void
137 MessagePort::QueueEvent(nsIDOMEvent* aEvent)
139 AssertCorrectThread();
140 MOZ_ASSERT(aEvent);
141 MOZ_ASSERT(!IsClosed());
142 MOZ_ASSERT(!mStarted);
144 mQueuedEvents.AppendElement(aEvent);
147 EventHandlerNonNull*
148 MessagePort::GetOnmessage()
150 AssertCorrectThread();
152 return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
153 : GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
156 void
157 MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
159 AssertCorrectThread();
161 if (NS_IsMainThread()) {
162 SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
164 else {
165 SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
168 Start();
171 already_AddRefed<MessagePortBase>
172 MessagePort::Clone()
174 NS_WARNING("Haven't implemented structured clone for these ports yet!");
175 return nullptr;
178 void
179 MessagePort::CloseInternal()
181 AssertCorrectThread();
182 MOZ_ASSERT(!IsClosed());
183 MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
185 NS_WARN_IF_FALSE(mStarted, "Called close() before start()!");
187 if (!mStarted) {
188 mQueuedEvents.Clear();
191 mSharedWorker = nullptr;
192 mWorkerPrivate = nullptr;
195 #ifdef DEBUG
196 void
197 MessagePort::AssertCorrectThread() const
199 if (IsClosed()) {
200 return; // Can't assert anything if we nulled out our pointers.
203 MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
204 !(mSharedWorker && mWorkerPrivate));
206 if (mSharedWorker) {
207 AssertIsOnMainThread();
209 else {
210 mWorkerPrivate->AssertIsOnWorkerThread();
213 #endif
215 NS_IMPL_ADDREF_INHERITED(MessagePort, nsDOMEventTargetHelper)
216 NS_IMPL_RELEASE_INHERITED(MessagePort, nsDOMEventTargetHelper)
218 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
219 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
221 NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
223 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
224 nsDOMEventTargetHelper)
225 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker)
226 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents)
227 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
229 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
230 nsDOMEventTargetHelper)
231 tmp->Close();
232 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
234 JSObject*
235 MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
237 AssertCorrectThread();
239 return MessagePortBinding::Wrap(aCx, aScope, this);
242 nsresult
243 MessagePort::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
245 AssertCorrectThread();
247 nsIDOMEvent*& event = aVisitor.mDOMEvent;
249 if (event) {
250 bool preventDispatch = false;
252 if (IsClosed()) {
253 preventDispatch = true;
254 } else if (NS_IsMainThread() && mSharedWorker->IsSuspended()) {
255 mSharedWorker->QueueEvent(event);
256 preventDispatch = true;
257 } else if (!mStarted) {
258 QueueEvent(event);
259 preventDispatch = true;
262 if (preventDispatch) {
263 aVisitor.mCanHandle = false;
264 aVisitor.mParentTarget = nullptr;
265 return NS_OK;
269 return nsDOMEventTargetHelper::PreHandleEvent(aVisitor);
272 bool
273 DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
275 MOZ_ASSERT(mMessagePort);
276 mMessagePort->AssertCorrectThread();
277 MOZ_ASSERT(mEvents.Length());
279 bool ignored;
280 for (uint32_t i = 0; i < mEvents.Length(); i++) {
281 mMessagePort->DispatchEvent(mEvents[i], &ignored);
284 return true;