Bug 1204775 - SharedWorker.port should be a 'real' MessagePort, r=khuey

This commit is contained in:
Andrea Marchesini 2015-09-16 00:47:19 +08:00
Родитель 995d2fc2f8
Коммит ff25288854
25 изменённых файлов: 249 добавлений и 963 удалений

Просмотреть файл

@ -114,8 +114,7 @@ PostMessageEvent::Run()
false /*cancelable */, messageData, mCallerOrigin,
EmptyString(), mSource);
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
ports));

Просмотреть файл

@ -20,9 +20,6 @@ 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,16 +1072,14 @@ StructuredCloneHelper::WriteTransferCallback(JSContext* aCx,
}
{
MessagePortBase* port = nullptr;
MessagePort* 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();
if (!port->CloneAndDisentangle(*identifier)) {
return false;
}
port->CloneAndDisentangle(*identifier);
*aTag = SCTAG_DOM_MAP_MESSAGEPORT;
*aOwnership = JS::SCTAG_TMO_CUSTOM;

Просмотреть файл

@ -7,6 +7,7 @@
#define mozilla_dom_StructuredCloneHelper_h
#include "js/StructuredClone.h"
#include "mozilla/Move.h"
#include "nsAutoPtr.h"
#include "nsISupports.h"
#include "nsTArray.h"
@ -111,7 +112,7 @@ protected:
};
class BlobImpl;
class MessagePortBase;
class MessagePort;
class MessagePortIdentifier;
class StructuredCloneHelper : public StructuredCloneHelperInternal
@ -191,11 +192,10 @@ 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.
void TakeTransferredPorts(nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
nsTArray<nsRefPtr<MessagePort>>&& TakeTransferredPorts()
{
MOZ_ASSERT(mSupportsTransferring);
MOZ_ASSERT(aPorts.IsEmpty());
aPorts.SwapElements(mTransferredPorts);
return Move(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<MessagePortBase>> mTransferredPorts;
nsTArray<nsRefPtr<MessagePort>> 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,11 +739,6 @@ 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<MessagePortBase>> ports;
nsTArray<nsRefPtr<MessagePort>> ports;
for (uint32_t i = 0, len = aParam.mPorts.Value().Value().Length(); i < len; ++i) {
ports.AppendElement(aParam.mPorts.Value().Value()[i].get());
}

Просмотреть файл

@ -17,7 +17,6 @@ namespace dom {
struct MessageEventInit;
class MessagePort;
class MessagePortBase;
class MessagePortList;
class OwningWindowProxyOrMessagePortOrClient;
@ -94,7 +93,7 @@ private:
nsString mOrigin;
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mWindowSource;
nsRefPtr<MessagePortBase> mPortSource;
nsRefPtr<MessagePort> mPortSource;
nsRefPtr<workers::ServiceWorkerClient> mClientSource;
nsRefPtr<MessagePortList> mPorts;
};

Просмотреть файл

@ -49,7 +49,12 @@ 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()) {
@ -62,14 +67,14 @@ MessageChannel::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
return nullptr;
}
nsRefPtr<MessageChannel> channel = new MessageChannel(window);
nsRefPtr<MessageChannel> channel = new MessageChannel(aWindow);
channel->mPort1 = MessagePort::Create(window, portUUID1, portUUID2, aRv);
channel->mPort1 = MessagePort::Create(aWindow, portUUID1, portUUID2, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
channel->mPort2 = MessagePort::Create(window, portUUID2, portUUID1, aRv);
channel->mPort2 = MessagePort::Create(aWindow, portUUID2, portUUID1, aRv);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}

Просмотреть файл

@ -40,6 +40,9 @@ public:
static already_AddRefed<MessageChannel>
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
static already_AddRefed<MessageChannel>
Constructor(nsPIDOMWindow* aWindow, ErrorResult& aRv);
MessagePort*
Port1() const
{

Просмотреть файл

@ -140,8 +140,7 @@ public:
event->SetTrusted(true);
event->SetSource(mPort);
nsTArray<nsRefPtr<MessagePortBase>> ports;
mData->TakeTransferredPorts(ports);
nsTArray<nsRefPtr<MessagePort>> ports = mData->TakeTransferredPorts();
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),
@ -171,19 +170,10 @@ 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,
MessagePortBase)
DOMEventTargetHelper)
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDispatchRunnable->mPort);
}
@ -194,7 +184,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MessagePort,
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MessagePort,
MessagePortBase)
DOMEventTargetHelper)
if (tmp->mDispatchRunnable) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDispatchRunnable->mPort);
}
@ -205,10 +195,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(MessagePortBase)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(MessagePort, MessagePortBase)
NS_IMPL_RELEASE_INHERITED(MessagePort, MessagePortBase)
NS_IMPL_ADDREF_INHERITED(MessagePort, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MessagePort, DOMEventTargetHelper)
namespace {
@ -287,7 +277,7 @@ NS_IMPL_ISUPPORTS(ForceCloseHelper, nsIIPCBackgroundChildCreateCallback)
} // namespace
MessagePort::MessagePort(nsPIDOMWindow* aWindow)
: MessagePortBase(aWindow)
: DOMEventTargetHelper(aWindow)
, mInnerID(0)
, mMessageQueueEnabled(false)
, mIsKeptAlive(false)
@ -364,16 +354,7 @@ MessagePort::Initialize(const nsID& aUUID,
// The port has to keep itself alive until it's entangled.
UpdateMustKeepAlive();
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 {
if (!NS_IsMainThread()) {
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
MOZ_ASSERT(!mWorkerFeature);
@ -386,6 +367,15 @@ 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);
}
}
}
@ -414,7 +404,7 @@ MessagePort::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
continue;
}
MessagePortBase* port = nullptr;
MessagePort* port = nullptr;
nsresult rv = UNWRAP_OBJECT(MessagePort, &value.toObject(), port);
if (NS_FAILED(rv)) {
continue;
@ -520,11 +510,6 @@ MessagePort::Dispatch()
void
MessagePort::Close()
{
// Not entangled yet, but already closed.
if (mNextStep != eNextStepNone) {
return;
}
if (mState == eStateUnshippedEntangled) {
MOZ_ASSERT(mUnshippedEntangledPort);
@ -540,7 +525,7 @@ MessagePort::Close()
}
// Not entangled yet, we have to wait.
if (mState < eStateEntangling) {
if (mState == eStateEntangling) {
mNextStep = eNextStepClose;
return;
}
@ -699,7 +684,7 @@ MessagePort::Disentangle()
UpdateMustKeepAlive();
}
bool
void
MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
{
MOZ_ASSERT(mIdentifier);
@ -710,13 +695,13 @@ MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
aIdentifier.neutered() = true;
if (mState > eStateEntangled) {
return true;
return;
}
// We already have a 'next step'. We have to consider this port as already
// cloned/closed/disentangled.
if (mNextStep != eNextStepNone) {
return true;
return;
}
aIdentifier.uuid() = mIdentifier->uuid();
@ -739,24 +724,23 @@ MessagePort::CloneAndDisentangle(MessagePortIdentifier& aIdentifier)
mState = eStateDisentangled;
UpdateMustKeepAlive();
return true;
return;
}
// Register this component to PBackground.
ConnectToPBackground();
mNextStep = eNextStepDisentangle;
return true;
return;
}
// Not entangled yet, we have to wait.
if (mState < eStateEntangled) {
mNextStep = eNextStepDisentangle;
return true;
return;
}
StartDisentangling();
return true;
}
void

Просмотреть файл

@ -31,41 +31,7 @@ namespace workers {
class WorkerFeature;
} // namespace workers
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
class MessagePort final : public DOMEventTargetHelper
, public nsIIPCBackgroundChildCreateCallback
, public nsIObserver
{
@ -76,7 +42,7 @@ public:
NS_DECL_NSIOBSERVER
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MessagePort,
MessagePortBase)
DOMEventTargetHelper)
static already_AddRefed<MessagePort>
Create(nsPIDOMWindow* aWindow, const nsID& aUUID,
@ -92,24 +58,24 @@ public:
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
virtual void
void
PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv) override;
ErrorResult& aRv);
virtual void Start() override;
void Start();
virtual void Close() override;
void Close();
virtual EventHandlerNonNull* GetOnmessage() override;
EventHandlerNonNull* GetOnmessage();
virtual void SetOnmessage(EventHandlerNonNull* aCallback) override;
void SetOnmessage(EventHandlerNonNull* aCallback);
// Non WebIDL methods
void UnshippedEntangle(MessagePort* aEntangledPort);
virtual bool CloneAndDisentangle(MessagePortIdentifier& aIdentifier) override;
void CloneAndDisentangle(MessagePortIdentifier& aIdentifier);
// These methods are useful for MessagePortChild

Просмотреть файл

@ -29,7 +29,7 @@ public:
public:
MessagePortList(nsISupports* aOwner,
const nsTArray<nsRefPtr<MessagePortBase>>& aPorts)
const nsTArray<nsRefPtr<MessagePort>>& aPorts)
: mOwner(aOwner)
, mPorts(aPorts)
{
@ -50,13 +50,13 @@ public:
return mPorts.Length();
}
MessagePortBase*
MessagePort*
Item(uint32_t aIndex)
{
return mPorts.SafeElementAt(aIndex);
}
MessagePortBase*
MessagePort*
IndexedGetter(uint32_t aIndex, bool &aFound)
{
aFound = aIndex < mPorts.Length();
@ -68,7 +68,7 @@ public:
public:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<MessagePortBase>> mPorts;
nsTArray<nsRefPtr<MessagePort>> mPorts;
};
} // namespace dom

Просмотреть файл

@ -1,318 +0,0 @@
/* -*- 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;
}

Просмотреть файл

@ -1,112 +0,0 @@
/* -*- 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,6 +34,7 @@
#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"
@ -2493,8 +2494,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);
@ -2508,9 +2509,18 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
}
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
// 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();
}
if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker)) {
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate,
channel->Port1());
if (!workerPrivate->RegisterSharedWorker(aCx, sharedWorker,
channel->Port2())) {
NS_WARNING("Worker is unreachable, this shouldn't happen!");
sharedWorker->Close();
return NS_ERROR_FAILURE;

Просмотреть файл

@ -138,8 +138,7 @@ private:
return NS_ERROR_FAILURE;
}
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
nsRefPtr<MessagePortList> portList =
new MessagePortList(static_cast<dom::Event*>(event.get()),

Просмотреть файл

@ -11,6 +11,7 @@
#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,16 +26,14 @@ using namespace mozilla;
USING_WORKERS_NAMESPACE
SharedWorker::SharedWorker(nsPIDOMWindow* aWindow,
WorkerPrivate* aWorkerPrivate)
: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate),
mFrozen(false)
WorkerPrivate* aWorkerPrivate,
MessagePort* aMessagePort)
: DOMEventTargetHelper(aWindow), mWorkerPrivate(aWorkerPrivate)
, mMessagePort(aMessagePort)
, mFrozen(false)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
mSerial = aWorkerPrivate->NextMessagePortSerial();
mMessagePort = new MessagePort(aWindow, this, mSerial);
}
SharedWorker::~SharedWorker()
@ -76,13 +74,11 @@ SharedWorker::Constructor(const GlobalObject& aGlobal, JSContext* aCx,
return sharedWorker.forget();
}
already_AddRefed<mozilla::dom::workers::MessagePort>
MessagePort*
SharedWorker::Port()
{
AssertIsOnMainThread();
nsRefPtr<MessagePort> messagePort = mMessagePort;
return messagePort.forget();
return mMessagePort;
}
void
@ -157,8 +153,7 @@ SharedWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
MOZ_ASSERT(mWorkerPrivate);
MOZ_ASSERT(mMessagePort);
mWorkerPrivate->PostMessageToMessagePort(aCx, mMessagePort->Serial(),
aMessage, aTransferable, aRv);
mMessagePort->PostMessage(aCx, aMessage, aTransferable, aRv);
}
void

Просмотреть файл

@ -10,7 +10,6 @@
#include "Workers.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/workers/bindings/MessagePort.h"
#include "mozilla/DOMEventTargetHelper.h"
class nsIDOMEvent;
@ -18,17 +17,19 @@ 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;
@ -37,7 +38,6 @@ class SharedWorker final : public DOMEventTargetHelper
nsRefPtr<WorkerPrivate> mWorkerPrivate;
nsRefPtr<MessagePort> mMessagePort;
nsTArray<nsCOMPtr<nsIDOMEvent>> mFrozenEvents;
uint64_t mSerial;
bool mFrozen;
public:
@ -46,15 +46,9 @@ public:
const nsAString& aScriptURL, const Optional<nsAString>& aName,
ErrorResult& aRv);
already_AddRefed<mozilla::dom::workers::MessagePort>
MessagePort*
Port();
uint64_t
Serial() const
{
return mSerial;
}
bool
IsFrozen() const
{
@ -93,7 +87,8 @@ public:
private:
// This class can only be created from the RuntimeService.
SharedWorker(nsPIDOMWindow* aWindow,
WorkerPrivate* aWorkerPrivate);
WorkerPrivate* aWorkerPrivate,
MessagePort* aMessagePort);
// This class is reference-counted and will be destroyed from Release().
~SharedWorker();

Просмотреть файл

@ -54,6 +54,7 @@
#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"
@ -88,7 +89,6 @@
#include "nsThreadManager.h"
#endif
#include "MessagePort.h"
#include "Navigator.h"
#include "Principal.h"
#include "RuntimeService.h"
@ -594,21 +594,15 @@ 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,
bool aToMessagePort, uint64_t aMessagePortSerial)
TargetAndBusyBehavior aBehavior)
: WorkerRunnable(aWorkerPrivate, aBehavior)
, StructuredCloneHelper(CloningSupported, TransferringSupported,
SameProcessDifferentThread)
, mMessagePortSerial(aMessagePortSerial)
, mToMessagePort(aToMessagePort)
{
}
@ -654,8 +648,7 @@ public:
return false;
}
nsTArray<nsRefPtr<MessagePortBase>> ports;
TakeTransferredPorts(ports);
nsTArray<nsRefPtr<MessagePort>> ports = TakeTransferredPorts();
event->SetTrusted(true);
event->SetPorts(new MessagePortList(static_cast<dom::Event*>(event.get()),
@ -671,8 +664,6 @@ 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.
@ -680,13 +671,6 @@ private:
return true;
}
if (mToMessagePort) {
return
aWorkerPrivate->DispatchMessageEventToMessagePort(aCx,
mMessagePortSerial,
*this);
}
if (aWorkerPrivate->IsFrozen()) {
aWorkerPrivate->QueueRunnable(this);
return true;
@ -700,16 +684,6 @@ 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);
}
@ -1521,18 +1495,19 @@ public:
class MessagePortRunnable final : public WorkerRunnable
{
uint64_t mMessagePortSerial;
bool mConnect;
MessagePortIdentifier mPortIdentifier;
public:
MessagePortRunnable(WorkerPrivate* aWorkerPrivate,
uint64_t aMessagePortSerial,
bool aConnect)
: WorkerRunnable(aWorkerPrivate, aConnect ?
WorkerThreadModifyBusyCount :
WorkerThreadUnchangedBusyCount),
mMessagePortSerial(aMessagePortSerial), mConnect(aConnect)
{ }
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);
}
private:
~MessagePortRunnable()
@ -1541,12 +1516,7 @@ private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
{
if (mConnect) {
return aWorkerPrivate->ConnectMessagePort(aCx, mMessagePortSerial);
}
aWorkerPrivate->DisconnectMessagePort(mMessagePortSerial);
return true;
return aWorkerPrivate->ConnectMessagePort(aCx, mPortIdentifier);
}
};
@ -2122,8 +2092,7 @@ WorkerPrivateParent<Derived>::WorkerPrivateParent(
mMemoryReportCondVar(mMutex, "WorkerPrivateParent Memory Report CondVar"),
mParent(aParent), mScriptURL(aScriptURL),
mSharedWorkerName(aSharedWorkerName), mLoadingWorkerScript(false),
mBusyCount(0), mMessagePortSerial(0),
mParentStatus(Pending), mParentFrozen(false),
mBusyCount(0), mParentStatus(Pending), mParentFrozen(false),
mIsChromeWorker(aIsChromeWorker), mMainThreadObjectsForgotten(false),
mWorkerType(aWorkerType),
mCreationTimeStamp(TimeStamp::Now()),
@ -2487,55 +2456,29 @@ 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.Count()) {
if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
AssertIsOnMainThread();
struct Closure
{
nsPIDOMWindow* mWindow;
bool mAllFrozen;
bool allFrozen = false;
explicit Closure(nsPIDOMWindow* aWindow)
: mWindow(aWindow), mAllFrozen(true)
{
AssertIsOnMainThread();
// aWindow may be null here.
}
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];
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;
}
mSharedWorkers[i]->Freeze();
} else {
MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
aWindow));
if (!mSharedWorkers[i]->IsFrozen()) {
allFrozen = false;
}
return PL_DHASH_NEXT;
}
};
}
Closure closure(aWindow);
mSharedWorkers.EnumerateRead(Closure::Freeze, &closure);
if (!closure.mAllFrozen || mParentFrozen) {
if (!allFrozen || mParentFrozen) {
return true;
}
}
@ -2576,56 +2519,30 @@ 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.Count()) {
if ((IsSharedWorker() || IsServiceWorker()) && !mSharedWorkers.IsEmpty()) {
AssertIsOnMainThread();
struct Closure
{
nsPIDOMWindow* mWindow;
bool mAnyRunning;
bool anyRunning = false;
explicit Closure(nsPIDOMWindow* aWindow)
: mWindow(aWindow), mAnyRunning(false)
{
AssertIsOnMainThread();
// aWindow may be null here.
}
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];
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;
}
mSharedWorkers[i]->Thaw();
anyRunning = true;
} else {
MOZ_ASSERT_IF(mSharedWorkers[i]->GetOwner() && aWindow,
!SameCOMIdentity(mSharedWorkers[i]->GetOwner(),
aWindow));
if (!mSharedWorkers[i]->IsFrozen()) {
anyRunning = true;
}
return PL_DHASH_NEXT;
}
};
}
Closure closure(aWindow);
mSharedWorkers.EnumerateRead(Closure::Thaw, &closure);
if (!closure.mAnyRunning || !mParentFrozen) {
if (!anyRunning || !mParentFrozen) {
return true;
}
}
@ -2762,8 +2679,6 @@ 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)
{
@ -2797,8 +2712,7 @@ WorkerPrivateParent<Derived>::PostMessageInternal(
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(ParentAsWorkerPrivate(),
WorkerRunnable::WorkerThreadModifyBusyCount,
aToMessagePort, aMessagePortSerial);
WorkerRunnable::WorkerThreadModifyBusyCount);
runnable->Write(aCx, aMessage, transferable, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@ -2821,88 +2735,7 @@ WorkerPrivateParent<Derived>::PostMessageToServiceWorker(
ErrorResult& aRv)
{
AssertIsOnMainThread();
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;
PostMessageInternal(aCx, aMessage, aTransferable, aClientInfo.forget(), aRv);
}
template <class Derived>
@ -3090,27 +2923,27 @@ WorkerPrivate::OfflineStatusChangeEventInternal(JSContext* aCx, bool aIsOffline)
template <class Derived>
bool
WorkerPrivateParent<Derived>::RegisterSharedWorker(JSContext* aCx,
SharedWorker* aSharedWorker)
SharedWorker* aSharedWorker,
MessagePort* aPort)
{
AssertIsOnMainThread();
MOZ_ASSERT(aSharedWorker);
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
MOZ_ASSERT(!mSharedWorkers.Get(aSharedWorker->Serial()));
MOZ_ASSERT(!mSharedWorkers.Contains(aSharedWorker));
if (IsSharedWorker()) {
nsRefPtr<MessagePortRunnable> runnable =
new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
true);
new MessagePortRunnable(ParentAsWorkerPrivate(), aPort);
if (!runnable->Dispatch(aCx)) {
return false;
}
}
mSharedWorkers.Put(aSharedWorker->Serial(), aSharedWorker);
mSharedWorkers.AppendElement(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.Count() > 1 && !Thaw(aCx, nullptr)) {
if (mSharedWorkers.Length() > 1 && !Thaw(aCx, nullptr)) {
return false;
}
@ -3126,21 +2959,14 @@ WorkerPrivateParent<Derived>::UnregisterSharedWorker(
AssertIsOnMainThread();
MOZ_ASSERT(aSharedWorker);
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
MOZ_ASSERT(mSharedWorkers.Get(aSharedWorker->Serial()));
MOZ_ASSERT(mSharedWorkers.Contains(aSharedWorker));
nsRefPtr<MessagePortRunnable> runnable =
new MessagePortRunnable(ParentAsWorkerPrivate(), aSharedWorker->Serial(),
false);
if (!runnable->Dispatch(aCx)) {
JS_ReportPendingException(aCx);
}
mSharedWorkers.Remove(aSharedWorker->Serial());
mSharedWorkers.RemoveElement(aSharedWorker);
// 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.Count()) {
if (!mSharedWorkers.IsEmpty()) {
if (!Freeze(aCx, nullptr)) {
JS_ReportPendingException(aCx);
}
@ -3278,29 +3104,13 @@ 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();
}
mSharedWorkers.EnumerateRead(Helper::Collect, &aSharedWorkers);
for (uint32_t i = 0; i < mSharedWorkers.Length(); ++i) {
aSharedWorkers.AppendElement(mSharedWorkers[i]);
}
}
template <class Derived>
@ -3312,47 +3122,19 @@ WorkerPrivateParent<Derived>::CloseSharedWorkersForWindow(
MOZ_ASSERT(IsSharedWorker() || IsServiceWorker());
MOZ_ASSERT(aWindow);
struct Closure
{
nsPIDOMWindow* mWindow;
nsAutoTArray<nsRefPtr<SharedWorker>, 10> mSharedWorkers;
nsAutoTArray<nsRefPtr<SharedWorker>, 10> sharedWorkers;
explicit Closure(nsPIDOMWindow* aWindow)
: mWindow(aWindow)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWindow);
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));
}
}
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();
for (uint32_t index = 0; index < sharedWorkers.Length(); index++) {
sharedWorkers[index]->Close();
}
}
@ -4588,9 +4370,6 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
}
}
// Clear away our MessagePorts.
mWorkerPorts.Clear();
// Unroot the globals
mScope = nullptr;
mDebuggerScope = nullptr;
@ -5528,8 +5307,6 @@ WorkerPrivate::PostMessageToParentInternal(
JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
bool aToMessagePort,
uint64_t aMessagePortSerial,
ErrorResult& aRv)
{
AssertIsOnWorkerThread();
@ -5554,8 +5331,7 @@ WorkerPrivate::PostMessageToParentInternal(
nsRefPtr<MessageEventRunnable> runnable =
new MessageEventRunnable(this,
WorkerRunnable::ParentThreadUnchangedBusyCount,
aToMessagePort, aMessagePortSerial);
WorkerRunnable::ParentThreadUnchangedBusyCount);
runnable->Write(aCx, aMessage, transferable, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@ -5567,26 +5343,6 @@ 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()
{
@ -6444,19 +6200,23 @@ WorkerPrivate::EndCTypesCall()
}
bool
WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
WorkerPrivate::ConnectMessagePort(JSContext* aCx,
MessagePortIdentifier& aIdentifier)
{
AssertIsOnWorkerThread();
NS_ASSERTION(!mWorkerPorts.GetWeak(aMessagePortSerial),
"Already have this port registered!");
WorkerGlobalScope* globalScope = GlobalScope();
JS::Rooted<JSObject*> jsGlobal(aCx, globalScope->GetWrapper());
MOZ_ASSERT(jsGlobal);
nsRefPtr<MessagePort> port = new MessagePort(this, aMessagePortSerial);
// 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;
}
GlobalObject globalObject(aCx, jsGlobal);
if (globalObject.Failed()) {
@ -6468,51 +6228,27 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial)
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<MessagePortBase>> ports;
nsTArray<nsRefPtr<MessagePort>> 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,6 +50,8 @@ struct RuntimeStats;
namespace mozilla {
namespace dom {
class Function;
class MessagePort;
class MessagePortIdentifier;
class StructuredCloneHelper;
} // namespace dom
namespace ipc {
@ -64,7 +66,6 @@ class ReportDebuggerErrorRunnable;
BEGIN_WORKERS_NAMESPACE
class AutoSyncLoopHolder;
class MessagePort;
class SharedWorker;
class ServiceWorkerClientInfo;
class WorkerControlRunnable;
@ -177,10 +178,9 @@ private:
// Only touched on the parent thread (currently this is always the main
// thread as SharedWorkers are always top-level).
nsDataHashtable<nsUint64HashKey, SharedWorker*> mSharedWorkers;
nsTArray<SharedWorker*> mSharedWorkers;
uint64_t mBusyCount;
uint64_t mMessagePortSerial;
Status mParentStatus;
bool mParentFrozen;
bool mIsChromeWorker;
@ -226,7 +226,6 @@ 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);
@ -328,7 +327,7 @@ public:
const Optional<Sequence<JS::Value> >& aTransferable,
ErrorResult& aRv)
{
PostMessageInternal(aCx, aMessage, aTransferable, false, 0, nullptr, aRv);
PostMessageInternal(aCx, aMessage, aTransferable, nullptr, aRv);
}
void
@ -337,19 +336,6 @@ 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);
@ -379,7 +365,8 @@ public:
OfflineStatusChangeEvent(JSContext* aCx, bool aIsOffline);
bool
RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
RegisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker,
MessagePort* aPort);
void
UnregisterSharedWorker(JSContext* aCx, SharedWorker* aSharedWorker);
@ -758,13 +745,6 @@ public:
return mSharedWorkerName;
}
uint64_t
NextMessagePortSerial()
{
AssertIsOnMainThread();
return mMessagePortSerial++;
}
bool
IsStorageAllowed() const
{
@ -952,8 +932,6 @@ 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;
@ -1076,13 +1054,12 @@ public:
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv)
{
PostMessageToParentInternal(aCx, aMessage, aTransferable, false, 0, aRv);
PostMessageToParentInternal(aCx, aMessage, aTransferable, aRv);
}
void
PostMessageToParentMessagePort(
JSContext* aCx,
uint64_t aMessagePortSerial,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
ErrorResult& aRv);
@ -1239,13 +1216,7 @@ public:
}
bool
ConnectMessagePort(JSContext* aCx, uint64_t aMessagePortSerial);
void
DisconnectMessagePort(uint64_t aMessagePortSerial);
MessagePort*
GetMessagePort(uint64_t aMessagePortSerial);
ConnectMessagePort(JSContext* aCx, MessagePortIdentifier& aIdentifier);
WorkerGlobalScope*
GetOrCreateGlobalScope(JSContext* aCx);
@ -1445,8 +1416,6 @@ private:
PostMessageToParentInternal(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Optional<Sequence<JS::Value>>& aTransferable,
bool aToMessagePort,
uint64_t aMessagePortSerial,
ErrorResult& aRv);
void

Просмотреть файл

@ -29,7 +29,6 @@ EXPORTS.mozilla.dom.workers.bindings += [
'DataStoreCursor.h',
'FileReaderSync.h',
'Location.h',
'MessagePort.h',
'Navigator.h',
'Performance.h',
'ServiceWorker.h',
@ -56,7 +55,6 @@ UNIFIED_SOURCES += [
'DataStoreCursor.cpp',
'FileReaderSync.cpp',
'Location.cpp',
'MessagePort.cpp',
'Navigator.cpp',
'Performance.cpp',
'Principal.cpp',

Просмотреть файл

@ -110,6 +110,7 @@ support-files =
sharedworker_performance_user_timing.js
referrer.sjs
performance_observer.html
sharedWorker_ports.js
[test_404.html]
[test_atob.html]
@ -221,3 +222,4 @@ 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]

Просмотреть файл

@ -0,0 +1,23 @@
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"});
}
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
<!--
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>