Bug 801304 Part 2 - Check if event queues should be suspended before processing their events, r=mayhemer,smaug.

--HG--
extra : rebase_source : e1828ffdaaaa7ab48f956c22a93109f80a765d43
This commit is contained in:
Brian Hackett 2018-12-14 06:47:58 -10:00
parent d0f7b1b700
commit a655254f45
2 changed files with 67 additions and 3 deletions

View File

@ -9,7 +9,8 @@
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "mozilla/Unused.h" #include "mozilla/Unused.h"
#include "nsISupports.h" #include "nsIChannel.h"
#include "nsIDocument.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
namespace mozilla { namespace mozilla {
@ -167,5 +168,57 @@ void ChannelEventQueue::ResumeInternal() {
} }
} }
bool
ChannelEventQueue::MaybeSuspendIfEventsAreSuppressed() {
// We only ever need to suppress events on the main thread, since this is
// where content scripts can run.
if (!NS_IsMainThread()) {
return false;
}
// Only suppress events for queues associated with XHRs, as these can cause
// content scripts to run.
if (mHasCheckedForXMLHttpRequest && !mForXMLHttpRequest) {
return false;
}
nsCOMPtr<nsIChannel> channel(do_QueryInterface(mOwner));
if (!channel) {
return false;
}
nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
if (!loadInfo) {
return false;
}
// Figure out if this is for an XHR, if we haven't done so already.
if (!mHasCheckedForXMLHttpRequest) {
nsContentPolicyType contentType = loadInfo->InternalContentPolicyType();
mForXMLHttpRequest =
(contentType == nsIContentPolicy::TYPE_INTERNAL_XMLHTTPREQUEST);
mHasCheckedForXMLHttpRequest = true;
if (!mForXMLHttpRequest) {
return false;
}
}
// Suspend the queue if the associated document has suppressed event handling,
// *and* it is not in the middle of a synchronous operation that might require
// XHR events to be processed (such as a synchronous XHR).
nsCOMPtr<nsIDocument> document;
loadInfo->GetLoadingDocument(getter_AddRefs(document));
if (document &&
document->EventHandlingSuppressed() &&
!document->IsInSyncOperation()) {
document->AddSuspendedChannelEventQueue(this);
SuspendInternal();
return true;
}
return false;
}
} // namespace net } // namespace net
} // namespace mozilla } // namespace mozilla

View File

@ -86,6 +86,8 @@ class ChannelEventQueue final {
mSuspended(false), mSuspended(false),
mForcedCount(0), mForcedCount(0),
mFlushing(false), mFlushing(false),
mHasCheckedForXMLHttpRequest(false),
mForXMLHttpRequest(false),
mOwner(owner), mOwner(owner),
mMutex("ChannelEventQueue::mMutex"), mMutex("ChannelEventQueue::mMutex"),
mRunningMutex("ChannelEventQueue::mRunningMutex") {} mRunningMutex("ChannelEventQueue::mRunningMutex") {}
@ -126,6 +128,8 @@ class ChannelEventQueue final {
void SuspendInternal(); void SuspendInternal();
void ResumeInternal(); void ResumeInternal();
bool MaybeSuspendIfEventsAreSuppressed();
inline void MaybeFlushQueue(); inline void MaybeFlushQueue();
void FlushQueue(); void FlushQueue();
inline void CompleteResume(); inline void CompleteResume();
@ -139,6 +143,11 @@ class ChannelEventQueue final {
uint32_t mForcedCount; // Support ForcedQueueing on multiple thread. uint32_t mForcedCount; // Support ForcedQueueing on multiple thread.
bool mFlushing; bool mFlushing;
// Whether the queue is associated with an XHR. This is lazily instantiated
// the first time it is needed.
bool mHasCheckedForXMLHttpRequest;
bool mForXMLHttpRequest;
// Keep ptr to avoid refcount cycle: only grab ref during flushing. // Keep ptr to avoid refcount cycle: only grab ref during flushing.
nsISupports* mOwner; nsISupports* mOwner;
@ -172,7 +181,8 @@ inline void ChannelEventQueue::RunOrEnqueue(ChannelEvent* aCallback,
MutexAutoLock lock(mMutex); MutexAutoLock lock(mMutex);
bool enqueue = bool enqueue =
!!mForcedCount || mSuspended || mFlushing || !mEventQueue.IsEmpty(); !!mForcedCount || mSuspended || mFlushing || !mEventQueue.IsEmpty() ||
MaybeSuspendIfEventsAreSuppressed();
if (enqueue) { if (enqueue) {
mEventQueue.AppendElement(std::move(event)); mEventQueue.AppendElement(std::move(event));
@ -292,7 +302,8 @@ inline void ChannelEventQueue::MaybeFlushQueue() {
{ {
MutexAutoLock lock(mMutex); MutexAutoLock lock(mMutex);
flushQueue = flushQueue =
!mForcedCount && !mFlushing && !mSuspended && !mEventQueue.IsEmpty(); !mForcedCount && !mFlushing && !mSuspended && !mEventQueue.IsEmpty() &&
!MaybeSuspendIfEventsAreSuppressed();
// Only one thread is allowed to run FlushQueue at a time. // Only one thread is allowed to run FlushQueue at a time.
if (flushQueue) { if (flushQueue) {