mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Backed out changeset ccfddcbccdac (bug 1204775) for sharedworker bustage
This commit is contained in:
parent
3b656f6d65
commit
ab3e843b68
@ -114,7 +114,8 @@ PostMessageEvent::Run()
|
||||
false /*cancelable */, messageData, mCallerOrigin,
|
||||
EmptyString(), mSource);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
ports));
|
||||
|
@ -20,6 +20,9 @@ class nsPIDOMWindow;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MessagePortBase;
|
||||
class MessagePortIdentifier;
|
||||
|
||||
/**
|
||||
* Class used to represent events generated by calls to Window.postMessage,
|
||||
* which asynchronously creates and dispatches events.
|
||||
|
@ -1072,14 +1072,16 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx,
|
||||
}
|
||||
|
||||
{
|
||||
MessagePort* port = nullptr;
|
||||
MessagePortBase* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, aObj, port);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// We use aExtraData to store the index of this new port identifier.
|
||||
*aExtraData = mPortIdentifiers.Length();
|
||||
MessagePortIdentifier* identifier = mPortIdentifiers.AppendElement();
|
||||
|
||||
port->CloneAndDisentangle(*identifier);
|
||||
if (!port->CloneAndDisentangle(*identifier)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
|
||||
*aOwnership = JS::SCTAG_TMO_CUSTOM;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#define mozilla_dom_StructuredCloneHelper_h
|
||||
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
@ -112,7 +111,7 @@ protected:
|
||||
};
|
||||
|
||||
class BlobImpl;
|
||||
class MessagePort;
|
||||
class MessagePortBase;
|
||||
class MessagePortIdentifier;
|
||||
|
||||
class StructuredCloneHelper : public StructuredCloneHelperInternal
|
||||
@ -192,10 +191,11 @@ public:
|
||||
// This must be called if the transferring has ports generated by Read().
|
||||
// MessagePorts are not thread-safe and they must be retrieved in the thread
|
||||
// where they are created.
|
||||
nsTArray<nsRefPtr<MessagePort>>&& TakeTransferredPorts()
|
||||
void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
|
||||
{
|
||||
MOZ_ASSERT(mSupportsTransferring);
|
||||
return Move(mTransferredPorts);
|
||||
MOZ_ASSERT(aPorts.IsEmpty());
|
||||
aPorts.SwapElements(mTransferredPorts);
|
||||
}
|
||||
|
||||
nsTArray<MessagePortIdentifier>& PortIdentifiers()
|
||||
@ -291,7 +291,7 @@ protected:
|
||||
|
||||
// This array contains the ports once we've finished the reading. It's
|
||||
// generated from the mPortIdentifiers array.
|
||||
nsTArray<nsRefPtr<MessagePort>> mTransferredPorts;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> mTransferredPorts;
|
||||
|
||||
// This array contains the identifiers of the MessagePorts. Based on these we
|
||||
// are able to reconnect the new transferred ports with the other
|
||||
|
@ -739,6 +739,11 @@ DOMInterfaces = {
|
||||
'headerFile': 'MediaRecorder.h',
|
||||
},
|
||||
|
||||
'MessagePort': {
|
||||
'nativeType': 'mozilla::dom::MessagePortBase',
|
||||
'headerFile': 'mozilla/dom/MessagePort.h',
|
||||
},
|
||||
|
||||
'MimeType': {
|
||||
'headerFile' : 'nsMimeTypeArray.h',
|
||||
'nativeType': 'nsMimeType',
|
||||
|
@ -167,7 +167,7 @@ MessageEvent::Constructor(EventTarget* aEventTarget,
|
||||
}
|
||||
|
||||
if (aParam.mPorts.WasPassed() && !aParam.mPorts.Value().IsNull()) {
|
||||
nsTArray<nsRefPtr<MessagePort>> ports;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
|
||||
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace dom {
|
||||
|
||||
struct MessageEventInit;
|
||||
class MessagePort;
|
||||
class MessagePortBase;
|
||||
class MessagePortList;
|
||||
class OwningWindowProxyOrMessagePortOrClient;
|
||||
|
||||
@ -93,7 +94,7 @@ private:
|
||||
nsString mOrigin;
|
||||
nsString mLastEventId;
|
||||
nsCOMPtr<nsIDOMWindow> mWindowSource;
|
||||
nsRefPtr<MessagePort> mPortSource;
|
||||
nsRefPtr<MessagePortBase> mPortSource;
|
||||
nsRefPtr<workers::ServiceWorkerClient> mClientSource;
|
||||
nsRefPtr<MessagePortList> mPorts;
|
||||
};
|
||||
|
@ -49,12 +49,7 @@ MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
// window can be null in workers.
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
return Constructor(window, aRv);
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<MessageChannel>
|
||||
MessageChannel::Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv)
|
||||
{
|
||||
nsID portUUID1;
|
||||
aRv = nsContentUtils::GenerateUUIDInPlace(portUUID1);
|
||||
if (aRv.Failed()) {
|
||||
@ -67,14 +62,14 @@ MessageChannel::Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageChannel> channel = new MessageChannel(aWindow);
|
||||
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
|
||||
|
||||
channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
|
||||
channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
|
||||
channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -40,9 +40,6 @@ public:
|
||||
static already_AddRefed<MessageChannel>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
static already_AddRefed<MessageChannel>
|
||||
Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv);
|
||||
|
||||
MessagePort*
|
||||
Port1() const
|
||||
{
|
||||
|
@ -140,7 +140,8 @@ public:
|
||||
event->SetTrusted(true);
|
||||
event->SetSource(mPort);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
mData->TakeTransferredPorts(ports);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
@ -170,10 +171,19 @@ private:
|
||||
|
||||
NS_IMPL_ISUPPORTS(PostMessageRunnable, nsICancelableRunnable, nsIRunnable)
|
||||
|
||||
MessagePortBase::MessagePortBase(nsPIDOMWindow* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
{
|
||||
}
|
||||
|
||||
MessagePortBase::MessagePortBase()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
MessagePortBase)
|
||||
if (tmp->mDispatchRunnable) {
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
|
||||
}
|
||||
@ -184,7 +194,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
MessagePortBase)
|
||||
if (tmp->mDispatchRunnable) {
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
|
||||
}
|
||||
@ -195,10 +205,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCBackgroundChildCreateCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
NS_INTERFACE_MAP_END_INHERITING(MessagePortBase)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
|
||||
NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
|
||||
NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
|
||||
|
||||
namespace {
|
||||
|
||||
@ -277,7 +287,7 @@ NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
|
||||
} // namespace
|
||||
|
||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
|
||||
: DOMEventTargetHelper(aWindow)
|
||||
: MessagePortBase(aWindow)
|
||||
, mInnerID(0)
|
||||
, mMessageQueueEnabled(false)
|
||||
, mIsKeptAlive(false)
|
||||
@ -354,7 +364,16 @@ MessagePort::Initialize(const nsID& aUUID,
|
||||
// The port has to keep itself alive until it's entangled.
|
||||
UpdateMustKeepAlive();
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
if (NS_IsMainThread()) {
|
||||
MOZ_ASSERT(GetOwner());
|
||||
MOZ_ASSERT(GetOwner()->IsInnerWindow());
|
||||
mInnerID = GetOwner()->WindowID();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "inner-window-destroyed", false);
|
||||
}
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
MOZ_ASSERT(!mWorkerFeature);
|
||||
@ -367,15 +386,6 @@ MessagePort::Initialize(const nsID& aUUID,
|
||||
}
|
||||
|
||||
mWorkerFeature = Move(feature);
|
||||
} else if (GetOwner()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(GetOwner()->IsInnerWindow());
|
||||
mInnerID = GetOwner()->WindowID();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "inner-window-destroyed", false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,7 +414,7 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
continue;
|
||||
}
|
||||
|
||||
MessagePort* port = nullptr;
|
||||
MessagePortBase* port = nullptr;
|
||||
nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
@ -510,6 +520,11 @@ MessagePort::Dispatch()
|
||||
void
|
||||
MessagePort::Close()
|
||||
{
|
||||
// Not entangled yet, but already closed.
|
||||
if (mNextStep != eNextStepNone) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mState == eStateUnshippedEntangled) {
|
||||
MOZ_ASSERT(mUnshippedEntangledPort);
|
||||
|
||||
@ -525,7 +540,7 @@ MessagePort::Close()
|
||||
}
|
||||
|
||||
// Not entangled yet, we have to wait.
|
||||
if (mState == eStateEntangling) {
|
||||
if (mState < eStateEntangling) {
|
||||
mNextStep = eNextStepClose;
|
||||
return;
|
||||
}
|
||||
@ -684,7 +699,7 @@ MessagePort::Disentangle()
|
||||
UpdateMustKeepAlive();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||
{
|
||||
MOZ_ASSERT(mIdentifier);
|
||||
@ -695,13 +710,13 @@ MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||
aIdentifier.neutered() = true;
|
||||
|
||||
if (mState > eStateEntangled) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We already have a 'next step'. We have to consider this port as already
|
||||
// cloned/closed/disentangled.
|
||||
if (mNextStep != eNextStepNone) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
aIdentifier.uuid() = mIdentifier->uuid();
|
||||
@ -724,23 +739,24 @@ MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||
|
||||
mState = eStateDisentangled;
|
||||
UpdateMustKeepAlive();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Register this component to PBackground.
|
||||
ConnectToPBackground();
|
||||
|
||||
mNextStep = eNextStepDisentangle;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not entangled yet, we have to wait.
|
||||
if (mState < eStateEntangled) {
|
||||
mNextStep = eNextStepDisentangle;
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
StartDisentangling();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -31,7 +31,41 @@ namespace workers {
|
||||
class WorkerFeature;
|
||||
} // namespace workers
|
||||
|
||||
class MessagePort final : public DOMEventTargetHelper
|
||||
class MessagePortBase : public DOMEventTargetHelper
|
||||
{
|
||||
protected:
|
||||
explicit MessagePortBase(nsPIDOMWindow* aWindow);
|
||||
MessagePortBase();
|
||||
|
||||
public:
|
||||
|
||||
virtual void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv) = 0;
|
||||
|
||||
virtual void
|
||||
Start() = 0;
|
||||
|
||||
virtual void
|
||||
Close() = 0;
|
||||
|
||||
// The 'message' event handler has to call |Start()| method, so we
|
||||
// cannot use IMPL_EVENT_HANDLER macro here.
|
||||
virtual EventHandlerNonNull*
|
||||
GetOnmessage() = 0;
|
||||
|
||||
virtual void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback) = 0;
|
||||
|
||||
// Duplicate this message port. This method is used by the Structured Clone
|
||||
// Algorithm and populates a MessagePortIdentifier object with the information
|
||||
// useful to create new MessagePort.
|
||||
virtual bool
|
||||
CloneAndDisentangle(MessagePortIdentifier& aIdentifier) = 0;
|
||||
};
|
||||
|
||||
class MessagePort final : public MessagePortBase
|
||||
, public nsIIPCBackgroundChildCreateCallback
|
||||
, public nsIObserver
|
||||
{
|
||||
@ -42,7 +76,7 @@ public:
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
MessagePortBase)
|
||||
|
||||
static already_AddRefed<MessagePort>
|
||||
Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
|
||||
@ -58,24 +92,24 @@ public:
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void
|
||||
virtual void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
void Start();
|
||||
virtual void Start() override;
|
||||
|
||||
void Close();
|
||||
virtual void Close() override;
|
||||
|
||||
EventHandlerNonNull* GetOnmessage();
|
||||
virtual EventHandlerNonNull* GetOnmessage() override;
|
||||
|
||||
void SetOnmessage(EventHandlerNonNull* aCallback);
|
||||
virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
|
||||
|
||||
// Non WebIDL methods
|
||||
|
||||
void UnshippedEntangle(MessagePort* aEntangledPort);
|
||||
|
||||
void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
|
||||
virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
|
||||
|
||||
// These methods are useful for MessagePortChild
|
||||
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
public:
|
||||
MessagePortList(nsISupports* aOwner,
|
||||
const nsTArray<nsRefPtr<MessagePort>>& aPorts)
|
||||
const nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
|
||||
: mOwner(aOwner)
|
||||
, mPorts(aPorts)
|
||||
{
|
||||
@ -50,13 +50,13 @@ public:
|
||||
return mPorts.Length();
|
||||
}
|
||||
|
||||
MessagePort*
|
||||
MessagePortBase*
|
||||
Item(uint32_t aIndex)
|
||||
{
|
||||
return mPorts.SafeElementAt(aIndex);
|
||||
}
|
||||
|
||||
MessagePort*
|
||||
MessagePortBase*
|
||||
IndexedGetter(uint32_t aIndex, bool &aFound)
|
||||
{
|
||||
aFound = aIndex < mPorts.Length();
|
||||
@ -68,7 +68,7 @@ public:
|
||||
|
||||
public:
|
||||
nsCOMPtr<nsISupports> mOwner;
|
||||
nsTArray<nsRefPtr<MessagePort>> mPorts;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> mPorts;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
318
dom/workers/MessagePort.cpp
Normal file
318
dom/workers/MessagePort.cpp
Normal file
@ -0,0 +1,318 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MessagePort.h"
|
||||
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
using mozilla::dom::EventHandlerNonNull;
|
||||
using mozilla::dom::MessagePortBase;
|
||||
using mozilla::dom::MessagePortIdentifier;
|
||||
using mozilla::dom::Optional;
|
||||
using mozilla::dom::Sequence;
|
||||
using mozilla::dom::AutoNoJSAPI;
|
||||
using namespace mozilla;
|
||||
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
namespace {
|
||||
|
||||
class DelayedEventRunnable final : public WorkerRunnable
|
||||
{
|
||||
nsRefPtr<mozilla::dom::workers::MessagePort> mMessagePort;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mEvents;
|
||||
|
||||
public:
|
||||
DelayedEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior,
|
||||
mozilla::dom::workers::MessagePort* aMessagePort,
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>>& aEvents)
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior), mMessagePort(aMessagePort)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aMessagePort);
|
||||
MOZ_ASSERT(aEvents.Length());
|
||||
|
||||
mEvents.SwapElements(aEvents);
|
||||
}
|
||||
|
||||
bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
return aWorkerPrivate->ModifyBusyCount(aCx, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult)
|
||||
{
|
||||
if (!aDispatchResult) {
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
aWorkerPrivate->ModifyBusyCount(aCx, false);
|
||||
}
|
||||
if (aCx) {
|
||||
JS_ReportPendingException(aCx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
MessagePort::MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
|
||||
uint64_t aSerial)
|
||||
: MessagePortBase(aWindow), mSharedWorker(aSharedWorker),
|
||||
mWorkerPrivate(nullptr), mSerial(aSerial), mStarted(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
}
|
||||
|
||||
MessagePort::MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial)
|
||||
: mWorkerPrivate(aWorkerPrivate), mSerial(aSerial), mStarted(false)
|
||||
{
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
MessagePort::~MessagePort()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (IsClosed()) {
|
||||
aRv = NS_ERROR_DOM_INVALID_STATE_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSharedWorker) {
|
||||
mSharedWorker->PostMessage(aCx, aMessage, aTransferable, aRv);
|
||||
}
|
||||
else {
|
||||
mWorkerPrivate->PostMessageToParentMessagePort(aCx, Serial(), aMessage,
|
||||
aTransferable, aRv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::Start()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (IsClosed()) {
|
||||
NS_WARNING("Called start() after calling close()!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mStarted) {
|
||||
return;
|
||||
}
|
||||
|
||||
mStarted = true;
|
||||
|
||||
if (!mQueuedEvents.IsEmpty()) {
|
||||
WorkerPrivate* workerPrivate;
|
||||
WorkerRunnable::TargetAndBusyBehavior behavior;
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
workerPrivate = mWorkerPrivate;
|
||||
behavior = WorkerRunnable::WorkerThreadModifyBusyCount;
|
||||
}
|
||||
else {
|
||||
workerPrivate = mSharedWorker->GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
behavior = WorkerRunnable::ParentThreadUnchangedBusyCount;
|
||||
}
|
||||
|
||||
nsRefPtr<DelayedEventRunnable> runnable =
|
||||
new DelayedEventRunnable(workerPrivate, behavior, this, mQueuedEvents);
|
||||
runnable->Dispatch(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::Close()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (!IsClosed()) {
|
||||
CloseInternal();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::QueueEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
MOZ_ASSERT(aEvent);
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
MOZ_ASSERT(!mStarted);
|
||||
|
||||
mQueuedEvents.AppendElement(aEvent);
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
MessagePort::GetOnmessage()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
return NS_IsMainThread() ? GetEventHandler(nsGkAtoms::onmessage, EmptyString())
|
||||
: GetEventHandler(nullptr, NS_LITERAL_STRING("message"));
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::SetOnmessage(EventHandlerNonNull* aCallback)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback);
|
||||
}
|
||||
else {
|
||||
SetEventHandler(nullptr, NS_LITERAL_STRING("message"), aCallback);
|
||||
}
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
bool
|
||||
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
|
||||
{
|
||||
NS_WARNING("Haven't implemented structured clone for these ports yet!");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MessagePort::CloseInternal()
|
||||
{
|
||||
AssertCorrectThread();
|
||||
MOZ_ASSERT(!IsClosed());
|
||||
MOZ_ASSERT_IF(mStarted, mQueuedEvents.IsEmpty());
|
||||
|
||||
if (!mStarted) {
|
||||
mQueuedEvents.Clear();
|
||||
}
|
||||
|
||||
mSharedWorker = nullptr;
|
||||
mWorkerPrivate = nullptr;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
MessagePort::AssertCorrectThread() const
|
||||
{
|
||||
if (IsClosed()) {
|
||||
return; // Can't assert anything if we nulled out our pointers.
|
||||
}
|
||||
|
||||
MOZ_ASSERT((mSharedWorker || mWorkerPrivate) &&
|
||||
!(mSharedWorker && mWorkerPrivate));
|
||||
|
||||
if (mSharedWorker) {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
else {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(mozilla::dom::workers::MessagePort, DOMEventTargetHelper)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MessagePort)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MessagePort)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSharedWorker)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mQueuedEvents)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
|
||||
DOMEventTargetHelper)
|
||||
tmp->Close();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
JSObject*
|
||||
MessagePort::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
return MessagePortBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MessagePort::PreHandleEvent(EventChainPreVisitor& aVisitor)
|
||||
{
|
||||
AssertCorrectThread();
|
||||
|
||||
nsIDOMEvent*& event = aVisitor.mDOMEvent;
|
||||
|
||||
if (event) {
|
||||
bool preventDispatch = false;
|
||||
|
||||
if (IsClosed()) {
|
||||
preventDispatch = true;
|
||||
} else if (NS_IsMainThread() && mSharedWorker->IsFrozen()) {
|
||||
mSharedWorker->QueueEvent(event);
|
||||
preventDispatch = true;
|
||||
} else if (!mStarted) {
|
||||
QueueEvent(event);
|
||||
preventDispatch = true;
|
||||
}
|
||||
|
||||
if (preventDispatch) {
|
||||
aVisitor.mCanHandle = false;
|
||||
aVisitor.mParentTarget = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return DOMEventTargetHelper::PreHandleEvent(aVisitor);
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
bool
|
||||
DelayedEventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(mMessagePort);
|
||||
mMessagePort->AssertCorrectThread();
|
||||
MOZ_ASSERT(mEvents.Length());
|
||||
|
||||
AutoNoJSAPI nojsapi;
|
||||
|
||||
bool ignored;
|
||||
for (uint32_t i = 0; i < mEvents.Length(); i++) {
|
||||
mMessagePort->DispatchEvent(mEvents[i], &ignored);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
112
dom/workers/MessagePort.h
Normal file
112
dom/workers/MessagePort.h
Normal file
@ -0,0 +1,112 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_messageport_h_
|
||||
#define mozilla_dom_workers_messageport_h_
|
||||
|
||||
#include "mozilla/dom/workers/Workers.h"
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class SharedWorker;
|
||||
class WorkerPrivate;
|
||||
|
||||
class MessagePort final : public mozilla::dom::MessagePortBase
|
||||
{
|
||||
friend class SharedWorker;
|
||||
friend class WorkerPrivate;
|
||||
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
|
||||
nsRefPtr<SharedWorker> mSharedWorker;
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mQueuedEvents;
|
||||
uint64_t mSerial;
|
||||
bool mStarted;
|
||||
|
||||
public:
|
||||
static bool
|
||||
PrefEnabled();
|
||||
|
||||
virtual void
|
||||
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv) override;
|
||||
|
||||
virtual void
|
||||
Start() override;
|
||||
|
||||
virtual void
|
||||
Close() override;
|
||||
|
||||
uint64_t
|
||||
Serial() const
|
||||
{
|
||||
return mSerial;
|
||||
}
|
||||
|
||||
void
|
||||
QueueEvent(nsIDOMEvent* aEvent);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort, DOMEventTargetHelper)
|
||||
|
||||
virtual EventHandlerNonNull*
|
||||
GetOnmessage() override;
|
||||
|
||||
virtual void
|
||||
SetOnmessage(EventHandlerNonNull* aCallback) override;
|
||||
|
||||
virtual bool
|
||||
CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
|
||||
|
||||
bool
|
||||
IsClosed() const
|
||||
{
|
||||
return !mSharedWorker && !mWorkerPrivate;
|
||||
}
|
||||
|
||||
virtual JSObject*
|
||||
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
virtual nsresult
|
||||
PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
AssertCorrectThread() const;
|
||||
#else
|
||||
void
|
||||
AssertCorrectThread() const { }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// This class can only be created by SharedWorker or WorkerPrivate.
|
||||
MessagePort(nsPIDOMWindow* aWindow, SharedWorker* aSharedWorker,
|
||||
uint64_t aSerial);
|
||||
MessagePort(WorkerPrivate* aWorkerPrivate, uint64_t aSerial);
|
||||
|
||||
// This class is reference-counted and will be destroyed from Release().
|
||||
~MessagePort();
|
||||
|
||||
void
|
||||
CloseInternal();
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_messageport_h_
|
@ -34,7 +34,6 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ErrorEventBinding.h"
|
||||
#include "mozilla/dom/EventTargetBinding.h"
|
||||
#include "mozilla/dom/MessageChannel.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
@ -2494,8 +2493,8 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
nsCOMPtr<nsPIDOMWindow> window = aLoadInfo->mWindow;
|
||||
|
||||
bool created = false;
|
||||
ErrorResult rv;
|
||||
if (!workerPrivate) {
|
||||
ErrorResult rv;
|
||||
workerPrivate =
|
||||
WorkerPrivate::Constructor(aCx, aScriptURL, false,
|
||||
aType, aName, aLoadInfo, rv);
|
||||
@ -2509,18 +2508,9 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
||||
workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
|
||||
}
|
||||
|
||||
// We don't actually care about this MessageChannel, but we use it to 'steal'
|
||||
// its 2 connected ports.
|
||||
nsRefPtr<MessageChannel> channel = MessageChannel::Constructor(window, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
|
||||
|
||||
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
|
||||
channel->Port1());
|
||||
|
||||
if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker,
|
||||
channel->Port2())) {
|
||||
if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
|
||||
NS_WARNING("Worker is unreachable, this shouldn't happen!");
|
||||
sharedWorker->Close();
|
||||
return NS_ERROR_FAILURE;
|
||||
|
@ -138,7 +138,8 @@ private:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsILineInputStream.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsISafeOutputStream.h"
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
|
@ -10,12 +10,12 @@
|
||||
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/SharedWorkerBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
|
||||
#include "MessagePort.h"
|
||||
#include "RuntimeService.h"
|
||||
#include "WorkerPrivate.h"
|
||||
|
||||
@ -26,14 +26,16 @@ using namespace mozilla;
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
MessagePort* aMessagePort)
|
||||
: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate)
|
||||
, mMessagePort(aMessagePort)
|
||||
, mFrozen(false)
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
|
||||
mFrozen(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
|
||||
mSerial = aWorkerPrivate->NextMessagePortSerial();
|
||||
|
||||
mMessagePort = new MessagePort(aWindow, this, mSerial);
|
||||
}
|
||||
|
||||
SharedWorker::~SharedWorker()
|
||||
@ -74,11 +76,13 @@ SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
return sharedWorker.forget();
|
||||
}
|
||||
|
||||
MessagePort*
|
||||
already_AddRefed<mozilla::dom::workers::MessagePort>
|
||||
SharedWorker::Port()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
return mMessagePort;
|
||||
|
||||
nsRefPtr<MessagePort> messagePort = mMessagePort;
|
||||
return messagePort.forget();
|
||||
}
|
||||
|
||||
void
|
||||
@ -153,7 +157,8 @@ SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
MOZ_ASSERT(mMessagePort);
|
||||
|
||||
mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
|
||||
mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(),
|
||||
aMessage, aTransferable, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "Workers.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/workers/bindings/MessagePort.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
|
||||
class nsIDOMEvent;
|
||||
@ -17,19 +18,17 @@ class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
|
||||
namespace dom {
|
||||
class MessagePort;
|
||||
}
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class MessagePort;
|
||||
class RuntimeService;
|
||||
class WorkerPrivate;
|
||||
|
||||
class SharedWorker final : public DOMEventTargetHelper
|
||||
{
|
||||
friend class MessagePort;
|
||||
friend class RuntimeService;
|
||||
|
||||
typedef mozilla::ErrorResult ErrorResult;
|
||||
@ -38,6 +37,7 @@ class SharedWorker final : public DOMEventTargetHelper
|
||||
nsRefPtr<WorkerPrivate> mWorkerPrivate;
|
||||
nsRefPtr<MessagePort> mMessagePort;
|
||||
nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
|
||||
uint64_t mSerial;
|
||||
bool mFrozen;
|
||||
|
||||
public:
|
||||
@ -46,9 +46,15 @@ public:
|
||||
const nsAString& aScriptURL, const Optional<nsAString>& aName,
|
||||
ErrorResult& aRv);
|
||||
|
||||
MessagePort*
|
||||
already_AddRefed<mozilla::dom::workers::MessagePort>
|
||||
Port();
|
||||
|
||||
uint64_t
|
||||
Serial() const
|
||||
{
|
||||
return mSerial;
|
||||
}
|
||||
|
||||
bool
|
||||
IsFrozen() const
|
||||
{
|
||||
@ -87,8 +93,7 @@ public:
|
||||
private:
|
||||
// This class can only be created from the RuntimeService.
|
||||
SharedWorker(nsPIDOMWindow* aWindow,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
MessagePort* aMessagePort);
|
||||
WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
// This class is reference-counted and will be destroyed from Release().
|
||||
~SharedWorker();
|
||||
|
@ -54,7 +54,6 @@
|
||||
#include "mozilla/dom/MessagePort.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/MessagePortList.h"
|
||||
#include "mozilla/dom/PMessagePort.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/PromiseDebugging.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
@ -89,6 +88,7 @@
|
||||
#include "nsThreadManager.h"
|
||||
#endif
|
||||
|
||||
#include "MessagePort.h"
|
||||
#include "Navigator.h"
|
||||
#include "Principal.h"
|
||||
#include "RuntimeService.h"
|
||||
@ -594,15 +594,21 @@ private:
|
||||
class MessageEventRunnable final : public WorkerRunnable
|
||||
, public StructuredCloneHelper
|
||||
{
|
||||
uint64_t mMessagePortSerial;
|
||||
bool mToMessagePort;
|
||||
|
||||
// This is only used for messages dispatched to a service worker.
|
||||
nsAutoPtr<ServiceWorkerClientInfo> mEventSource;
|
||||
|
||||
public:
|
||||
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior)
|
||||
TargetAndBusyBehavior aBehavior,
|
||||
bool aToMessagePort, uint64_t aMessagePortSerial)
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior)
|
||||
, StructuredCloneHelper(CloningSupported, TransferringSupported,
|
||||
SameProcessDifferentThread)
|
||||
, mMessagePortSerial(aMessagePortSerial)
|
||||
, mToMessagePort(aToMessagePort)
|
||||
{
|
||||
}
|
||||
|
||||
@ -648,7 +654,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
TakeTransferredPorts(ports);
|
||||
|
||||
event->SetTrusted(true);
|
||||
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
|
||||
@ -664,6 +671,8 @@ private:
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
MOZ_ASSERT_IF(mToMessagePort, aWorkerPrivate->IsSharedWorker());
|
||||
|
||||
if (mBehavior == ParentThreadUnchangedBusyCount) {
|
||||
// Don't fire this event if the JS object has been disconnected from the
|
||||
// private object.
|
||||
@ -671,6 +680,13 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mToMessagePort) {
|
||||
return
|
||||
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
|
||||
mMessagePortSerial,
|
||||
*this);
|
||||
}
|
||||
|
||||
if (aWorkerPrivate->IsFrozen()) {
|
||||
aWorkerPrivate->QueueRunnable(this);
|
||||
return true;
|
||||
@ -684,6 +700,16 @@ private:
|
||||
|
||||
MOZ_ASSERT(aWorkerPrivate == GetWorkerPrivateFromContext(aCx));
|
||||
|
||||
if (mToMessagePort) {
|
||||
nsRefPtr<workers::MessagePort> port =
|
||||
aWorkerPrivate->GetMessagePort(mMessagePortSerial);
|
||||
if (!port) {
|
||||
// Must have been closed already.
|
||||
return true;
|
||||
}
|
||||
return DispatchDOMEvent(aCx, aWorkerPrivate, port, false);
|
||||
}
|
||||
|
||||
return DispatchDOMEvent(aCx, aWorkerPrivate, aWorkerPrivate->GlobalScope(),
|
||||
false);
|
||||
}
|
||||
@ -1495,19 +1521,18 @@ public:
|
||||
|
||||
class MessagePortRunnable final : public WorkerRunnable
|
||||
{
|
||||
MessagePortIdentifier mPortIdentifier;
|
||||
uint64_t mMessagePortSerial;
|
||||
bool mConnect;
|
||||
|
||||
public:
|
||||
MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
MessagePort* aPort)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
{
|
||||
MOZ_ASSERT(aPort);
|
||||
// In order to move the port from one thread to another one, we have to
|
||||
// close and disentangle it. The output will be a MessagePortIdentifier that
|
||||
// will be used to recreate a new MessagePort on the other thread.
|
||||
aPort->CloneAndDisentangle(mPortIdentifier);
|
||||
}
|
||||
uint64_t aMessagePortSerial,
|
||||
bool aConnect)
|
||||
: WorkerRunnable(aWorkerPrivate, aConnect ?
|
||||
WorkerThreadModifyBusyCount :
|
||||
WorkerThreadUnchangedBusyCount),
|
||||
mMessagePortSerial(aMessagePortSerial), mConnect(aConnect)
|
||||
{ }
|
||||
|
||||
private:
|
||||
~MessagePortRunnable()
|
||||
@ -1516,7 +1541,12 @@ private:
|
||||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
|
||||
{
|
||||
return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
|
||||
if (mConnect) {
|
||||
return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial);
|
||||
}
|
||||
|
||||
aWorkerPrivate->DisconnectMessagePort(mMessagePortSerial);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@ -2092,7 +2122,8 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
|
||||
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
|
||||
mParent(aParent), mScriptURL(aScriptURL),
|
||||
mSharedWorkerName(aSharedWorkerName), mLoadingWorkerScript(false),
|
||||
mBusyCount(0), mParentStatus(Pending), mParentFrozen(false),
|
||||
mBusyCount(0), mMessagePortSerial(0),
|
||||
mParentStatus(Pending), mParentFrozen(false),
|
||||
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
|
||||
mWorkerType(aWorkerType),
|
||||
mCreationTimeStamp(TimeStamp::Now()),
|
||||
@ -2456,29 +2487,55 @@ WorkerPrivateParent<Derived>::Freeze(JSContext* aCx, nsPIDOMWindow* aWindow)
|
||||
// Shared workers are only frozen if all of their owning documents are
|
||||
// frozen. It can happen that mSharedWorkers is empty but this thread has
|
||||
// not been unregistered yet.
|
||||
if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
|
||||
if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
bool allFrozen = false;
|
||||
struct Closure
|
||||
{
|
||||
nsPIDOMWindow* mWindow;
|
||||
bool mAllFrozen;
|
||||
|
||||
for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
|
||||
if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
|
||||
// Calling Freeze() may change the refcount, ensure that the worker
|
||||
// outlives this call.
|
||||
nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
|
||||
|
||||
mSharedWorkers[i]->Freeze();
|
||||
} else {
|
||||
MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
|
||||
!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
|
||||
aWindow));
|
||||
if (!mSharedWorkers[i]->IsFrozen()) {
|
||||
allFrozen = false;
|
||||
}
|
||||
explicit Closure(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow), mAllFrozen(true)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
// aWindow may be null here.
|
||||
}
|
||||
}
|
||||
|
||||
if (!allFrozen || mParentFrozen) {
|
||||
static PLDHashOperator
|
||||
Freeze(const uint64_t& aKey,
|
||||
SharedWorker* aSharedWorker,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto closure = static_cast<Closure*>(aClosure);
|
||||
|
||||
if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
|
||||
// Calling Freeze() may change the refcount, ensure that the worker
|
||||
// outlives this call.
|
||||
nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
|
||||
|
||||
aSharedWorker->Freeze();
|
||||
} else {
|
||||
MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
|
||||
!SameCOMIdentity(aSharedWorker->GetOwner(),
|
||||
closure->mWindow));
|
||||
if (!aSharedWorker->IsFrozen()) {
|
||||
closure->mAllFrozen = false;
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
Closure closure(aWindow);
|
||||
|
||||
mSharedWorkers.EnumerateRead(Closure::Freeze, &closure);
|
||||
|
||||
if (!closure.mAllFrozen || mParentFrozen) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2519,30 +2576,56 @@ WorkerPrivateParent<Derived>::Thaw(JSContext* aCx, nsPIDOMWindow* aWindow)
|
||||
// Shared workers are resumed if any of their owning documents are thawed.
|
||||
// It can happen that mSharedWorkers is empty but this thread has not been
|
||||
// unregistered yet.
|
||||
if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
|
||||
if ((IsSharedWorker() || IsServiceWorker()) && mSharedWorkers.Count()) {
|
||||
AssertIsOnMainThread();
|
||||
|
||||
bool anyRunning = false;
|
||||
struct Closure
|
||||
{
|
||||
nsPIDOMWindow* mWindow;
|
||||
bool mAnyRunning;
|
||||
|
||||
for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
|
||||
if (aWindow && mSharedWorkers[i]->GetOwner() == aWindow) {
|
||||
// Calling Thaw() may change the refcount, ensure that the worker
|
||||
// outlives this call.
|
||||
nsRefPtr<SharedWorker> kungFuDeathGrip = mSharedWorkers[i];
|
||||
|
||||
mSharedWorkers[i]->Thaw();
|
||||
anyRunning = true;
|
||||
} else {
|
||||
MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
|
||||
!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
|
||||
aWindow));
|
||||
if (!mSharedWorkers[i]->IsFrozen()) {
|
||||
anyRunning = true;
|
||||
}
|
||||
explicit Closure(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow), mAnyRunning(false)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
// aWindow may be null here.
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyRunning || !mParentFrozen) {
|
||||
static PLDHashOperator
|
||||
Thaw(const uint64_t& aKey,
|
||||
SharedWorker* aSharedWorker,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto closure = static_cast<Closure*>(aClosure);
|
||||
|
||||
if (closure->mWindow && aSharedWorker->GetOwner() == closure->mWindow) {
|
||||
// Calling Thaw() may change the refcount, ensure that the worker
|
||||
// outlives this call.
|
||||
nsRefPtr<SharedWorker> kungFuDeathGrip = aSharedWorker;
|
||||
|
||||
aSharedWorker->Thaw();
|
||||
closure->mAnyRunning = true;
|
||||
} else {
|
||||
MOZ_ASSERT_IF(aSharedWorker->GetOwner() && closure->mWindow,
|
||||
!SameCOMIdentity(aSharedWorker->GetOwner(),
|
||||
closure->mWindow));
|
||||
if (!aSharedWorker->IsFrozen()) {
|
||||
closure->mAnyRunning = true;
|
||||
}
|
||||
}
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
Closure closure(aWindow);
|
||||
|
||||
mSharedWorkers.EnumerateRead(Closure::Thaw, &closure);
|
||||
|
||||
if (!closure.mAnyRunning || !mParentFrozen) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2679,6 +2762,8 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial,
|
||||
ServiceWorkerClientInfo* aClientInfo,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
@ -2712,7 +2797,8 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
|
||||
|
||||
nsRefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(ParentAsWorkerPrivate(),
|
||||
WorkerRunnable::WorkerThreadModifyBusyCount);
|
||||
WorkerRunnable::WorkerThreadModifyBusyCount,
|
||||
aToMessagePort, aMessagePortSerial);
|
||||
|
||||
runnable->Write(aCx, aMessage, transferable, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -2735,7 +2821,88 @@ WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, aClientInfo.forget(), aRv);
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, false, 0,
|
||||
aClientInfo.forget(), aRv);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::PostMessageToMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, true, aMessagePortSerial,
|
||||
nullptr, aRv);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
bool
|
||||
WorkerPrivateParent<Derived>::DispatchMessageEventToMessagePort(
|
||||
JSContext* aCx, uint64_t aMessagePortSerial,
|
||||
StructuredCloneHelper& aHelper)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
SharedWorker* sharedWorker;
|
||||
if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) {
|
||||
// SharedWorker has already been unregistered?
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<MessagePort> port = sharedWorker->Port();
|
||||
NS_ASSERTION(port, "SharedWorkers always have a port!");
|
||||
|
||||
if (port->IsClosed()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> parent = do_QueryInterface(port->GetParentObject());
|
||||
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(port->GetParentObject()))) {
|
||||
return false;
|
||||
}
|
||||
JSContext* cx = jsapi.cx();
|
||||
|
||||
ErrorResult rv;
|
||||
JS::Rooted<JS::Value> data(cx);
|
||||
aHelper.Read(parent, cx, &data, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<MessageEvent> event = new MessageEvent(port, nullptr, nullptr);
|
||||
rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false, false, data,
|
||||
EmptyString(), EmptyString(), nullptr);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
aHelper.TakeTransferredPorts(ports);
|
||||
|
||||
event->SetTrusted(true);
|
||||
event->SetPorts(new MessagePortList(port, ports));
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent;
|
||||
CallQueryInterface(event.get(), getter_AddRefs(domEvent));
|
||||
NS_ASSERTION(domEvent, "This should never fail!");
|
||||
|
||||
bool ignored;
|
||||
rv = port->DispatchEvent(domEvent, &ignored);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
xpc::Throw(cx, rv.StealNSResult());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
@ -2923,27 +3090,27 @@ WorkerPrivate::OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline)
|
||||
template <class Derived>
|
||||
bool
|
||||
WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
|
||||
SharedWorker* aSharedWorker,
|
||||
MessagePort* aPort)
|
||||
SharedWorker* aSharedWorker)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
|
||||
MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
|
||||
MOZ_ASSERT(!mSharedWorkers.Get(aSharedWorker->Serial()));
|
||||
|
||||
if (IsSharedWorker()) {
|
||||
nsRefPtr<MessagePortRunnable> runnable =
|
||||
new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
|
||||
new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
|
||||
true);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mSharedWorkers.AppendElement(aSharedWorker);
|
||||
mSharedWorkers.Put(aSharedWorker->Serial(), aSharedWorker);
|
||||
|
||||
// If there were other SharedWorker objects attached to this worker then they
|
||||
// may all have been frozen and this worker would need to be thawed.
|
||||
if (mSharedWorkers.Length() > 1 && !Thaw(aCx, nullptr)) {
|
||||
if (mSharedWorkers.Count() > 1 && !Thaw(aCx, nullptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2959,14 +3126,21 @@ WorkerPrivateParent<Derived>::UnregisterSharedWorker(
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
|
||||
MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
|
||||
MOZ_ASSERT(mSharedWorkers.Get(aSharedWorker->Serial()));
|
||||
|
||||
mSharedWorkers.RemoveElement(aSharedWorker);
|
||||
nsRefPtr<MessagePortRunnable> runnable =
|
||||
new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
|
||||
false);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
JS_ReportPendingException(aCx);
|
||||
}
|
||||
|
||||
mSharedWorkers.Remove(aSharedWorker->Serial());
|
||||
|
||||
// If there are still SharedWorker objects attached to this worker then they
|
||||
// may all be frozen and this worker would need to be frozen. Otherwise,
|
||||
// if that was the last SharedWorker then it's time to cancel this worker.
|
||||
if (!mSharedWorkers.IsEmpty()) {
|
||||
if (mSharedWorkers.Count()) {
|
||||
if (!Freeze(aCx, nullptr)) {
|
||||
JS_ReportPendingException(aCx);
|
||||
}
|
||||
@ -3104,13 +3278,29 @@ WorkerPrivateParent<Derived>::GetAllSharedWorkers(
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
|
||||
|
||||
struct Helper
|
||||
{
|
||||
static PLDHashOperator
|
||||
Collect(const uint64_t& aKey,
|
||||
SharedWorker* aSharedWorker,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto array = static_cast<nsTArray<nsRefPtr<SharedWorker>>*>(aClosure);
|
||||
array->AppendElement(aSharedWorker);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
if (!aSharedWorkers.IsEmpty()) {
|
||||
aSharedWorkers.Clear();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
|
||||
aSharedWorkers.AppendElement(mSharedWorkers[i]);
|
||||
}
|
||||
mSharedWorkers.EnumerateRead(Helper::Collect, &aSharedWorkers);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
@ -3122,19 +3312,47 @@ WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
|
||||
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
|
||||
MOZ_ASSERT(aWindow);
|
||||
|
||||
nsAutoTArray<nsRefPtr<SharedWorker>, 10> sharedWorkers;
|
||||
struct Closure
|
||||
{
|
||||
nsPIDOMWindow* mWindow;
|
||||
nsAutoTArray<nsRefPtr<SharedWorker>, 10> mSharedWorkers;
|
||||
|
||||
for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
|
||||
if (mSharedWorkers[i]->GetOwner() == aWindow) {
|
||||
sharedWorkers.AppendElement(mSharedWorkers[i]);
|
||||
} else {
|
||||
MOZ_ASSERT(!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
|
||||
aWindow));
|
||||
explicit Closure(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aWindow);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t index = 0; index < sharedWorkers.Length(); index++) {
|
||||
sharedWorkers[index]->Close();
|
||||
static PLDHashOperator
|
||||
Collect(const uint64_t& aKey,
|
||||
SharedWorker* aSharedWorker,
|
||||
void* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(aSharedWorker);
|
||||
MOZ_ASSERT(aClosure);
|
||||
|
||||
auto closure = static_cast<Closure*>(aClosure);
|
||||
MOZ_ASSERT(closure->mWindow);
|
||||
|
||||
if (aSharedWorker->GetOwner() == closure->mWindow) {
|
||||
closure->mSharedWorkers.AppendElement(aSharedWorker);
|
||||
} else {
|
||||
MOZ_ASSERT(!SameCOMIdentity(aSharedWorker->GetOwner(),
|
||||
closure->mWindow));
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
};
|
||||
|
||||
Closure closure(aWindow);
|
||||
|
||||
mSharedWorkers.EnumerateRead(Closure::Collect, &closure);
|
||||
|
||||
for (uint32_t index = 0; index < closure.mSharedWorkers.Length(); index++) {
|
||||
closure.mSharedWorkers[index]->Close();
|
||||
}
|
||||
}
|
||||
|
||||
@ -4370,6 +4588,9 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
|
||||
}
|
||||
}
|
||||
|
||||
// Clear away our MessagePorts.
|
||||
mWorkerPorts.Clear();
|
||||
|
||||
// Unroot the globals
|
||||
mScope = nullptr;
|
||||
mDebuggerScope = nullptr;
|
||||
@ -5307,6 +5528,8 @@ WorkerPrivate::PostMessageToParentInternal(
|
||||
JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
@ -5331,7 +5554,8 @@ WorkerPrivate::PostMessageToParentInternal(
|
||||
|
||||
nsRefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(this,
|
||||
WorkerRunnable::ParentThreadUnchangedBusyCount);
|
||||
WorkerRunnable::ParentThreadUnchangedBusyCount,
|
||||
aToMessagePort, aMessagePortSerial);
|
||||
|
||||
runnable->Write(aCx, aMessage, transferable, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
@ -5343,6 +5567,26 @@ WorkerPrivate::PostMessageToParentInternal(
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::PostMessageToParentMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
if (!mWorkerPorts.GetWeak(aMessagePortSerial)) {
|
||||
// This port has been closed from the main thread. There's no point in
|
||||
// sending this message so just bail.
|
||||
return;
|
||||
}
|
||||
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, true,
|
||||
aMessagePortSerial, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::EnterDebuggerEventLoop()
|
||||
{
|
||||
@ -6200,23 +6444,19 @@ WorkerPrivate::EndCTypesCall()
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::ConnectMessagePort(JSContext* aCx,
|
||||
MessagePortIdentifier& aIdentifier)
|
||||
WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
|
||||
"Already have this port registered!");
|
||||
|
||||
WorkerGlobalScope* globalScope = GlobalScope();
|
||||
|
||||
JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
|
||||
MOZ_ASSERT(jsGlobal);
|
||||
|
||||
// This MessagePortIdentifier is used to create a new port, still connected
|
||||
// with the other one, but in the worker thread.
|
||||
ErrorResult rv;
|
||||
nsRefPtr<MessagePort> port = MessagePort::Create(nullptr, aIdentifier, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
|
||||
|
||||
GlobalObject globalObject(aCx, jsGlobal);
|
||||
if (globalObject.Failed()) {
|
||||
@ -6228,27 +6468,51 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx,
|
||||
init.mCancelable = false;
|
||||
init.mSource.SetValue().SetAsMessagePort() = port;
|
||||
|
||||
ErrorResult rv;
|
||||
|
||||
nsRefPtr<MessageEvent> event =
|
||||
MessageEvent::Constructor(globalObject,
|
||||
NS_LITERAL_STRING("connect"), init, rv);
|
||||
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsTArray<nsRefPtr<MessagePort>> ports;
|
||||
nsTArray<nsRefPtr<MessagePortBase>> ports;
|
||||
ports.AppendElement(port);
|
||||
|
||||
nsRefPtr<MessagePortList> portList =
|
||||
new MessagePortList(static_cast<nsIDOMEventTarget*>(globalScope), ports);
|
||||
event->SetPorts(portList);
|
||||
|
||||
mWorkerPorts.Put(aMessagePortSerial, port);
|
||||
|
||||
nsCOMPtr<nsIDOMEvent> domEvent = do_QueryObject(event);
|
||||
|
||||
nsEventStatus dummy = nsEventStatus_eIgnore;
|
||||
globalScope->DispatchDOMEvent(nullptr, domEvent, nullptr, &dummy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::DisconnectMessagePort(uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
mWorkerPorts.Remove(aMessagePortSerial);
|
||||
}
|
||||
|
||||
workers::MessagePort*
|
||||
WorkerPrivate::GetMessagePort(uint64_t aMessagePortSerial)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
nsRefPtr<MessagePort> port;
|
||||
if (mWorkerPorts.Get(aMessagePortSerial, getter_AddRefs(port))) {
|
||||
return port;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WorkerGlobalScope*
|
||||
WorkerPrivate::GetOrCreateGlobalScope(JSContext* aCx)
|
||||
{
|
||||
|
@ -50,8 +50,6 @@ struct RuntimeStats;
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Function;
|
||||
class MessagePort;
|
||||
class MessagePortIdentifier;
|
||||
class StructuredCloneHelper;
|
||||
} // namespace dom
|
||||
namespace ipc {
|
||||
@ -66,6 +64,7 @@ class ReportDebuggerErrorRunnable;
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class AutoSyncLoopHolder;
|
||||
class MessagePort;
|
||||
class SharedWorker;
|
||||
class ServiceWorkerClientInfo;
|
||||
class WorkerControlRunnable;
|
||||
@ -178,9 +177,10 @@ private:
|
||||
|
||||
// Only touched on the parent thread (currently this is always the main
|
||||
// thread as SharedWorkers are always top-level).
|
||||
nsTArray<SharedWorker*> mSharedWorkers;
|
||||
nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
|
||||
|
||||
uint64_t mBusyCount;
|
||||
uint64_t mMessagePortSerial;
|
||||
Status mParentStatus;
|
||||
bool mParentFrozen;
|
||||
bool mIsChromeWorker;
|
||||
@ -226,6 +226,7 @@ private:
|
||||
void
|
||||
PostMessageInternal(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort, uint64_t aMessagePortSerial,
|
||||
ServiceWorkerClientInfo* aClientInfo,
|
||||
ErrorResult& aRv);
|
||||
|
||||
@ -327,7 +328,7 @@ public:
|
||||
const Optional<Sequence<JS::Value> >& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
|
||||
PostMessageInternal(aCx, aMessage, aTransferable, false, 0, nullptr, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
@ -336,6 +337,19 @@ public:
|
||||
nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
PostMessageToMessagePort(JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value> >& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
DispatchMessageEventToMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
StructuredCloneHelper& aHelper);
|
||||
|
||||
void
|
||||
UpdateRuntimeOptions(JSContext* aCx,
|
||||
const JS::RuntimeOptions& aRuntimeOptions);
|
||||
@ -365,8 +379,7 @@ public:
|
||||
OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
|
||||
|
||||
bool
|
||||
RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker,
|
||||
MessagePort* aPort);
|
||||
RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
|
||||
|
||||
void
|
||||
UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
|
||||
@ -745,6 +758,13 @@ public:
|
||||
return mSharedWorkerName;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
NextMessagePortSerial()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
return mMessagePortSerial++;
|
||||
}
|
||||
|
||||
bool
|
||||
IsStorageAllowed() const
|
||||
{
|
||||
@ -932,6 +952,8 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
|
||||
nsRefPtr<MemoryReporter> mMemoryReporter;
|
||||
|
||||
nsRefPtrHashtable<nsUint64HashKey, MessagePort> mWorkerPorts;
|
||||
|
||||
// fired on the main thread if the worker script fails to load
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedRunnable;
|
||||
|
||||
@ -1054,12 +1076,13 @@ public:
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
|
||||
PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
PostMessageToParentMessagePort(
|
||||
JSContext* aCx,
|
||||
uint64_t aMessagePortSerial,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv);
|
||||
@ -1216,7 +1239,13 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
|
||||
ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
|
||||
|
||||
void
|
||||
DisconnectMessagePort(uint64_t aMessagePortSerial);
|
||||
|
||||
MessagePort*
|
||||
GetMessagePort(uint64_t aMessagePortSerial);
|
||||
|
||||
WorkerGlobalScope*
|
||||
GetOrCreateGlobalScope(JSContext* aCx);
|
||||
@ -1416,6 +1445,8 @@ private:
|
||||
PostMessageToParentInternal(JSContext* aCx,
|
||||
JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,7 @@ EXPORTS.mozilla.dom.workers.bindings += [
|
||||
'DataStoreCursor.h',
|
||||
'FileReaderSync.h',
|
||||
'Location.h',
|
||||
'MessagePort.h',
|
||||
'Navigator.h',
|
||||
'Performance.h',
|
||||
'ServiceWorker.h',
|
||||
@ -55,6 +56,7 @@ UNIFIED_SOURCES += [
|
||||
'DataStoreCursor.cpp',
|
||||
'FileReaderSync.cpp',
|
||||
'Location.cpp',
|
||||
'MessagePort.cpp',
|
||||
'Navigator.cpp',
|
||||
'Performance.cpp',
|
||||
'Principal.cpp',
|
||||
|
@ -110,7 +110,6 @@ support-files =
|
||||
sharedworker_performance_user_timing.js
|
||||
referrer.sjs
|
||||
performance_observer.html
|
||||
sharedWorker_ports.js
|
||||
|
||||
[test_404.html]
|
||||
[test_atob.html]
|
||||
@ -222,4 +221,3 @@ skip-if = buildapp == 'b2g' || e10s
|
||||
skip-if = (os == "win") || (os == "mac") || toolkit == 'android' || e10s #bug 798220
|
||||
[test_xhrAbort.html]
|
||||
[test_referrer.html]
|
||||
[test_sharedWorker_ports.html]
|
||||
|
@ -1,23 +0,0 @@
|
||||
var port;
|
||||
onconnect = function(evt) {
|
||||
evt.source.postMessage({ type: "connected" });
|
||||
|
||||
if (!port) {
|
||||
port = evt.source;
|
||||
evt.source.onmessage = function(evtFromPort) {
|
||||
port.postMessage({type: "status",
|
||||
test: "Port from the main-thread!" == evtFromPort.data,
|
||||
msg: "The message is coming from the main-thread"});
|
||||
port.postMessage({type: "status",
|
||||
test: (evtFromPort.ports.length == 1),
|
||||
msg: "1 port transferred"});
|
||||
|
||||
evtFromPort.ports[0].onmessage = function(evtFromPort2) {
|
||||
port.postMessage({type: "status",
|
||||
test: (evtFromPort2.data.type == "connected"),
|
||||
msg: "The original message received" });
|
||||
port.postMessage({type: "finish"});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for MessagePort and SharedWorkers</title>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [["dom.workers.sharedWorkers.enabled", true]]},
|
||||
function() {
|
||||
var sw1 = new SharedWorker('sharedWorker_ports.js');
|
||||
sw1.port.onmessage = function(event) {
|
||||
if (event.data.type == "connected") {
|
||||
ok(true, "The SharedWorker is alive.");
|
||||
|
||||
var sw2 = new SharedWorker('sharedWorker_ports.js');
|
||||
sw1.port.postMessage("Port from the main-thread!", [sw2.port]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "status") {
|
||||
ok(event.data.test, event.data.msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.data.type == "finish") {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user