Bug 867755 - Dispatch imgRequestProxy notifications r=seth

This commit is contained in:
Steve Workman 2013-09-28 11:28:43 -07:00
parent 8bc9e8de94
commit a15a4e8e26
5 changed files with 145 additions and 4 deletions

View File

@ -93,12 +93,16 @@ Image::GetDecoderType(const char *aMimeType)
void
ImageResource::IncrementAnimationConsumers()
{
MOZ_ASSERT(NS_IsMainThread(), "Main thread only to encourage serialization "
"with DecrementAnimationConsumers");
mAnimationConsumers++;
}
void
ImageResource::DecrementAnimationConsumers()
{
MOZ_ASSERT(NS_IsMainThread(), "Main thread only to encourage serialization "
"with IncrementAnimationConsumers");
NS_ABORT_IF_FALSE(mAnimationConsumers >= 1, "Invalid no. of animation consumers!");
mAnimationConsumers--;
}

View File

@ -67,12 +67,16 @@ ImageWrapper::OutOfProcessSizeOfDecoded() const
void
ImageWrapper::IncrementAnimationConsumers()
{
MOZ_ASSERT(NS_IsMainThread(), "Main thread only to encourage serialization "
"with DecrementAnimationConsumers");
mInnerImage->IncrementAnimationConsumers();
}
void
ImageWrapper::DecrementAnimationConsumers()
{
MOZ_ASSERT(NS_IsMainThread(), "Main thread only to encourage serialization "
"with IncrementAnimationConsumers");
mInnerImage->DecrementAnimationConsumers();
}
@ -249,12 +253,16 @@ ImageWrapper::IsDecoded()
NS_IMETHODIMP
ImageWrapper::LockImage()
{
MOZ_ASSERT(NS_IsMainThread(),
"Main thread to encourage serialization with UnlockImage");
return mInnerImage->LockImage();
}
NS_IMETHODIMP
ImageWrapper::UnlockImage()
{
MOZ_ASSERT(NS_IsMainThread(),
"Main thread to encourage serialization with LockImage");
return mInnerImage->UnlockImage();
}

View File

@ -2673,6 +2673,8 @@ RasterImage::Draw(gfxContext *aContext,
NS_IMETHODIMP
RasterImage::LockImage()
{
MOZ_ASSERT(NS_IsMainThread(),
"Main thread to encourage serialization with UnlockImage");
if (mError)
return NS_ERROR_FAILURE;
@ -2690,6 +2692,8 @@ RasterImage::LockImage()
NS_IMETHODIMP
RasterImage::UnlockImage()
{
MOZ_ASSERT(NS_IsMainThread(),
"Main thread to encourage serialization with LockImage");
if (mError)
return NS_ERROR_FAILURE;

View File

@ -35,6 +35,8 @@ public:
virtual void OnStartDecode()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTrackerNotifyingObserver::OnStartDecode");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStartDecode callback before we've created our image");
@ -63,6 +65,8 @@ public:
virtual void OnStartContainer()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTrackerNotifyingObserver::OnStartContainer");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
@ -89,6 +93,8 @@ public:
virtual void FrameChanged(const nsIntRect* dirtyRect)
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTrackerNotifyingObserver::FrameChanged");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"FrameChanged callback before we've created our image");
@ -103,6 +109,8 @@ public:
virtual void OnStopFrame()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTrackerNotifyingObserver::OnStopFrame");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStopFrame callback before we've created our image");
@ -119,6 +127,8 @@ public:
virtual void OnStopDecode(nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTrackerNotifyingObserver::OnStopDecode");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnStopDecode callback before we've created our image");
@ -148,6 +158,8 @@ public:
virtual void OnDiscard()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnDiscard callback before we've created our image");
@ -161,6 +173,8 @@ public:
virtual void OnUnlockedDraw()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnUnlockedDraw callback before we've created our image");
mTracker->RecordUnlockedDraw();
@ -173,6 +187,8 @@ public:
virtual void OnImageIsAnimated()
{
MOZ_ASSERT(NS_IsMainThread(),
"Use imgStatusTracker::mConsumers on main thread only");
NS_ABORT_IF_FALSE(mTracker->GetImage(),
"OnImageIsAnimated callback before we've created our image");
mTracker->RecordImageIsAnimated();
@ -356,11 +372,16 @@ class imgRequestNotifyRunnable : public nsRunnable
imgRequestNotifyRunnable(imgStatusTracker* aTracker, imgRequestProxy* aRequestProxy)
: mTracker(aTracker)
{
MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
MOZ_ASSERT(aRequestProxy, "aRequestProxy should not be null");
MOZ_ASSERT(aTracker, "aTracker should not be null");
mProxies.AppendElement(aRequestProxy);
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
MOZ_ASSERT(mTracker, "mTracker should not be null");
for (uint32_t i = 0; i < mProxies.Length(); ++i) {
mProxies[i]->SetNotificationsDeferred(false);
mTracker->SyncNotify(mProxies[i]);
@ -390,6 +411,7 @@ class imgRequestNotifyRunnable : public nsRunnable
void
imgStatusTracker::Notify(imgRequestProxy* proxy)
{
MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe");
#ifdef PR_LOGGING
if (GetImage() && GetImage()->GetURI()) {
nsRefPtr<ImageURL> uri(GetImage()->GetURI());
@ -423,10 +445,15 @@ class imgStatusNotifyRunnable : public nsRunnable
imgStatusNotifyRunnable(imgStatusTracker& status,
imgRequestProxy* requestproxy)
: mStatus(status), mImage(status.mImage), mProxy(requestproxy)
{}
{
MOZ_ASSERT(NS_IsMainThread(), "Should be created on the main thread");
MOZ_ASSERT(requestproxy, "requestproxy cannot be null");
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
MOZ_ASSERT(mProxy, "mProxy cannot be null");
mProxy->SetNotificationsDeferred(false);
mStatus.SyncNotify(mProxy);
@ -444,6 +471,7 @@ class imgStatusNotifyRunnable : public nsRunnable
void
imgStatusTracker::NotifyCurrentState(imgRequestProxy* proxy)
{
MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe");
#ifdef PR_LOGGING
nsRefPtr<ImageURL> uri;
proxy->GetURI(getter_AddRefs(uri));
@ -475,6 +503,7 @@ imgStatusTracker::SyncNotifyState(nsTObserverArray<imgRequestProxy*>& proxies,
bool hasImage, uint32_t state,
nsIntRect& dirtyRect, bool hadLastPart)
{
MOZ_ASSERT(NS_IsMainThread());
// OnStartRequest
if (state & stateRequestStarted)
NOTIFY_IMAGE_OBSERVERS(OnStartRequest());
@ -598,6 +627,7 @@ imgStatusTracker::ApplyDifference(const ImageStatusDiff& aDiff)
void
imgStatusTracker::SyncNotifyDifference(const ImageStatusDiff& diff)
{
MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
LOG_SCOPE(GetImgLog(), "imgStatusTracker::SyncNotifyDifference");
nsIntRect invalidRect = mInvalidRect.Union(diff.invalidRect);
@ -632,6 +662,7 @@ imgStatusTracker::CloneForRecording()
void
imgStatusTracker::SyncNotify(imgRequestProxy* proxy)
{
MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe");
#ifdef PR_LOGGING
nsRefPtr<ImageURL> uri;
proxy->GetURI(getter_AddRefs(uri));
@ -656,6 +687,8 @@ void
imgStatusTracker::EmulateRequestFinished(imgRequestProxy* aProxy,
nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread(),
"SyncNotifyState and mConsumers are not threadsafe");
nsCOMPtr<imgIRequest> kungFuDeathGrip(aProxy);
// In certain cases the request might not have started yet.
@ -676,6 +709,7 @@ imgStatusTracker::EmulateRequestFinished(imgRequestProxy* aProxy,
void
imgStatusTracker::AddConsumer(imgRequestProxy* aConsumer)
{
MOZ_ASSERT(NS_IsMainThread());
mConsumers.AppendElementUnlessExists(aConsumer);
}
@ -683,6 +717,7 @@ imgStatusTracker::AddConsumer(imgRequestProxy* aConsumer)
bool
imgStatusTracker::RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread());
// Remove the proxy from the list.
bool removed = mConsumers.RemoveElement(aConsumer);
@ -739,6 +774,7 @@ imgStatusTracker::RecordStartDecode()
void
imgStatusTracker::SendStartDecode(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnStartDecode();
}
@ -757,6 +793,7 @@ imgStatusTracker::RecordStartContainer(imgIContainer* aContainer)
void
imgStatusTracker::SendStartContainer(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnStartContainer();
}
@ -780,6 +817,7 @@ imgStatusTracker::RecordStopFrame()
void
imgStatusTracker::SendStopFrame(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnStopFrame();
}
@ -805,6 +843,7 @@ void
imgStatusTracker::SendStopDecode(imgRequestProxy* aProxy,
nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnStopDecode();
}
@ -828,6 +867,7 @@ imgStatusTracker::RecordDiscard()
void
imgStatusTracker::SendDiscard(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnDiscard();
}
@ -851,6 +891,7 @@ imgStatusTracker::RecordImageIsAnimated()
void
imgStatusTracker::SendImageIsAnimated(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnImageIsAnimated();
}
@ -858,6 +899,7 @@ imgStatusTracker::SendImageIsAnimated(imgRequestProxy* aProxy)
void
imgStatusTracker::SendUnlockedDraw(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnUnlockedDraw();
}
@ -865,6 +907,7 @@ imgStatusTracker::SendUnlockedDraw(imgRequestProxy* aProxy)
void
imgStatusTracker::OnUnlockedDraw()
{
MOZ_ASSERT(NS_IsMainThread());
RecordUnlockedDraw();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
@ -884,6 +927,7 @@ void
imgStatusTracker::SendFrameChanged(imgRequestProxy* aProxy,
const nsIntRect* aDirtyRect)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnFrameUpdate(aDirtyRect);
}
@ -912,6 +956,7 @@ imgStatusTracker::RecordStartRequest()
void
imgStatusTracker::SendStartRequest(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred())
aProxy->OnStartRequest();
}
@ -919,6 +964,7 @@ imgStatusTracker::SendStartRequest(imgRequestProxy* aProxy)
void
imgStatusTracker::OnStartRequest()
{
MOZ_ASSERT(NS_IsMainThread());
RecordStartRequest();
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
@ -945,15 +991,48 @@ imgStatusTracker::SendStopRequest(imgRequestProxy* aProxy,
bool aLastPart,
nsresult aStatus)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred()) {
aProxy->OnStopRequest(aLastPart);
}
}
class OnStopRequestEvent : public nsRunnable
{
public:
OnStopRequestEvent(imgStatusTracker* aTracker,
bool aLastPart,
nsresult aStatus)
: mTracker(aTracker)
, mLastPart(aLastPart)
, mStatus(aStatus)
{
MOZ_ASSERT(!NS_IsMainThread(), "Should be created off the main thread");
MOZ_ASSERT(aTracker, "aTracker should not be null");
}
NS_IMETHOD Run()
{
MOZ_ASSERT(NS_IsMainThread(), "Should be running on the main thread");
MOZ_ASSERT(mTracker, "mTracker should not be null");
mTracker->OnStopRequest(mLastPart, mStatus);
return NS_OK;
}
private:
nsRefPtr<imgStatusTracker> mTracker;
bool mLastPart;
nsresult mStatus;
};
void
imgStatusTracker::OnStopRequest(bool aLastPart,
nsresult aStatus)
{
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(
new OnStopRequestEvent(this, aLastPart, aStatus));
return;
}
bool preexistingError = mImageStatus == imgIRequest::STATUS_ERROR;
RecordStopRequest(aLastPart, aStatus);
@ -971,6 +1050,7 @@ imgStatusTracker::OnStopRequest(bool aLastPart,
void
imgStatusTracker::OnDiscard()
{
MOZ_ASSERT(NS_IsMainThread());
RecordDiscard();
/* notify the kids */
@ -983,6 +1063,7 @@ imgStatusTracker::OnDiscard()
void
imgStatusTracker::FrameChanged(const nsIntRect* aDirtyRect)
{
MOZ_ASSERT(NS_IsMainThread());
RecordFrameChanged(aDirtyRect);
/* notify the kids */
@ -995,6 +1076,7 @@ imgStatusTracker::FrameChanged(const nsIntRect* aDirtyRect)
void
imgStatusTracker::OnStopFrame()
{
MOZ_ASSERT(NS_IsMainThread());
RecordStopFrame();
/* notify the kids */
@ -1007,6 +1089,14 @@ imgStatusTracker::OnStopFrame()
void
imgStatusTracker::OnDataAvailable()
{
if (!NS_IsMainThread()) {
// Note: SetHasImage calls Image::Lock and Image::IncrementAnimationCounter
// so subsequent calls or dispatches which Unlock or Decrement~ should
// be issued after this to avoid race conditions.
NS_DispatchToMainThread(
NS_NewRunnableMethod(this, &imgStatusTracker::OnDataAvailable));
return;
}
// Notify any imgRequestProxys that are observing us that we have an Image.
nsTObserverArray<imgRequestProxy*>::ForwardIterator iter(mConsumers);
while (iter.HasMore()) {
@ -1024,6 +1114,7 @@ imgStatusTracker::RecordBlockOnload()
void
imgStatusTracker::SendBlockOnload(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred()) {
aProxy->BlockOnload();
}
@ -1038,6 +1129,7 @@ imgStatusTracker::RecordUnblockOnload()
void
imgStatusTracker::SendUnblockOnload(imgRequestProxy* aProxy)
{
MOZ_ASSERT(NS_IsMainThread());
if (!aProxy->NotificationsDeferred()) {
aProxy->UnblockOnload();
}
@ -1046,6 +1138,11 @@ imgStatusTracker::SendUnblockOnload(imgRequestProxy* aProxy)
void
imgStatusTracker::MaybeUnblockOnload()
{
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(
NS_NewRunnableMethod(this, &imgStatusTracker::MaybeUnblockOnload));
return;
}
if (!(mState & stateBlockingOnload)) {
return;
}

View File

@ -19,6 +19,7 @@ class nsIRunnable;
#include "mozilla/RefPtr.h"
#include "nsCOMPtr.h"
#include "nsTObserverArray.h"
#include "nsThreadUtils.h"
#include "nsRect.h"
namespace mozilla {
@ -129,6 +130,8 @@ public:
// We will also take note of any notifications that happen between the time
// Notify() is called and when we call SyncNotify on |proxy|, and replay them
// as well.
// Should be called on the main thread only, since imgRequestProxy and GetURI
// are not threadsafe.
void Notify(imgRequestProxy* proxy);
// Schedule an asynchronous "replaying" of all the notifications that would
@ -136,12 +139,16 @@ public:
// Unlike Notify(), does *not* take into account future notifications.
// This is only useful if you do not have an imgRequest, e.g., if you are a
// static request returned from imgIRequest::GetStaticRequest().
// Should be called on the main thread only, since imgRequestProxy and GetURI
// are not threadsafe.
void NotifyCurrentState(imgRequestProxy* proxy);
// "Replay" all of the notifications that would have to happen to put us in
// the state we're currently in.
// Only use this if you're already servicing an asynchronous call (e.g.
// OnStartRequest).
// Should be called on the main thread only, since imgRequestProxy and GetURI
// are not threadsafe.
void SyncNotify(imgRequestProxy* proxy);
// Send some notifications that would be necessary to make |proxy| believe
@ -153,16 +160,23 @@ public:
// with its status. Weak pointers.
void AddConsumer(imgRequestProxy* aConsumer);
bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus);
size_t ConsumerCount() const { return mConsumers.Length(); }
size_t ConsumerCount() const {
MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
return mConsumers.Length();
}
// This is intentionally non-general because its sole purpose is to support an
// some obscure network priority logic in imgRequest. That stuff could probably
// be improved, but it's too scary to mess with at the moment.
bool FirstConsumerIs(imgRequestProxy* aConsumer) {
MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
return mConsumers.SafeElementAt(0, nullptr) == aConsumer;
}
void AdoptConsumers(imgStatusTracker* aTracker) { mConsumers = aTracker->mConsumers; }
void AdoptConsumers(imgStatusTracker* aTracker) {
MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only");
mConsumers = aTracker->mConsumers;
}
// Returns whether we are in the process of loading; that is, whether we have
// not received OnStopRequest.
@ -187,6 +201,8 @@ public:
void RecordDecoded();
/* non-virtual imgDecoderObserver methods */
// Functions with prefix Send- are main thread only, since they contain calls
// to imgRequestProxy functions, which are expected on the main thread.
void RecordStartDecode();
void SendStartDecode(imgRequestProxy* aProxy);
void RecordStartContainer(imgIContainer* aContainer);
@ -207,12 +223,18 @@ public:
void SendImageIsAnimated(imgRequestProxy *aProxy);
/* non-virtual sort-of-nsIRequestObserver methods */
// Functions with prefix Send- are main thread only, since they contain calls
// to imgRequestProxy functions, which are expected on the main thread.
void RecordStartRequest();
void SendStartRequest(imgRequestProxy* aProxy);
void RecordStopRequest(bool aLastPart, nsresult aStatus);
void SendStopRequest(imgRequestProxy* aProxy, bool aLastPart, nsresult aStatus);
// All main thread only because they call functions (like SendStartRequest)
// which are expected to be called on the main thread.
void OnStartRequest();
// OnDataAvailable will dispatch a call to itself onto the main thread if not
// called there.
void OnDataAvailable();
void OnStopRequest(bool aLastPart, nsresult aStatus);
void OnDiscard();
@ -231,6 +253,7 @@ public:
void RecordUnblockOnload();
void SendUnblockOnload(imgRequestProxy* aProxy);
// Main thread only because mConsumers is not threadsafe.
void MaybeUnblockOnload();
void RecordError();
@ -256,6 +279,7 @@ public:
// Notify for the changes captured in an ImageStatusDiff. Because this may
// result in recursive notifications, no decoding locks may be held.
// Called on the main thread only.
void SyncNotifyDifference(const mozilla::image::ImageStatusDiff& aDiff);
nsIntRect GetInvalidRect() const { return mInvalidRect; }
@ -267,8 +291,11 @@ private:
friend class imgStatusTrackerNotifyingObserver;
imgStatusTracker(const imgStatusTracker& aOther);
// Main thread only because it deals with the observer service.
void FireFailureNotification();
// Main thread only, since imgRequestProxy calls are expected on the main
// thread, and mConsumers is not threadsafe.
static void SyncNotifyState(nsTObserverArray<imgRequestProxy*>& proxies,
bool hasImage, uint32_t state,
nsIntRect& dirtyRect, bool hadLastPart);
@ -283,7 +310,8 @@ private:
mozilla::image::Image* mImage;
// List of proxies attached to the image. Each proxy represents a consumer
// using the image.
// using the image. Array and/or individual elements should only be accessed
// on the main thread.
nsTObserverArray<imgRequestProxy*> mConsumers;
mozilla::RefPtr<imgDecoderObserver> mTrackerObserver;