Bug 559200 - e10s HTTP: Buffer incoming IPDL necko messages. r=dougt

--HG--
extra : rebase_source : cfee85b987fb60fac9a3536774f63139000e797f
This commit is contained in:
Josh Matthews 2010-04-21 12:46:50 +09:30
parent 73cbe59a21
commit caccfbd455
2 changed files with 182 additions and 1 deletions

View File

@ -49,6 +49,14 @@
#include "nsMimeTypes.h"
#include "nsNetUtil.h"
using mozilla::MutexAutoLock;
class Callback
{
public:
virtual bool Run() = 0;
};
namespace mozilla {
namespace net {
@ -59,6 +67,8 @@ HttpChannelChild::HttpChannelChild()
, mCacheExpirationTime(nsICache::NO_EXPIRATION_TIME)
, mState(HCC_NEW)
, mIPCOpen(false)
, mShouldBuffer(true)
, mBufferLock("mozilla.net.HttpChannelChild.mBufferLock")
{
LOG(("Creating HttpChannelChild @%x\n", this));
}
@ -146,13 +156,56 @@ HttpChannelChild::RecvOnStartRequest(const nsHttpResponseHead& responseHead,
if (mResponseHead)
SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
return true;
MutexAutoLock lock(mBufferLock);
bool ret = true;
nsCOMPtr<nsIHttpChannel> kungFuDeathGrip(this);
for (PRUint32 i = 0; i < mBufferedCallbacks.Length(); i++) {
ret = mBufferedCallbacks[i]->Run();
if (!ret)
break;
}
mBufferedCallbacks.Clear();
mShouldBuffer = false;
return ret;
}
class DataAvailableEvent : public Callback
{
public:
DataAvailableEvent(HttpChannelChild* child,
const nsCString& data,
const PRUint32& offset,
const PRUint32& count)
: mChild(child)
, mData(data)
, mOffset(offset)
, mCount(count) {}
bool Run()
{
return mChild->OnDataAvailable(mData, mOffset, mCount);
}
private:
HttpChannelChild* mChild;
nsCString mData;
PRUint32 mOffset;
PRUint32 mCount;
};
bool
HttpChannelChild::RecvOnDataAvailable(const nsCString& data,
const PRUint32& offset,
const PRUint32& count)
{
DataAvailableEvent* event = new DataAvailableEvent(this, data, offset, count);
return BufferOrDispatch(event);
}
bool
HttpChannelChild::OnDataAvailable(const nsCString& data,
const PRUint32& offset,
const PRUint32& count)
{
LOG(("HttpChannelChild::RecvOnDataAvailable [this=%x]\n", this));
@ -182,8 +235,33 @@ HttpChannelChild::RecvOnDataAvailable(const nsCString& data,
return true;
}
class StopRequestEvent : public Callback
{
public:
StopRequestEvent(HttpChannelChild* child,
const nsresult& statusCode)
: mChild(child)
, mStatusCode(statusCode) {}
bool Run()
{
return mChild->OnStopRequest(mStatusCode);
}
private:
HttpChannelChild* mChild;
nsresult mStatusCode;
};
bool
HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode)
{
StopRequestEvent* event = new StopRequestEvent(this, statusCode);
return BufferOrDispatch(event);
}
bool
HttpChannelChild::OnStopRequest(const nsresult& statusCode)
{
LOG(("HttpChannelChild::RecvOnStopRequest [this=%x status=%u]\n",
this, statusCode));
@ -206,9 +284,37 @@ HttpChannelChild::RecvOnStopRequest(const nsresult& statusCode)
return true;
}
class ProgressEvent : public Callback
{
public:
ProgressEvent(HttpChannelChild* child,
const PRUint64& progress,
const PRUint64& progressMax)
: mChild(child)
, mProgress(progress)
, mProgressMax(progressMax) {}
bool Run()
{
return mChild->OnProgress(mProgress, mProgressMax);
}
private:
HttpChannelChild* mChild;
PRUint64 mProgress, mProgressMax;
};
bool
HttpChannelChild::RecvOnProgress(const PRUint64& progress,
const PRUint64& progressMax)
{
ProgressEvent* event = new ProgressEvent(this, progress, progressMax);
return BufferOrDispatch(event);
}
bool
HttpChannelChild::OnProgress(const PRUint64& progress,
const PRUint64& progressMax)
{
LOG(("HttpChannelChild::RecvOnProgress [this=%p progress=%llu/%llu]\n",
this, progress, progressMax));
@ -230,9 +336,38 @@ HttpChannelChild::RecvOnProgress(const PRUint64& progress,
return true;
}
class StatusEvent : public Callback
{
public:
StatusEvent(HttpChannelChild* child,
const nsresult& status,
const nsString& statusArg)
: mChild(child)
, mStatus(status)
, mStatusArg(statusArg) {}
bool Run()
{
return mChild->OnStatus(mStatus, mStatusArg);
}
private:
HttpChannelChild* mChild;
nsresult mStatus;
nsString mStatusArg;
};
bool
HttpChannelChild::RecvOnStatus(const nsresult& status,
const nsString& statusArg)
{
StatusEvent* event = new StatusEvent(this, status, statusArg);
return BufferOrDispatch(event);
}
bool
HttpChannelChild::OnStatus(const nsresult& status,
const nsString& statusArg)
{
LOG(("HttpChannelChild::RecvOnStatus [this=%p status=%x]\n", this, status));
@ -250,6 +385,25 @@ HttpChannelChild::RecvOnStatus(const nsresult& status,
return true;
}
bool
HttpChannelChild::BufferOrDispatch(Callback* callback)
{
if (mShouldBuffer) {
MutexAutoLock lock(mBufferLock);
// If we can't grab the lock immediately, that means we're currently
// emptying the buffer. Therefore, the following condition should now
// be false, and we can resume immediate message processing.
if (mShouldBuffer) {
mBufferedCallbacks.AppendElement(callback);
return true;
}
}
bool result = callback->Run();
delete callback;
return result;
}
//-----------------------------------------------------------------------------
// HttpChannelChild::nsIRequest
//-----------------------------------------------------------------------------

View File

@ -58,6 +58,10 @@
#include "nsIResumableChannel.h"
#include "nsIProxiedChannel.h"
#include "nsITraceableChannel.h"
#include "mozilla/Mutex.h"
class nsIRunnable;
class Callback;
namespace mozilla {
namespace net {
@ -143,6 +147,29 @@ private:
// FIXME: replace with IPDL states (bug 536319)
enum HttpChannelChildState mState;
bool mIPCOpen;
// Workaround for Necko re-entrancy dangers. We buffer all messages
// received until OnStartRequest completes.
nsTArray<nsAutoPtr<Callback> > mBufferedCallbacks;
bool mShouldBuffer;
mozilla::Mutex mBufferLock;
bool BufferOrDispatch(Callback* callback);
// This class does not actually implement the stream listener interface.
// These functions actually perform the actions associated with the
// corresponding IPDL receivers above.
bool OnDataAvailable(const nsCString& data,
const PRUint32& offset,
const PRUint32& count);
bool OnStopRequest(const nsresult& statusCode);
bool OnProgress(const PRUint64& progress, const PRUint64& progressMax);
bool OnStatus(const nsresult& status, const nsString& statusArg);
friend class StopRequestEvent;
friend class DataAvailableEvent;
friend class ProgressEvent;
friend class StatusEvent;
};
} // namespace net