Bug 497003 - Support delivery of OnDataAvailable on the HTML5 parser thread r=hsivonen r=bholley r=bz

This commit is contained in:
Steve Workman 2013-07-08 18:45:26 -07:00
parent 39eb54cc4f
commit 881c09835a
6 changed files with 126 additions and 22 deletions

View File

@ -103,6 +103,16 @@ nsStreamListenerTee::CheckListenerChain()
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
if (NS_FAILED(rv)) {
return rv;
}
if (!mObserver) {
return rv;
}
retargetableListener = do_QueryInterface(mObserver, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
return rv;
}

View File

@ -27,6 +27,8 @@
#include "nsCharsetSource.h"
#include "nsIWyciwygChannel.h"
#include "nsIInputStreamChannel.h"
#include "nsIThreadRetargetableRequest.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/EncodingUtils.h"
@ -74,9 +76,10 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHtml5StreamParser)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHtml5StreamParser)
NS_INTERFACE_TABLE_HEAD(nsHtml5StreamParser)
NS_INTERFACE_TABLE2(nsHtml5StreamParser,
NS_INTERFACE_TABLE3(nsHtml5StreamParser,
nsIStreamListener,
nsICharsetDetectionObserver)
nsICharsetDetectionObserver,
nsIThreadRetargetableStreamListener)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsHtml5StreamParser)
NS_INTERFACE_MAP_END
@ -928,6 +931,14 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
mReparseForbidden = true;
mFeedChardet = false; // can't restart anyway
}
// Attempt to retarget delivery of data (via OnDataAvailable) to the parser
// thread, rather than through the main thread.
nsCOMPtr<nsIThreadRetargetableRequest> threadRetargetableRequest =
do_QueryInterface(mRequest);
if (threadRetargetableRequest) {
threadRetargetableRequest->RetargetDeliveryTo(mThread);
}
}
if (mCharsetSource == kCharsetFromParentFrame) {
@ -962,6 +973,22 @@ nsHtml5StreamParser::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
return NS_OK;
}
NS_IMETHODIMP
nsHtml5StreamParser::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
if (!mObserver) {
return NS_OK;
}
nsresult rv;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetable =
do_QueryInterface(mObserver, &rv);
if (NS_SUCCEEDED(rv) && retargetable) {
rv = retargetable->CheckListenerChain();
}
return rv;
}
void
nsHtml5StreamParser::DoStopRequest()
{
@ -1027,7 +1054,7 @@ nsHtml5StreamParser::OnStopRequest(nsIRequest* aRequest,
}
void
nsHtml5StreamParser::DoDataAvailable(uint8_t* aBuffer, uint32_t aLength)
nsHtml5StreamParser::DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength)
{
NS_ASSERTION(IsParserThread(), "Wrong thread!");
NS_PRECONDITION(STREAM_BEING_READ == mStreamState,
@ -1112,22 +1139,55 @@ nsHtml5StreamParser::OnDataAvailable(nsIRequest* aRequest,
NS_ASSERTION(mRequest == aRequest, "Got data on wrong stream.");
uint32_t totalRead;
const mozilla::fallible_t fallible = mozilla::fallible_t();
nsAutoArrayPtr<uint8_t> data(new (fallible) uint8_t[aLength]);
if (!data) {
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
// Main thread to parser thread dispatch requires copying to buffer first.
if (NS_IsMainThread()) {
const mozilla::fallible_t fallible = mozilla::fallible_t();
nsAutoArrayPtr<uint8_t> data(new (fallible) uint8_t[aLength]);
if (!data) {
return mExecutor->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
}
rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
aLength, &totalRead);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
nsCOMPtr<nsIRunnable> dataAvailable = new nsHtml5DataAvailable(this,
data.forget(),
totalRead);
if (NS_FAILED(mThread->Dispatch(dataAvailable, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching DataAvailable event failed.");
}
return rv;
} else {
NS_ASSERTION(IsParserThread(), "Wrong thread!");
mozilla::MutexAutoLock autoLock(mTokenizerMutex);
// Read directly from response buffer.
rv = aInStream->ReadSegments(CopySegmentsToParser, this, aLength,
&totalRead);
if (NS_FAILED(rv)) {
NS_WARNING("Failed reading response data to parser");
return rv;
}
return NS_OK;
}
rv = aInStream->Read(reinterpret_cast<char*>(data.get()),
aLength, &totalRead);
NS_ENSURE_SUCCESS(rv, rv);
NS_ASSERTION(totalRead <= aLength, "Read more bytes than were available?");
nsCOMPtr<nsIRunnable> dataAvailable = new nsHtml5DataAvailable(this,
data.forget(),
totalRead);
if (NS_FAILED(mThread->Dispatch(dataAvailable, nsIThread::DISPATCH_NORMAL))) {
NS_WARNING("Dispatching DataAvailable event failed.");
}
return rv;
}
/* static */
NS_METHOD
nsHtml5StreamParser::CopySegmentsToParser(nsIInputStream *aInStream,
void *aClosure,
const char *aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t *aWriteCount)
{
nsHtml5StreamParser* parser = static_cast<nsHtml5StreamParser*>(aClosure);
parser->DoDataAvailable((const uint8_t*)aFromSegment, aCount);
// Assume DoDataAvailable consumed all available bytes.
*aWriteCount = aCount;
return NS_OK;
}
bool

View File

@ -20,6 +20,7 @@
#include "nsHtml5Speculation.h"
#include "nsITimer.h"
#include "nsICharsetDetector.h"
#include "nsIThreadRetargetableStreamListener.h"
class nsHtml5Parser;
@ -101,6 +102,7 @@ enum eHtml5StreamState {
};
class nsHtml5StreamParser : public nsIStreamListener,
public nsIThreadRetargetableStreamListener,
public nsICharsetDetectionObserver {
friend class nsHtml5RequestStopper;
@ -125,6 +127,8 @@ class nsHtml5StreamParser : public nsIStreamListener,
NS_DECL_NSIREQUESTOBSERVER
// nsIStreamListener methods:
NS_DECL_NSISTREAMLISTENER
// nsIThreadRetargetableStreamListener methods:
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
// nsICharsetDetectionObserver
/**
@ -241,7 +245,14 @@ class nsHtml5StreamParser : public nsIStreamListener,
void DoStopRequest();
void DoDataAvailable(uint8_t* aBuffer, uint32_t aLength);
void DoDataAvailable(const uint8_t* aBuffer, uint32_t aLength);
static NS_METHOD CopySegmentsToParser(nsIInputStream *aInStream,
void *aClosure,
const char *aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t *aWriteCount);
bool IsTerminatedOrInterrupted() {
mozilla::MutexAutoLock autoLock(mTerminatedMutex);

View File

@ -228,7 +228,6 @@ class nsHtml5TreeOpExecutor : public nsContentSink,
* value if broken.
*/
inline nsresult IsBroken() {
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
return mBroken;
}

View File

@ -30,10 +30,12 @@
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIDocShellTreeOwner.h"
#include "nsIThreadRetargetableStreamListener.h"
#include "nsXPIDLString.h"
#include "nsString.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "nsReadableUtils.h"
#include "nsError.h"
@ -63,6 +65,7 @@ PRLogModuleInfo* nsURILoader::mLog = nullptr;
* (or aborted).
*/
class nsDocumentOpenInfo MOZ_FINAL : public nsIStreamListener
, public nsIThreadRetargetableStreamListener
{
public:
// Needed for nsCOMPtr to work right... Don't call this!
@ -110,6 +113,8 @@ public:
// nsIStreamListener methods:
NS_DECL_NSISTREAMLISTENER
// nsIThreadRetargetableStreamListener
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
protected:
~nsDocumentOpenInfo();
@ -159,6 +164,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocumentOpenInfo)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIRequestObserver)
NS_INTERFACE_MAP_ENTRY(nsIStreamListener)
NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableStreamListener)
NS_INTERFACE_MAP_END_THREADSAFE
nsDocumentOpenInfo::nsDocumentOpenInfo()
@ -266,6 +272,22 @@ NS_IMETHODIMP nsDocumentOpenInfo::OnStartRequest(nsIRequest *request, nsISupport
return rv;
}
NS_IMETHODIMP
nsDocumentOpenInfo::CheckListenerChain()
{
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread!");
nsresult rv = NS_OK;
nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
do_QueryInterface(m_targetStreamListener, &rv);
if (retargetableListener) {
rv = retargetableListener->CheckListenerChain();
}
LOG(("[0x%p] nsDocumentOpenInfo::CheckListenerChain %s listener %p rv %x",
this, (NS_SUCCEEDED(rv) ? "success" : "failure"),
(nsIStreamListener*)m_targetStreamListener, rv));
return rv;
}
NS_IMETHODIMP
nsDocumentOpenInfo::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
nsIInputStream * inStr,
@ -558,7 +580,7 @@ nsDocumentOpenInfo::ConvertData(nsIRequest *request,
// stream is split up into multiple destination streams. This
// intermediate instance is used to target these "decoded" streams...
//
nsCOMPtr<nsDocumentOpenInfo> nextLink =
nsRefPtr<nsDocumentOpenInfo> nextLink =
new nsDocumentOpenInfo(m_originalContext, mFlags, mURILoader);
if (!nextLink) return NS_ERROR_OUT_OF_MEMORY;
@ -812,7 +834,7 @@ nsresult nsURILoader::OpenChannel(nsIChannel* channel,
// we need to create a DocumentOpenInfo object which will go ahead and open
// the url and discover the content type....
nsCOMPtr<nsDocumentOpenInfo> loader =
nsRefPtr<nsDocumentOpenInfo> loader =
new nsDocumentOpenInfo(aWindowContext, aFlags, this);
if (!loader) return NS_ERROR_OUT_OF_MEMORY;

View File

@ -203,6 +203,8 @@ class nsMainThreadPtrHandle
operator T*() { return get(); }
T* operator->() { return get(); }
operator bool() { return get(); }
// These are safe to call on other threads with appropriate external locking.
bool operator==(const nsMainThreadPtrHandle<T>& aOther) const {
if (!mPtr || !aOther.mPtr)