diff --git a/netwerk/ipc/ChannelEventQueue.h b/netwerk/ipc/ChannelEventQueue.h index 704c6f9b70ea..0350514d1cd0 100644 --- a/netwerk/ipc/ChannelEventQueue.h +++ b/netwerk/ipc/ChannelEventQueue.h @@ -10,6 +10,7 @@ #include #include +#include class nsISupports; @@ -35,10 +36,13 @@ class AutoEventEnqueuerBase; class ChannelEventQueue { + NS_INLINE_DECL_REFCOUNTING(ChannelEventQueue) + public: ChannelEventQueue(nsISupports *owner) - : mForced(false) + : mSuspendCount(0) , mSuspended(false) + , mForced(false) , mFlushing(false) , mOwner(owner) {} @@ -63,22 +67,21 @@ class ChannelEventQueue // Suspend/resume event queue. ShouldEnqueue() will return true and no events // will be run/flushed until resume is called. These should be called when // the channel owning the event queue is suspended/resumed. - // - Note: these suspend/resume functions are NOT meant to be called - // recursively: call them only at initial suspend, and actual resume). - // - Note: Resume flushes the queue and invokes any pending callbacks - // immediately--caller must arrange any needed asynchronicity vis a vis - // the channel's own Resume() method. inline void Suspend(); + // Resume flushes the queue asynchronously, i.e. items in queue will be + // dispatched in a new event on the current thread. inline void Resume(); private: inline void MaybeFlushQueue(); void FlushQueue(); + inline void CompleteResume(); nsTArray > mEventQueue; + uint32_t mSuspendCount; + bool mSuspended; bool mForced; - bool mSuspended; bool mFlushing; // Keep ptr to avoid refcount cycle: only grab ref during flushing. @@ -120,20 +123,37 @@ ChannelEventQueue::EndForcedQueueing() inline void ChannelEventQueue::Suspend() { - NS_ABORT_IF_FALSE(!mSuspended, - "ChannelEventQueue::Suspend called recursively"); - mSuspended = true; + mSuspendCount++; +} + +inline void +ChannelEventQueue::CompleteResume() +{ + // 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; + MaybeFlushQueue(); + } } inline void ChannelEventQueue::Resume() { - NS_ABORT_IF_FALSE(mSuspended, - "ChannelEventQueue::Resume called when not suspended!"); + // Resuming w/o suspend: error in debug mode, ignore in build + MOZ_ASSERT(mSuspendCount > 0); + if (mSuspendCount <= 0) { + return; + } - mSuspended = false; - MaybeFlushQueue(); + if (!--mSuspendCount) { + nsRefPtr > event = + NS_NewRunnableMethod(this, &ChannelEventQueue::CompleteResume); + NS_DispatchToCurrentThread(event); + } } inline void @@ -151,14 +171,14 @@ ChannelEventQueue::MaybeFlushQueue() class AutoEventEnqueuer { public: - AutoEventEnqueuer(ChannelEventQueue &queue) : mEventQueue(queue) { - mEventQueue.StartForcedQueueing(); + AutoEventEnqueuer(ChannelEventQueue *queue) : mEventQueue(queue) { + mEventQueue->StartForcedQueueing(); } ~AutoEventEnqueuer() { - mEventQueue.EndForcedQueueing(); + mEventQueue->EndForcedQueueing(); } private: - ChannelEventQueue &mEventQueue; + ChannelEventQueue* mEventQueue; }; } diff --git a/netwerk/protocol/ftp/FTPChannelChild.cpp b/netwerk/protocol/ftp/FTPChannelChild.cpp index c433bb63ca0e..70f14b3d0326 100644 --- a/netwerk/protocol/ftp/FTPChannelChild.cpp +++ b/netwerk/protocol/ftp/FTPChannelChild.cpp @@ -30,7 +30,6 @@ namespace net { FTPChannelChild::FTPChannelChild(nsIURI* uri) : mIPCOpen(false) -, ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast(this))) , mCanceled(false) , mSuspendCount(0) , mIsPending(false) @@ -42,6 +41,7 @@ FTPChannelChild::FTPChannelChild(nsIURI* uri) // grab a reference to the handler to ensure that it doesn't go away. NS_ADDREF(gFtpHandler); SetURI(uri); + mEventQ = new ChannelEventQueue(static_cast(this)); } FTPChannelChild::~FTPChannelChild() @@ -242,9 +242,9 @@ FTPChannelChild::RecvOnStartRequest(const int64_t& aContentLength, const nsCString& aEntityID, const URIParams& aURI) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FTPStartRequestEvent(this, aContentLength, aContentType, - aLastModified, aEntityID, aURI)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FTPStartRequestEvent(this, aContentLength, aContentType, + aLastModified, aEntityID, aURI)); } else { DoOnStartRequest(aContentLength, aContentType, aLastModified, aEntityID, aURI); @@ -296,8 +296,8 @@ FTPChannelChild::RecvOnDataAvailable(const nsCString& data, const uint64_t& offset, const uint32_t& count) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FTPDataAvailableEvent(this, data, offset, count)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FTPDataAvailableEvent(this, data, offset, count)); } else { DoOnDataAvailable(data, offset, count); } @@ -351,8 +351,8 @@ class FTPStopRequestEvent : public ChannelEvent bool FTPChannelChild::RecvOnStopRequest(const nsresult& statusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FTPStopRequestEvent(this, statusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FTPStopRequestEvent(this, statusCode)); } else { DoOnStopRequest(statusCode); } @@ -399,8 +399,8 @@ class FTPFailedAsyncOpenEvent : public ChannelEvent bool FTPChannelChild::RecvFailedAsyncOpen(const nsresult& statusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FTPFailedAsyncOpenEvent(this, statusCode)); } else { DoFailedAsyncOpen(statusCode); } @@ -443,8 +443,8 @@ class FTPDeleteSelfEvent : public ChannelEvent bool FTPChannelChild::RecvDeleteSelf() { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FTPDeleteSelfEvent(this)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FTPDeleteSelfEvent(this)); } else { DoDeleteSelf(); } @@ -477,32 +477,12 @@ FTPChannelChild::Suspend() NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE); if (!mSuspendCount++) { SendSuspend(); - mEventQ.Suspend(); } + mEventQ->Suspend(); + return NS_OK; } -nsresult -FTPChannelChild::AsyncCall(void (FTPChannelChild::*funcPtr)(), - nsRunnableMethod **retval) -{ - nsresult rv; - - nsRefPtr > event = NS_NewRunnableMethod(this, funcPtr); - rv = NS_DispatchToCurrentThread(event); - if (NS_SUCCEEDED(rv) && retval) { - *retval = event; - } - - return rv; -} - -void -FTPChannelChild::CompleteResume() -{ - mEventQ.Resume(); -} - NS_IMETHODIMP FTPChannelChild::Resume() { @@ -510,8 +490,9 @@ FTPChannelChild::Resume() if (!--mSuspendCount) { SendResume(); - AsyncCall(&FTPChannelChild::CompleteResume); } + mEventQ->Resume(); + return NS_OK; } diff --git a/netwerk/protocol/ftp/FTPChannelChild.h b/netwerk/protocol/ftp/FTPChannelChild.h index 2683734367f3..1379e21ad2a1 100644 --- a/netwerk/protocol/ftp/FTPChannelChild.h +++ b/netwerk/protocol/ftp/FTPChannelChild.h @@ -100,15 +100,10 @@ protected: friend class FTPDeleteSelfEvent; private: - // Called asynchronously from Resume: continues any pending calls into client. - void CompleteResume(); - nsresult AsyncCall(void (FTPChannelChild::*funcPtr)(), - nsRunnableMethod **retval = nullptr); - nsCOMPtr mUploadStream; bool mIPCOpen; - ChannelEventQueue mEventQ; + nsRefPtr mEventQ; bool mCanceled; uint32_t mSuspendCount; bool mIsPending; diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index f1b4bc5e2c7c..812981821287 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -38,9 +38,10 @@ HttpChannelChild::HttpChannelChild() , mSendResumeAt(false) , mIPCOpen(false) , mKeptAlive(false) - , ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast(this))) { LOG(("Creating HttpChannelChild @%x\n", this)); + + mEventQ = new ChannelEventQueue(static_cast(this)); } HttpChannelChild::~HttpChannelChild() @@ -141,8 +142,8 @@ bool HttpChannelChild::RecvAssociateApplicationCache(const nsCString &groupID, const nsCString &clientID) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new AssociateApplicationCacheEvent(this, groupID, clientID)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new AssociateApplicationCacheEvent(this, groupID, clientID)); } else { AssociateApplicationCache(groupID, clientID); } @@ -222,8 +223,8 @@ HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead, const NetAddr& selfAddr, const NetAddr& peerAddr) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new StartRequestEvent(this, responseHead, useResponseHead, + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new StartRequestEvent(this, responseHead, useResponseHead, requestHeaders, isFromCache, cacheEntryAvailable, cacheExpirationTime, cachedCharset, @@ -331,8 +332,8 @@ HttpChannelChild::RecvOnTransportAndData(const nsresult& status, const uint64_t& offset, const uint32_t& count) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new TransportAndDataEvent(this, status, progress, + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new TransportAndDataEvent(this, status, progress, progressMax, data, offset, count)); } else { @@ -427,8 +428,8 @@ class StopRequestEvent : public ChannelEvent bool HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new StopRequestEvent(this, statusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new StopRequestEvent(this, statusCode)); } else { OnStopRequest(statusCode); } @@ -491,8 +492,8 @@ bool HttpChannelChild::RecvOnProgress(const uint64_t& progress, const uint64_t& progressMax) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new ProgressEvent(this, progress, progressMax)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new ProgressEvent(this, progress, progressMax)); } else { OnProgress(progress, progressMax); } @@ -544,8 +545,8 @@ class StatusEvent : public ChannelEvent bool HttpChannelChild::RecvOnStatus(const nsresult& status) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new StatusEvent(this, status)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new StatusEvent(this, status)); } else { OnStatus(status); } @@ -594,8 +595,8 @@ class FailedAsyncOpenEvent : public ChannelEvent bool HttpChannelChild::RecvFailedAsyncOpen(const nsresult& status) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new FailedAsyncOpenEvent(this, status)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new FailedAsyncOpenEvent(this, status)); } else { FailedAsyncOpen(status); } @@ -641,8 +642,8 @@ class DeleteSelfEvent : public ChannelEvent bool HttpChannelChild::RecvDeleteSelf() { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new DeleteSelfEvent(this)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new DeleteSelfEvent(this)); } else { DeleteSelf(); } @@ -688,8 +689,8 @@ HttpChannelChild::RecvRedirect1Begin(const uint32_t& newChannelId, const uint32_t& redirectFlags, const nsHttpResponseHead& responseHead) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new Redirect1Event(this, newChannelId, newUri, + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new Redirect1Event(this, newChannelId, newUri, redirectFlags, responseHead)); } else { Redirect1Begin(newChannelId, newUri, redirectFlags, responseHead); @@ -763,8 +764,8 @@ class Redirect3Event : public ChannelEvent bool HttpChannelChild::RecvRedirect3Complete() { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new Redirect3Event(this)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new Redirect3Event(this)); } else { Redirect3Complete(); } @@ -931,24 +932,12 @@ HttpChannelChild::Suspend() NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE); if (!mSuspendCount++) { SendSuspend(); - mEventQ.Suspend(); } + mEventQ->Suspend(); + return NS_OK; } -void -HttpChannelChild::CompleteResume() -{ - if (mCallOnResume) { - (this->*mCallOnResume)(); - mCallOnResume = 0; - } - - // Don't resume event queue until now, else queued events could get - // flushed/called before mCallOnResume, which needs to run first. - mEventQ.Resume(); -} - NS_IMETHODIMP HttpChannelChild::Resume() { @@ -959,8 +948,13 @@ HttpChannelChild::Resume() if (!--mSuspendCount) { SendResume(); - rv = AsyncCall(&HttpChannelChild::CompleteResume); + if (mCallOnResume) { + AsyncCall(mCallOnResume); + mCallOnResume = nullptr; + } } + mEventQ->Resume(); + return rv; } diff --git a/netwerk/protocol/http/HttpChannelChild.h b/netwerk/protocol/http/HttpChannelChild.h index 4ae9de6f127c..6a91c9e435e2 100644 --- a/netwerk/protocol/http/HttpChannelChild.h +++ b/netwerk/protocol/http/HttpChannelChild.h @@ -138,7 +138,7 @@ private: bool mIPCOpen; bool mKeptAlive; // IPC kept open, but only for security info - ChannelEventQueue mEventQ; + nsRefPtr mEventQ; // true after successful AsyncOpen until OnStopRequest completes. bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; } @@ -173,9 +173,6 @@ private: void Redirect3Complete(); void DeleteSelf(); - // Called asynchronously from Resume: continues any pending calls into client. - void CompleteResume(); - friend class AssociateApplicationCacheEvent; friend class StartRequestEvent; friend class StopRequestEvent; diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index 620d2adef5cf..e6c5b249195d 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -49,11 +49,11 @@ NS_INTERFACE_MAP_BEGIN(WebSocketChannelChild) NS_INTERFACE_MAP_END WebSocketChannelChild::WebSocketChannelChild(bool aSecure) -: ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast(this))) -, mIPCOpen(false) + : mIPCOpen(false) { LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this)); BaseWebSocketChannel::mEncrypted = aSecure; + mEventQ = new ChannelEventQueue(static_cast(this)); } WebSocketChannelChild::~WebSocketChannelChild() @@ -102,8 +102,8 @@ bool WebSocketChannelChild::RecvOnStart(const nsCString& aProtocol, const nsCString& aExtensions) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new StartEvent(this, aProtocol, aExtensions)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new StartEvent(this, aProtocol, aExtensions)); } else { OnStart(aProtocol, aExtensions); } @@ -145,8 +145,8 @@ class StopEvent : public ChannelEvent bool WebSocketChannelChild::RecvOnStop(const nsresult& aStatusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new StopEvent(this, aStatusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new StopEvent(this, aStatusCode)); } else { OnStop(aStatusCode); } @@ -191,8 +191,8 @@ class MessageEvent : public ChannelEvent bool WebSocketChannelChild::RecvOnMessageAvailable(const nsCString& aMsg) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new MessageEvent(this, aMsg, false)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new MessageEvent(this, aMsg, false)); } else { OnMessageAvailable(aMsg); } @@ -212,8 +212,8 @@ WebSocketChannelChild::OnMessageAvailable(const nsCString& aMsg) bool WebSocketChannelChild::RecvOnBinaryMessageAvailable(const nsCString& aMsg) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new MessageEvent(this, aMsg, true)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new MessageEvent(this, aMsg, true)); } else { OnBinaryMessageAvailable(aMsg); } @@ -251,8 +251,8 @@ class AcknowledgeEvent : public ChannelEvent bool WebSocketChannelChild::RecvOnAcknowledge(const uint32_t& aSize) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new AcknowledgeEvent(this, aSize)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new AcknowledgeEvent(this, aSize)); } else { OnAcknowledge(aSize); } @@ -294,8 +294,8 @@ bool WebSocketChannelChild::RecvOnServerClose(const uint16_t& aCode, const nsCString& aReason) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new ServerCloseEvent(this, aCode, aReason)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new ServerCloseEvent(this, aCode, aReason)); } else { OnServerClose(aCode, aReason); } diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.h b/netwerk/protocol/websocket/WebSocketChannelChild.h index 5265b6e6b4f4..c09aa32565ef 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.h +++ b/netwerk/protocol/websocket/WebSocketChannelChild.h @@ -55,7 +55,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel, void OnServerClose(const uint16_t& aCode, const nsCString& aReason); void AsyncOpenFailed(); - ChannelEventQueue mEventQ; + nsRefPtr mEventQ; bool mIPCOpen; friend class StartEvent; diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp index d9dc8e87ea96..d00f5ab7b775 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp +++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.cpp @@ -41,9 +41,9 @@ WyciwygChannelChild::WyciwygChannelChild() , mState(WCC_NEW) , mIPCOpen(false) , mSentAppData(false) - , ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this))) { LOG(("Creating WyciwygChannelChild @%x\n", this)); + mEventQ = new ChannelEventQueue(NS_ISUPPORTS_CAST(nsIWyciwygChannel*, this)); } WyciwygChannelChild::~WyciwygChannelChild() @@ -117,8 +117,8 @@ WyciwygChannelChild::RecvOnStartRequest(const nsresult& statusCode, const nsCString& charset, const nsCString& securityInfo) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new WyciwygStartRequestEvent(this, statusCode, + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new WyciwygStartRequestEvent(this, statusCode, contentLength, source, charset, securityInfo)); } else { @@ -172,8 +172,8 @@ bool WyciwygChannelChild::RecvOnDataAvailable(const nsCString& data, const uint64_t& offset) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new WyciwygDataAvailableEvent(this, data, offset)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new WyciwygDataAvailableEvent(this, data, offset)); } else { OnDataAvailable(data, offset); } @@ -233,8 +233,8 @@ private: bool WyciwygChannelChild::RecvOnStopRequest(const nsresult& statusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new WyciwygStopRequestEvent(this, statusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new WyciwygStopRequestEvent(this, statusCode)); } else { OnStopRequest(statusCode); } @@ -290,8 +290,8 @@ class WyciwygCancelEvent : public ChannelEvent bool WyciwygChannelChild::RecvCancelEarly(const nsresult& statusCode) { - if (mEventQ.ShouldEnqueue()) { - mEventQ.Enqueue(new WyciwygCancelEvent(this, statusCode)); + if (mEventQ->ShouldEnqueue()) { + mEventQ->Enqueue(new WyciwygCancelEvent(this, statusCode)); } else { CancelEarly(statusCode); } diff --git a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h index fa79771dd042..e2c1c5bd2fb1 100644 --- a/netwerk/protocol/wyciwyg/WyciwygChannelChild.h +++ b/netwerk/protocol/wyciwyg/WyciwygChannelChild.h @@ -99,7 +99,7 @@ private: bool mIPCOpen; bool mSentAppData; - ChannelEventQueue mEventQ; + nsRefPtr mEventQ; friend class WyciwygStartRequestEvent; friend class WyciwygDataAvailableEvent;