--- a/netwerk/ipc/ChannelEventQueue.cpp
+++ b/netwerk/ipc/ChannelEventQueue.cpp
@@ -1,20 +1,21 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set sw=2 ts=8 et 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 "nsISupports.h"
-#include "mozilla/net/ChannelEventQueue.h"
+#include "ChannelEventQueue.h"
+
+#include "mozilla/Assertions.h"
#include "mozilla/Unused.h"
+#include "nsISupports.h"
#include "nsThreadUtils.h"
-#include "mozilla/Unused.h"
namespace mozilla {
namespace net {
ChannelEvent*
ChannelEventQueue::TakeEvent()
{
MutexAutoLock lock(mMutex);
@@ -34,80 +35,125 @@ void
ChannelEventQueue::FlushQueue()
{
// Events flushed could include destruction of channel (and our own
// destructor) unless we make sure its refcount doesn't drop to 0 while this
// method is running.
nsCOMPtr<nsISupports> kungFuDeathGrip(mOwner);
mozilla::Unused << kungFuDeathGrip; // Not used in this function
- // Prevent flushed events from flushing the queue recursively
+ bool needResumeOnOtherThread = false;
{
- MutexAutoLock lock(mMutex);
- mFlushing = true;
+ // Don't allow event enqueued during flush to make sure all events
+ // are run.
+ ReentrantMonitorAutoEnter monitor(mRunningMonitor);
+
+ // Prevent flushed events from flushing the queue recursively
+ {
+ MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(!mFlushing);
+ mFlushing = true;
+ }
+
+ while (true) {
+ UniquePtr<ChannelEvent> event(TakeEvent());
+ if (!event) {
+ break;
+ }
+
+ nsCOMPtr<nsIEventTarget> target = event->GetEventTarget();
+ MOZ_ASSERT(target);
+
+ bool isCurrentThread = false;
+ nsresult rv = target->IsOnCurrentThread(&isCurrentThread);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ // Simply run this event on current thread if we are not sure about it
+ // in release channel, or assert in Aurora/Nightly channel.
+ MOZ_DIAGNOSTIC_ASSERT(false);
+ isCurrentThread = true;
+ }
+
+ if (!isCurrentThread) {
+ // Next event needs to run on another thread. Put it back to
+ // the front of the queue can try resume on that thread.
+ Suspend();
+ PrependEvent(event);
+
+ needResumeOnOtherThread = true;
+ break;
+ }
+
+ event->Run();
+ }
+
+ {
+ MutexAutoLock lock(mMutex);
+ MOZ_ASSERT(mFlushing);
+ mFlushing = false;
+ MOZ_ASSERT(mEventQueue.IsEmpty() || (needResumeOnOtherThread || mSuspended || !!mForcedCount));
+ }
}
- while (true) {
- UniquePtr<ChannelEvent> event(TakeEvent());
- if (!event) {
- break;
- }
-
- event->Run();
+ // The flush procedure is aborted because next event cannot be run on current
+ // thread. We need to resume the event processing right after flush procedure
+ // is finished.
+ // Note: we cannot call Resume() while "mFlushing == true" because
+ // CompleteResume will not trigger FlushQueue while there is an ongoing flush.
+ if (needResumeOnOtherThread) {
+ Resume();
}
-
- MutexAutoLock lock(mMutex);
- mFlushing = false;
}
void
-ChannelEventQueue::Resume()
+ChannelEventQueue::Suspend()
{
MutexAutoLock lock(mMutex);
+ SuspendInternal();
+}
+
+void
+ChannelEventQueue::SuspendInternal()
+{
+ mMutex.AssertCurrentThreadOwns();
+
+ mSuspended = true;
+ mSuspendCount++;
+}
+
+void ChannelEventQueue::Resume()
+{
+ MutexAutoLock lock(mMutex);
+ ResumeInternal();
+}
+
+void
+ChannelEventQueue::ResumeInternal()
+{
+ mMutex.AssertCurrentThreadOwns();
// Resuming w/o suspend: error in debug mode, ignore in build
MOZ_ASSERT(mSuspendCount > 0);
if (mSuspendCount <= 0) {
return;
}
if (!--mSuspendCount) {
- RefPtr<Runnable> event =
- NewRunnableMethod(this, &ChannelEventQueue::CompleteResume);
- if (mTargetThread) {
- mTargetThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL);
- } else {
- MOZ_RELEASE_ASSERT(NS_IsMainThread());
- Unused << NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event.forget())));
+ if (mEventQueue.IsEmpty()) {
+ // Nothing in queue to flush, simply clear the flag.
+ mSuspended = false;
+ return;
}
- }
-}
-
-nsresult
-ChannelEventQueue::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
-{
- MOZ_RELEASE_ASSERT(NS_IsMainThread());
- MOZ_RELEASE_ASSERT(!mTargetThread);
- MOZ_RELEASE_ASSERT(aTargetThread);
- mTargetThread = do_QueryInterface(aTargetThread);
- MOZ_RELEASE_ASSERT(mTargetThread);
-
- return NS_OK;
-}
+ // Worker thread requires a CancelableRunnable.
+ RefPtr<Runnable> event =
+ NewCancelableRunnableMethod(this, &ChannelEventQueue::CompleteResume);
-nsresult
-ChannelEventQueue::ResetDeliveryTarget()
-{
- MutexAutoLock lock(mMutex);
+ nsCOMPtr<nsIEventTarget> target;
+ target = mEventQueue[0]->GetEventTarget();
+ MOZ_ASSERT(target);
- MOZ_RELEASE_ASSERT(mEventQueue.IsEmpty());
- MOZ_RELEASE_ASSERT(mSuspendCount == 0);
- MOZ_RELEASE_ASSERT(!mSuspended);
- MOZ_RELEASE_ASSERT(!mForced);
- MOZ_RELEASE_ASSERT(!mFlushing);
- mTargetThread = nullptr;
-
- return NS_OK;
+ Unused << NS_WARN_IF(NS_FAILED(target->Dispatch(event.forget(),
+ NS_DISPATCH_NORMAL)));
+ }
}
} // namespace net
} // namespace mozilla
--- a/netwerk/ipc/ChannelEventQueue.h
+++ b/netwerk/ipc/ChannelEventQueue.h
@@ -5,31 +5,49 @@
* 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_net_ChannelEventQueue_h
#define mozilla_net_ChannelEventQueue_h
#include "nsTArray.h"
#include "nsAutoPtr.h"
+#include "nsIEventTarget.h"
+#include "nsThreadUtils.h"
+#include "mozilla/DebugOnly.h"
#include "mozilla/Mutex.h"
+#include "mozilla/ReentrantMonitor.h"
#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
class nsISupports;
-class nsIEventTarget;
namespace mozilla {
namespace net {
class ChannelEvent
{
public:
ChannelEvent() { MOZ_COUNT_CTOR(ChannelEvent); }
virtual ~ChannelEvent() { MOZ_COUNT_DTOR(ChannelEvent); }
virtual void Run() = 0;
+ virtual already_AddRefed<nsIEventTarget> GetEventTarget() = 0;
+};
+
+class MainThreadChannelEvent : public ChannelEvent
+{
+ public:
+ MainThreadChannelEvent() { MOZ_COUNT_CTOR(MainThreadChannelEvent); }
+ virtual ~MainThreadChannelEvent() { MOZ_COUNT_DTOR(MainThreadChannelEvent); }
+
+ already_AddRefed<nsIEventTarget>
+ GetEventTarget() override
+ {
+ return do_GetMainThread();
+ }
};
// Workaround for Necko re-entrancy dangers. We buffer IPDL messages in a
// queue if still dispatching previous one(s) to listeners/observers.
// Otherwise synchronous XMLHttpRequests and/or other code that spins the
// event loop (ex: IPDL rpc) could cause listener->OnDataAvailable (for
// instance) to be dispatched and called before mListener->OnStartRequest has
// completed.
@@ -37,186 +55,238 @@ class ChannelEvent
class ChannelEventQueue final
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChannelEventQueue)
public:
explicit ChannelEventQueue(nsISupports *owner)
: mSuspendCount(0)
, mSuspended(false)
- , mForced(false)
+ , mForcedCount(0)
, mFlushing(false)
, mOwner(owner)
, mMutex("ChannelEventQueue::mMutex")
+ , mRunningMonitor("ChannelEventQueue::mRunningMonitor")
{}
// Puts IPDL-generated channel event into queue, to be run later
// automatically when EndForcedQueueing and/or Resume is called.
//
// @param aCallback - the ChannelEvent
// @param aAssertionWhenNotQueued - this optional param will be used in an
// assertion when the event is executed directly.
inline void RunOrEnqueue(ChannelEvent* aCallback,
bool aAssertionWhenNotQueued = false);
+
+ // Append ChannelEvent in front of the event queue.
+ inline nsresult PrependEvent(UniquePtr<ChannelEvent>& aEvent);
inline nsresult PrependEvents(nsTArray<UniquePtr<ChannelEvent>>& aEvents);
// After StartForcedQueueing is called, RunOrEnqueue() will start enqueuing
// events that will be run/flushed when EndForcedQueueing is called.
// - Note: queueing may still be required after EndForcedQueueing() (if the
// queue is suspended, etc): always call RunOrEnqueue() to avoid race
// conditions.
inline void StartForcedQueueing();
inline void EndForcedQueueing();
// Suspend/resume event queue. RunOrEnqueue() will start enqueuing
// events and they will be run/flushed when resume is called. These should be
// called when the channel owning the event queue is suspended/resumed.
- inline void Suspend();
+ void Suspend();
// Resume flushes the queue asynchronously, i.e. items in queue will be
// dispatched in a new event on the current thread.
void Resume();
- // Retargets delivery of events to the target thread specified.
- nsresult RetargetDeliveryTo(nsIEventTarget* aTargetThread);
-
- // Nulls out the delivery target so events are delivered to the main
- // thread. Should only be called when the queue is known to be empty.
- // Useful if the queue will be re-used.
- nsresult ResetDeliveryTarget();
-
private:
// Private destructor, to discourage deletion outside of Release():
~ChannelEventQueue()
{
}
+ void SuspendInternal();
+ void ResumeInternal();
+
inline void MaybeFlushQueue();
void FlushQueue();
inline void CompleteResume();
ChannelEvent* TakeEvent();
nsTArray<UniquePtr<ChannelEvent>> mEventQueue;
uint32_t mSuspendCount;
- bool mSuspended;
- bool mForced;
+ bool mSuspended;
+ uint32_t mForcedCount; // Support ForcedQueueing on multiple thread.
bool mFlushing;
// Keep ptr to avoid refcount cycle: only grab ref during flushing.
nsISupports *mOwner;
+ // For atomic mEventQueue operation and state update
Mutex mMutex;
- // EventTarget for delivery of events to the correct thread.
- nsCOMPtr<nsIEventTarget> mTargetThread;
+ // To guarantee event execution order among threads
+ ReentrantMonitor mRunningMonitor;
friend class AutoEventEnqueuer;
};
inline void
ChannelEventQueue::RunOrEnqueue(ChannelEvent* aCallback,
bool aAssertionWhenNotQueued)
{
MOZ_ASSERT(aCallback);
+ // Events execution could be a destruction of the channel (and our own
+ // destructor) unless we make sure its refcount doesn't drop to 0 while this
+ // method is running.
+ nsCOMPtr<nsISupports> kungFuDeathGrip(mOwner);
+ Unused << kungFuDeathGrip; // Not used in this function
+
// To avoid leaks.
UniquePtr<ChannelEvent> event(aCallback);
+ // To guarantee that the running event and all the events generated within
+ // it will be finished before events on other threads.
+ ReentrantMonitorAutoEnter monitor(mRunningMonitor);
+
{
MutexAutoLock lock(mMutex);
- bool enqueue = mForced || mSuspended || mFlushing;
- MOZ_ASSERT(enqueue == true || mEventQueue.IsEmpty(),
- "Should always enqueue if ChannelEventQueue not empty");
+ bool enqueue = !!mForcedCount || mSuspended || mFlushing || !mEventQueue.IsEmpty();
if (enqueue) {
mEventQueue.AppendElement(Move(event));
return;
}
+
+ nsCOMPtr<nsIEventTarget> target = event->GetEventTarget();
+ MOZ_ASSERT(target);
+
+ bool isCurrentThread = false;
+ DebugOnly<nsresult> rv = target->IsOnCurrentThread(&isCurrentThread);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+ if (!isCurrentThread) {
+ // Leverage Suspend/Resume mechanism to trigger flush procedure without
+ // creating a new one.
+ SuspendInternal();
+ mEventQueue.AppendElement(Move(event));
+ ResumeInternal();
+ return;
+ }
}
MOZ_RELEASE_ASSERT(!aAssertionWhenNotQueued);
event->Run();
}
inline void
ChannelEventQueue::StartForcedQueueing()
{
MutexAutoLock lock(mMutex);
- mForced = true;
+ ++mForcedCount;
}
inline void
ChannelEventQueue::EndForcedQueueing()
{
+ bool tryFlush = false;
{
MutexAutoLock lock(mMutex);
- mForced = false;
+ MOZ_ASSERT(mForcedCount > 0);
+ if(!--mForcedCount) {
+ tryFlush = true;
+ }
}
- MaybeFlushQueue();
+ if (tryFlush) {
+ MaybeFlushQueue();
+ }
+}
+
+inline nsresult
+ChannelEventQueue::PrependEvent(UniquePtr<ChannelEvent>& aEvent)
+{
+ MutexAutoLock lock(mMutex);
+
+ // Prepending event while no queue flush foreseen might cause the following
+ // channel events not run. This assertion here guarantee there must be a
+ // queue flush, either triggered by Resume or EndForcedQueueing, to execute
+ // the added event.
+ MOZ_ASSERT(mSuspended || !!mForcedCount);
+
+ UniquePtr<ChannelEvent>* newEvent =
+ mEventQueue.InsertElementAt(0, Move(aEvent));
+
+ if (!newEvent) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ return NS_OK;
}
inline nsresult
ChannelEventQueue::PrependEvents(nsTArray<UniquePtr<ChannelEvent>>& aEvents)
{
MutexAutoLock lock(mMutex);
+ // Prepending event while no queue flush foreseen might cause the following
+ // channel events not run. This assertion here guarantee there must be a
+ // queue flush, either triggered by Resume or EndForcedQueueing, to execute
+ // the added events.
+ MOZ_ASSERT(mSuspended || !!mForcedCount);
+
UniquePtr<ChannelEvent>* newEvents =
mEventQueue.InsertElementsAt(0, aEvents.Length());
if (!newEvents) {
return NS_ERROR_OUT_OF_MEMORY;
}
for (uint32_t i = 0; i < aEvents.Length(); i++) {
newEvents[i] = Move(aEvents[i]);
}
return NS_OK;
}
inline void
-ChannelEventQueue::Suspend()
-{
- MutexAutoLock lock(mMutex);
-
- mSuspended = true;
- mSuspendCount++;
-}
-
-inline void
ChannelEventQueue::CompleteResume()
{
+ bool tryFlush = false;
{
MutexAutoLock lock(mMutex);
// channel may have been suspended again since Resume fired event to call
// this.
if (!mSuspendCount) {
// we need to remain logically suspended (for purposes of queuing incoming
// messages) until this point, else new incoming messages could run before
// queued ones.
mSuspended = false;
+ tryFlush = true;
}
}
- MaybeFlushQueue();
+ if (tryFlush) {
+ MaybeFlushQueue();
+ }
}
inline void
ChannelEventQueue::MaybeFlushQueue()
{
// Don't flush if forced queuing on, we're already being flushed, or
// suspended, or there's nothing to flush
bool flushQueue = false;
{
MutexAutoLock lock(mMutex);
- flushQueue = !mForced && !mFlushing && !mSuspended &&
+ flushQueue = !mForcedCount && !mFlushing && !mSuspended &&
!mEventQueue.IsEmpty();
}
if (flushQueue) {
FlushQueue();
}
}
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -258,16 +258,22 @@ public:
{
}
void Run()
{
mChild->DoOnStartRequest(mChannelStatus, mContentLength, mContentType,
mLastModified, mEntityID, mURI);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
nsresult mChannelStatus;
int64_t mContentLength;
nsCString mContentType;
PRTime mLastModified;
nsCString mEntityID;
URIParams mURI;
@@ -364,16 +370,22 @@ public:
, mCount(aCount)
{
}
void Run()
{
mChild->DoOnDataAvailable(mChannelStatus, mData, mOffset, mCount);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
nsresult mChannelStatus;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
@@ -407,16 +419,22 @@ class MaybeDivertOnDataFTPEvent : public
, mOffset(offset)
, mCount(count) {}
void Run()
{
mChild->MaybeDivertOnData(mData, mOffset, mCount);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
void
@@ -493,16 +511,20 @@ public:
, mUseUTF8(aUseUTF8)
{
}
void Run()
{
mChild->DoOnStopRequest(mChannelStatus, mErrorMsg, mUseUTF8);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ return do_GetMainThread();
+ }
private:
FTPChannelChild* mChild;
nsresult mChannelStatus;
nsCString mErrorMsg;
bool mUseUTF8;
};
mozilla::ipc::IPCResult
@@ -554,16 +576,22 @@ class MaybeDivertOnStopFTPEvent : public
: mChild(child)
, mChannelStatus(aChannelStatus) {}
void Run()
{
mChild->MaybeDivertOnStop(mChannelStatus);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
nsresult mChannelStatus;
};
void
FTPChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus)
{
@@ -641,16 +669,23 @@ FTPChannelChild::DoOnStopRequest(const n
}
class FTPFailedAsyncOpenEvent : public ChannelEvent
{
public:
FTPFailedAsyncOpenEvent(FTPChannelChild* aChild, nsresult aStatus)
: mChild(aChild), mStatus(aStatus) {}
void Run() { mChild->DoFailedAsyncOpen(mStatus); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
nsresult mStatus;
};
mozilla::ipc::IPCResult
FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode)
{
@@ -693,16 +728,23 @@ class FTPFlushedForDiversionEvent : publ
{
MOZ_RELEASE_ASSERT(aChild);
}
void Run()
{
mChild->FlushedForDiversion();
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
};
mozilla::ipc::IPCResult
FTPChannelChild::RecvFlushedForDiversion()
{
LOG(("FTPChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
@@ -742,16 +784,23 @@ FTPChannelChild::RecvDivertMessages()
}
class FTPDeleteSelfEvent : public ChannelEvent
{
public:
explicit FTPDeleteSelfEvent(FTPChannelChild* aChild)
: mChild(aChild) {}
void Run() { mChild->DoDeleteSelf(); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
FTPChannelChild* mChild;
};
mozilla::ipc::IPCResult
FTPChannelChild::RecvDeleteSelf()
{
mEventQ->RunOrEnqueue(new FTPDeleteSelfEvent(this));
@@ -956,14 +1005,26 @@ FTPChannelChild::EnsureDispatcher()
mDispatcher = nsContentUtils::GetDispatcherByLoadInfo(loadInfo);
if (!mDispatcher) {
return;
}
nsCOMPtr<nsIEventTarget> target =
mDispatcher->EventTargetFor(TaskCategory::Network);
gNeckoChild->SetEventTargetForActor(this, target);
- mEventQ->RetargetDeliveryTo(target);
+
+ mNeckoTarget = target;
+}
+
+already_AddRefed<nsIEventTarget>
+FTPChannelChild::GetNeckoTarget()
+{
+ nsCOMPtr<nsIEventTarget> target = mNeckoTarget;
+
+ if (!target) {
+ target = do_GetMainThread();
+ }
+ return target.forget();
}
} // namespace net
} // namespace mozilla
--- a/netwerk/protocol/ftp/FTPChannelChild.h
+++ b/netwerk/protocol/ftp/FTPChannelChild.h
@@ -13,16 +13,17 @@
#include "mozilla/net/ChannelEventQueue.h"
#include "nsBaseChannel.h"
#include "nsIFTPChannel.h"
#include "nsIUploadChannel.h"
#include "nsIProxiedChannel.h"
#include "nsIResumableChannel.h"
#include "nsIChildChannel.h"
#include "nsIDivertableChannel.h"
+#include "nsIEventTarget.h"
#include "nsIStreamListener.h"
#include "PrivateBrowsingChannel.h"
namespace mozilla {
class Dispatcher;
@@ -118,19 +119,23 @@ protected:
void DoDeleteSelf();
friend class FTPStartRequestEvent;
friend class FTPDataAvailableEvent;
friend class MaybeDivertOnDataFTPEvent;
friend class FTPStopRequestEvent;
friend class MaybeDivertOnStopFTPEvent;
friend class FTPFailedAsyncOpenEvent;
+ friend class FTPFlushedForDiversionEvent;
friend class FTPDeleteSelfEvent;
private:
+ // Get event target for processing network events.
+ already_AddRefed<nsIEventTarget> GetNeckoTarget();
+
nsCOMPtr<nsIInputStream> mUploadStream;
bool mIPCOpen;
RefPtr<ChannelEventQueue> mEventQ;
// If nsUnknownDecoder is involved we queue onDataAvailable (and possibly
// OnStopRequest) so that we can divert them if needed when the listener's
// OnStartRequest is finally called
@@ -149,16 +154,19 @@ private:
bool mDivertingToParent;
// Once set, no OnStart/OnData/OnStop callbacks should be received from the
// parent channel, nor dequeued from the ChannelEventQueue.
bool mFlushedForDiversion;
// Set if SendSuspend is called. Determines if SendResume is needed when
// diverting callbacks to parent.
bool mSuspendSent;
+ // EventTarget for labeling networking events.
+ nsCOMPtr<nsIEventTarget> mNeckoTarget;
+
RefPtr<Dispatcher> mDispatcher;
void EnsureDispatcher();
};
inline bool
FTPChannelChild::IsSuspended()
{
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -235,17 +235,17 @@ mozilla::ipc::IPCResult
FTPChannelParent::RecvResume()
{
if (mChannel) {
ResumeChannel();
}
return IPC_OK();
}
-class FTPDivertDataAvailableEvent : public ChannelEvent
+class FTPDivertDataAvailableEvent : public MainThreadChannelEvent
{
public:
FTPDivertDataAvailableEvent(FTPChannelParent* aParent,
const nsCString& data,
const uint64_t& offset,
const uint32_t& count)
: mParent(aParent)
, mData(data)
@@ -326,17 +326,17 @@ FTPChannelParent::DivertOnDataAvailable(
if (NS_FAILED(rv)) {
if (mChannel) {
mChannel->Cancel(rv);
}
mStatus = rv;
}
}
-class FTPDivertStopRequestEvent : public ChannelEvent
+class FTPDivertStopRequestEvent : public MainThreadChannelEvent
{
public:
FTPDivertStopRequestEvent(FTPChannelParent* aParent,
const nsresult& statusCode)
: mParent(aParent)
, mStatusCode(statusCode)
{
}
@@ -386,17 +386,17 @@ FTPChannelParent::DivertOnStopRequest(co
forcePendingIChan->ForcePending(false);
}
}
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
OnStopRequest(mChannel, nullptr, status);
}
-class FTPDivertCompleteEvent : public ChannelEvent
+class FTPDivertCompleteEvent : public MainThreadChannelEvent
{
public:
explicit FTPDivertCompleteEvent(FTPChannelParent* aParent)
: mParent(aParent)
{
}
void Run() {
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -175,16 +175,17 @@ HttpChannelChild::HttpChannelChild()
, mSuspendSent(false)
, mSynthesizedResponse(false)
, mShouldInterceptSubsequentRedirect(false)
, mRedirectingForSubsequentSynthesizedResponse(false)
, mPostRedirectChannelShouldIntercept(false)
, mPostRedirectChannelShouldUpgrade(false)
, mShouldParentIntercept(false)
, mSuspendParentAfterSynthesizeResponse(false)
+ , mEventTargetMutex("HttpChannelChild::EventTargetMutex")
{
LOG(("Creating HttpChannelChild @%p\n", this));
mChannelCreationTime = PR_Now();
mChannelCreationTimestamp = TimeStamp::Now();
mAsyncOpenTime = TimeStamp::Now();
mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(this));
}
@@ -288,16 +289,23 @@ class AssociateApplicationCacheEvent : p
AssociateApplicationCacheEvent(HttpChannelChild* aChild,
const nsCString &aGroupID,
const nsCString &aClientID)
: mChild(aChild)
, groupID(aGroupID)
, clientID(aClientID) {}
void Run() { mChild->AssociateApplicationCache(groupID, clientID); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsCString groupID;
nsCString clientID;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID,
@@ -362,16 +370,23 @@ class StartRequestEvent : public Channel
{
LOG(("StartRequestEvent [this=%p]\n", mChild));
mChild->OnStartRequest(mChannelStatus, mResponseHead, mUseResponseHead,
mRequestHeaders, mIsFromCache, mCacheEntryAvailable,
mCacheExpirationTime, mCachedCharset,
mSecurityInfoSerialization, mSelfAddr, mPeerAddr,
mCacheKey, mAltDataType, mAltDataLen);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
nsHttpResponseHead mResponseHead;
nsHttpHeaderArray mRequestHeaders;
bool mUseResponseHead;
bool mIsFromCache;
bool mCacheEntryAvailable;
@@ -621,16 +636,23 @@ class TransportAndDataEvent : public Cha
, mOffset(offset)
, mCount(count) {}
void Run()
{
mChild->OnTransportAndData(mChannelStatus, mTransportStatus,
mOffset, mCount, mData);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
nsresult mTransportStatus;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
@@ -665,16 +687,22 @@ class MaybeDivertOnDataHttpEvent : publi
, mOffset(offset)
, mCount(count) {}
void Run()
{
mChild->MaybeDivertOnData(mData, mOffset, mCount);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsCString mData;
uint64_t mOffset;
uint32_t mCount;
};
void
@@ -828,16 +856,23 @@ class StopRequestEvent : public ChannelE
StopRequestEvent(HttpChannelChild* child,
const nsresult& channelStatus,
const ResourceTimingStruct& timing)
: mChild(child)
, mChannelStatus(channelStatus)
, mTiming(timing) {}
void Run() { mChild->OnStopRequest(mChannelStatus, mTiming); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
ResourceTimingStruct mTiming;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnStopRequest(const nsresult& channelStatus,
@@ -861,16 +896,22 @@ class MaybeDivertOnStopHttpEvent : publi
, mChannelStatus(channelStatus)
{}
void Run()
{
mChild->MaybeDivertOnStop(mChannelStatus);
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mChannelStatus;
};
void
HttpChannelChild::MaybeDivertOnStop(const nsresult& aChannelStatus)
{
@@ -1031,16 +1072,23 @@ class ProgressEvent : public ChannelEven
ProgressEvent(HttpChannelChild* child,
const int64_t& progress,
const int64_t& progressMax)
: mChild(child)
, mProgress(progress)
, mProgressMax(progressMax) {}
void Run() { mChild->OnProgress(mProgress, mProgressMax); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
int64_t mProgress, mProgressMax;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnProgress(const int64_t& progress,
const int64_t& progressMax)
@@ -1079,16 +1127,23 @@ class StatusEvent : public ChannelEvent
{
public:
StatusEvent(HttpChannelChild* child,
const nsresult& status)
: mChild(child)
, mStatus(status) {}
void Run() { mChild->OnStatus(mStatus); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mStatus;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvOnStatus(const nsresult& status)
{
@@ -1126,16 +1181,23 @@ HttpChannelChild::OnStatus(const nsresul
class FailedAsyncOpenEvent : public ChannelEvent
{
public:
FailedAsyncOpenEvent(HttpChannelChild* child, const nsresult& status)
: mChild(child)
, mStatus(status) {}
void Run() { mChild->FailedAsyncOpen(mStatus); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
nsresult mStatus;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status)
{
@@ -1180,16 +1242,23 @@ HttpChannelChild::DoNotifyListenerCleanu
}
}
class DeleteSelfEvent : public ChannelEvent
{
public:
explicit DeleteSelfEvent(HttpChannelChild* child) : mChild(child) {}
void Run() { mChild->DeleteSelf(); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvDeleteSelf()
{
LOG(("HttpChannelChild::RecvDeleteSelf [this=%p]\n", this));
@@ -1237,19 +1306,22 @@ HttpChannelChild::OverrideRunnable::Run(
mozilla::ipc::IPCResult
HttpChannelChild::RecvFinishInterceptedRedirect()
{
// Hold a ref to this to keep it from being deleted by Send__delete__()
RefPtr<HttpChannelChild> self(this);
Send__delete__(this);
- // Reset the event target since the IPC actor is about to be destroyed.
- // Following channel event should be handled on main thread.
- mEventQ->ResetDeliveryTarget();
+ {
+ // Reset the event target since the IPC actor is about to be destroyed.
+ // Following channel event should be handled on main thread.
+ MutexAutoLock lock(mEventTargetMutex);
+ mNeckoTarget = nullptr;
+ }
// The IPDL connection was torn down by a interception logic in
// CompleteRedirectSetup, and we need to call FinishInterceptedRedirect.
NS_DispatchToMainThread(NewRunnableMethod(this, &HttpChannelChild::FinishInterceptedRedirect));
return IPC_OK();
}
@@ -1310,16 +1382,23 @@ class Redirect1Event : public ChannelEve
, mChannelId(channelId) {}
void Run()
{
mChild->Redirect1Begin(mRegistrarId, mNewURI, mRedirectFlags,
mResponseHead, mSecurityInfoSerialization,
mChannelId);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
uint32_t mRegistrarId;
URIParams mNewURI;
uint32_t mRedirectFlags;
nsHttpResponseHead mResponseHead;
nsCString mSecurityInfoSerialization;
nsCString mChannelId;
@@ -1483,16 +1562,23 @@ HttpChannelChild::OverrideSecurityInfoFo
MOZ_ASSERT(NS_SUCCEEDED(rv));
}
class Redirect3Event : public ChannelEvent
{
public:
explicit Redirect3Event(HttpChannelChild* child) : mChild(child) {}
void Run() { mChild->Redirect3Complete(nullptr); }
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvRedirect3Complete()
{
LOG(("HttpChannelChild::RecvRedirect3Complete [this=%p]\n", this));
@@ -1508,16 +1594,23 @@ class HttpFlushedForDiversionEvent : pub
{
MOZ_RELEASE_ASSERT(aChild);
}
void Run()
{
mChild->FlushedForDiversion();
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ MOZ_ASSERT(mChild);
+ nsCOMPtr<nsIEventTarget> target = mChild->GetNeckoTarget();
+ return target.forget();
+ }
private:
HttpChannelChild* mChild;
};
mozilla::ipc::IPCResult
HttpChannelChild::RecvFlushedForDiversion()
{
LOG(("HttpChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
@@ -2101,17 +2194,36 @@ HttpChannelChild::SetEventTarget()
GetIsMainDocumentChannel(&isMainDocumentChannel);
MOZ_ASSERT(isMainDocumentChannel);
}
#endif
nsCOMPtr<nsIEventTarget> target =
dispatcher->EventTargetFor(TaskCategory::Network);
gNeckoChild->SetEventTargetForActor(this, target);
- mEventQ->RetargetDeliveryTo(target);
+
+ {
+ MutexAutoLock lock(mEventTargetMutex);
+ mNeckoTarget = target;
+ }
+}
+
+already_AddRefed<nsIEventTarget>
+HttpChannelChild::GetNeckoTarget()
+{
+ nsCOMPtr<nsIEventTarget> target;
+ {
+ MutexAutoLock lock(mEventTargetMutex);
+ target = mNeckoTarget;
+ }
+
+ if (!target) {
+ target = do_GetMainThread();
+ }
+ return target.forget();
}
nsresult
HttpChannelChild::ContinueAsyncOpen()
{
nsCString appCacheClientId;
if (mInheritApplicationCache) {
// Pick up an application cache from the notification
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -3,16 +3,17 @@
/* 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_net_HttpChannelChild_h
#define mozilla_net_HttpChannelChild_h
+#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "mozilla/net/PHttpChannelChild.h"
#include "mozilla/net/ChannelEventQueue.h"
#include "nsIStreamListener.h"
#include "nsILoadGroup.h"
#include "nsIInterfaceRequestor.h"
@@ -192,16 +193,19 @@ private:
};
// Sets the event target for future IPC messages. Messages will either be
// directed to the TabGroup or DocGroup, depending on the LoadInfo associated
// with the channel. Should be called when a new channel is being set up,
// before the constructor message is sent to the parent.
void SetEventTarget();
+ // Get event target for processing network events.
+ already_AddRefed<nsIEventTarget> GetNeckoTarget();
+
MOZ_MUST_USE nsresult ContinueAsyncOpen();
void DoOnStartRequest(nsIRequest* aRequest, nsISupports* aContext);
void DoOnStatus(nsIRequest* aRequest, nsresult status);
void DoOnProgress(nsIRequest* aRequest, int64_t progress, int64_t progressMax);
void DoOnDataAvailable(nsIRequest* aRequest, nsISupports* aContext, nsIInputStream* aStream,
uint64_t offset, uint32_t count);
void DoPreOnStopRequest(nsresult aStatus);
@@ -290,16 +294,21 @@ private:
// Needed to call AsyncOpen in FinishInterceptedRedirect
nsCOMPtr<nsIStreamListener> mInterceptedRedirectListener;
nsCOMPtr<nsISupports> mInterceptedRedirectContext;
// Needed to call CleanupRedirectingChannel in FinishInterceptedRedirect
RefPtr<HttpChannelChild> mInterceptingChannel;
// Used to call OverrideWithSynthesizedResponse in FinishInterceptedRedirect
RefPtr<OverrideRunnable> mOverrideRunnable;
+ // EventTarget for labeling networking events.
+ nsCOMPtr<nsIEventTarget> mNeckoTarget;
+ // Used to ensure atomicity of mNeckoTarget;
+ Mutex mEventTargetMutex;
+
void FinishInterceptedRedirect();
void CleanupRedirectingChannel(nsresult rv);
// true after successful AsyncOpen until OnStopRequest completes.
bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
void AssociateApplicationCache(const nsCString &groupID,
const nsCString &clientID);
@@ -361,16 +370,17 @@ private:
friend class MaybeDivertOnDataHttpEvent;
friend class MaybeDivertOnStopHttpEvent;
friend class ProgressEvent;
friend class StatusEvent;
friend class FailedAsyncOpenEvent;
friend class Redirect1Event;
friend class Redirect3Event;
friend class DeleteSelfEvent;
+ friend class HttpFlushedForDiversionEvent;
friend class HttpAsyncAborter<HttpChannelChild>;
friend class InterceptStreamListener;
friend class InterceptedChannelContent;
};
// A stream listener interposed between the nsInputStreamPump used for intercepted channels
// and this channel's original listener. This is only used to ensure the original listener
// sees the channel as the request object, and to synthesize OnStatus and OnProgress notifications.
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -833,17 +833,17 @@ HttpChannelParent::RecvMarkOfflineCacheE
if (mOfflineForeignMarker) {
mOfflineForeignMarker->MarkAsForeign();
mOfflineForeignMarker = 0;
}
return IPC_OK();
}
-class DivertDataAvailableEvent : public ChannelEvent
+class DivertDataAvailableEvent : public MainThreadChannelEvent
{
public:
DivertDataAvailableEvent(HttpChannelParent* aParent,
const nsCString& data,
const uint64_t& offset,
const uint32_t& count)
: mParent(aParent)
, mData(data)
@@ -928,17 +928,17 @@ HttpChannelParent::DivertOnDataAvailable
if (NS_FAILED(rv)) {
if (mChannel) {
mChannel->Cancel(rv);
}
mStatus = rv;
}
}
-class DivertStopRequestEvent : public ChannelEvent
+class DivertStopRequestEvent : public MainThreadChannelEvent
{
public:
DivertStopRequestEvent(HttpChannelParent* aParent,
const nsresult& statusCode)
: mParent(aParent)
, mStatusCode(statusCode)
{
}
@@ -989,17 +989,17 @@ HttpChannelParent::DivertOnStopRequest(c
if (mChannel) {
mChannel->ForcePending(false);
}
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
mParentListener->OnStopRequest(mChannel, nullptr, status);
}
-class DivertCompleteEvent : public ChannelEvent
+class DivertCompleteEvent : public MainThreadChannelEvent
{
public:
explicit DivertCompleteEvent(HttpChannelParent* aParent)
: mParent(aParent)
{
}
void Run() {
--- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp
@@ -171,16 +171,25 @@ public:
mEventTarget->Dispatch(new WrappedChannelEvent(mChannelEvent.forget()),
NS_DISPATCH_NORMAL);
return;
}
mChannelEvent->Run();
}
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = mEventTarget;
+ if (!target) {
+ target = do_GetMainThread();
+ }
+ return target.forget();
+ }
+
private:
nsAutoPtr<ChannelEvent> mChannelEvent;
nsCOMPtr<nsIEventTarget> mEventTarget;
};
class StartEvent : public ChannelEvent
{
public:
@@ -195,16 +204,23 @@ class StartEvent : public ChannelEvent
, mEffectiveURL(aEffectiveURL)
, mEncrypted(aEncrypted)
{}
void Run()
{
mChild->OnStart(mProtocol, mExtensions, mEffectiveURL, mEncrypted);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = do_GetCurrentThread();
+ return target.forget();
+ }
+
private:
RefPtr<WebSocketChannelChild> mChild;
nsCString mProtocol;
nsCString mExtensions;
nsString mEffectiveURL;
bool mEncrypted;
};
@@ -253,16 +269,23 @@ class StopEvent : public ChannelEvent
: mChild(aChild)
, mStatusCode(aStatusCode)
{}
void Run()
{
mChild->OnStop(mStatusCode);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = do_GetCurrentThread();
+ return target.forget();
+ }
+
private:
RefPtr<WebSocketChannelChild> mChild;
nsresult mStatusCode;
};
mozilla::ipc::IPCResult
WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode)
{
@@ -303,16 +326,23 @@ class MessageEvent : public ChannelEvent
void Run()
{
if (!mBinary) {
mChild->OnMessageAvailable(mMessage);
} else {
mChild->OnBinaryMessageAvailable(mMessage);
}
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = do_GetCurrentThread();
+ return target.forget();
+ }
+
private:
RefPtr<WebSocketChannelChild> mChild;
nsCString mMessage;
bool mBinary;
};
mozilla::ipc::IPCResult
WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg)
@@ -375,16 +405,23 @@ class AcknowledgeEvent : public ChannelE
: mChild(aChild)
, mSize(aSize)
{}
void Run()
{
mChild->OnAcknowledge(mSize);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = do_GetCurrentThread();
+ return target.forget();
+ }
+
private:
RefPtr<WebSocketChannelChild> mChild;
uint32_t mSize;
};
mozilla::ipc::IPCResult
WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize)
{
@@ -421,16 +458,23 @@ class ServerCloseEvent : public ChannelE
, mCode(aCode)
, mReason(aReason)
{}
void Run()
{
mChild->OnServerClose(mCode, mReason);
}
+
+ already_AddRefed<nsIEventTarget> GetEventTarget()
+ {
+ nsCOMPtr<nsIEventTarget> target = do_GetCurrentThread();
+ return target.forget();
+ }
+
private:
RefPtr<WebSocketChannelChild> mChild;
uint16_t mCode;
nsCString mReason;
};
mozilla::ipc::IPCResult
WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode,
@@ -716,29 +760,16 @@ WebSocketChannelChild::SendBinaryStream(
NS_IMETHODIMP
WebSocketChannelChild::GetSecurityInfo(nsISupports **aSecurityInfo)
{
LOG(("WebSocketChannelChild::GetSecurityInfo() %p\n", this));
return NS_ERROR_NOT_AVAILABLE;
}
-//-----------------------------------------------------------------------------
-// WebSocketChannelChild::nsIThreadRetargetableRequest
-//-----------------------------------------------------------------------------
-
-NS_IMETHODIMP
-WebSocketChannelChild::RetargetDeliveryTo(nsIEventTarget* aTargetThread)
-{
- nsresult rv = BaseWebSocketChannel::RetargetDeliveryTo(aTargetThread);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv));
-
- return mEventQ->RetargetDeliveryTo(aTargetThread);
-}
-
bool
WebSocketChannelChild::IsOnTargetThread()
{
MOZ_ASSERT(mTargetThread);
bool isOnTargetThread = false;
nsresult rv = mTargetThread->IsOnCurrentThread(&isOnTargetThread);
MOZ_ASSERT(NS_SUCCEEDED(rv));
return NS_FAILED(rv) ? false : isOnTargetThread;
--- a/netwerk/protocol/websocket/WebSocketChannelChild.h
+++ b/netwerk/protocol/websocket/WebSocketChannelChild.h
@@ -20,17 +20,16 @@ class ChannelEventQueue;
class WebSocketChannelChild final : public BaseWebSocketChannel,
public PWebSocketChild
{
public:
explicit WebSocketChannelChild(bool aSecure);
NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSITHREADRETARGETABLEREQUEST
// nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us
//
NS_IMETHOD AsyncOpen(nsIURI *aURI, const nsACString &aOrigin,
uint64_t aInnerWindowID,
nsIWebSocketListener *aListener,
nsISupports *aContext) override;
NS_IMETHOD Close(uint16_t code, const nsACString & reason) override;
--- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
+++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp
@@ -125,17 +125,17 @@ WyciwygChannelChild::Init(nsIURI* uri)
policyType);
return NS_OK;
}
//-----------------------------------------------------------------------------
// WyciwygChannelChild::PWyciwygChannelChild
//-----------------------------------------------------------------------------
-class WyciwygStartRequestEvent : public ChannelEvent
+class WyciwygStartRequestEvent : public MainThreadChannelEvent
{
public:
WyciwygStartRequestEvent(WyciwygChannelChild* child,
const nsresult& statusCode,
const int64_t& contentLength,
const int32_t& source,
const nsCString& charset,
const nsCString& securityInfo)
@@ -187,17 +187,17 @@ WyciwygChannelChild::OnStartRequest(cons
AutoEventEnqueuer ensureSerialDispatch(mEventQ);
nsresult rv = mListener->OnStartRequest(this, mListenerContext);
if (NS_FAILED(rv))
Cancel(rv);
}
-class WyciwygDataAvailableEvent : public ChannelEvent
+class WyciwygDataAvailableEvent : public MainThreadChannelEvent
{
public:
WyciwygDataAvailableEvent(WyciwygChannelChild* child,
const nsCString& data,
const uint64_t& offset)
: mChild(child), mData(data), mOffset(offset) {}
void Run() { mChild->OnDataAvailable(mData, mOffset); }
private:
@@ -248,17 +248,17 @@ WyciwygChannelChild::OnDataAvailable(con
Cancel(rv);
if (mProgressSink && NS_SUCCEEDED(rv)) {
mProgressSink->OnProgress(this, nullptr, offset + data.Length(),
mContentLength);
}
}
-class WyciwygStopRequestEvent : public ChannelEvent
+class WyciwygStopRequestEvent : public MainThreadChannelEvent
{
public:
WyciwygStopRequestEvent(WyciwygChannelChild* child,
const nsresult& statusCode)
: mChild(child), mStatusCode(statusCode) {}
void Run() { mChild->OnStopRequest(mStatusCode); }
private:
WyciwygChannelChild* mChild;
@@ -300,17 +300,17 @@ WyciwygChannelChild::OnStopRequest(const
mCallbacks = nullptr;
mProgressSink = nullptr;
}
if (mIPCOpen)
PWyciwygChannelChild::Send__delete__(this);
}
-class WyciwygCancelEvent : public ChannelEvent
+class WyciwygCancelEvent : public MainThreadChannelEvent
{
public:
WyciwygCancelEvent(WyciwygChannelChild* child, const nsresult& status)
: mChild(child)
, mStatus(status) {}
void Run() { mChild->CancelEarly(mStatus); }
private: