Bug 870564 - Youtube video freezes after a long time r=jdm

This commit is contained in:
Jason Duell 2013-06-04 16:10:55 -07:00
Родитель 34288bd4dd
Коммит c36b0246a8
9 изменённых файлов: 111 добавлений и 124 удалений

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

@ -10,6 +10,7 @@
#include <nsTArray.h>
#include <nsAutoPtr.h>
#include <nsThreadUtils.h>
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<nsAutoPtr<ChannelEvent> > 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<nsRunnableMethod<ChannelEventQueue> > 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;
};
}

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

@ -30,7 +30,6 @@ namespace net {
FTPChannelChild::FTPChannelChild(nsIURI* uri)
: mIPCOpen(false)
, ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast<nsIFTPChannel*>(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<nsIFTPChannel*>(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<FTPChannelChild> **retval)
{
nsresult rv;
nsRefPtr<nsRunnableMethod<FTPChannelChild> > 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;
}

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

@ -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<FTPChannelChild> **retval = nullptr);
nsCOMPtr<nsIInputStream> mUploadStream;
bool mIPCOpen;
ChannelEventQueue mEventQ;
nsRefPtr<ChannelEventQueue> mEventQ;
bool mCanceled;
uint32_t mSuspendCount;
bool mIsPending;

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

@ -38,9 +38,10 @@ HttpChannelChild::HttpChannelChild()
, mSendResumeAt(false)
, mIPCOpen(false)
, mKeptAlive(false)
, ALLOW_THIS_IN_INITIALIZER_LIST(mEventQ(static_cast<nsIHttpChannel*>(this)))
{
LOG(("Creating HttpChannelChild @%x\n", this));
mEventQ = new ChannelEventQueue(static_cast<nsIHttpChannel*>(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;
}

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

@ -138,7 +138,7 @@ private:
bool mIPCOpen;
bool mKeptAlive; // IPC kept open, but only for security info
ChannelEventQueue mEventQ;
nsRefPtr<ChannelEventQueue> 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;

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

@ -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<nsIWebSocketChannel*>(this)))
, mIPCOpen(false)
: mIPCOpen(false)
{
LOG(("WebSocketChannelChild::WebSocketChannelChild() %p\n", this));
BaseWebSocketChannel::mEncrypted = aSecure;
mEventQ = new ChannelEventQueue(static_cast<nsIWebSocketChannel*>(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);
}

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

@ -55,7 +55,7 @@ class WebSocketChannelChild : public BaseWebSocketChannel,
void OnServerClose(const uint16_t& aCode, const nsCString& aReason);
void AsyncOpenFailed();
ChannelEventQueue mEventQ;
nsRefPtr<ChannelEventQueue> mEventQ;
bool mIPCOpen;
friend class StartEvent;

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

@ -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);
}

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

@ -99,7 +99,7 @@ private:
bool mIPCOpen;
bool mSentAppData;
ChannelEventQueue mEventQ;
nsRefPtr<ChannelEventQueue> mEventQ;
friend class WyciwygStartRequestEvent;
friend class WyciwygDataAvailableEvent;