Bug 393936 - Cancel() must not notify anything sync. Make removal from the loadgroup async, and add another call CancelAndForgetObserver() that removes the listener immediately (since some callsites expect that). r=bz, sr=pavlov, a=blocking1.9.1+

This commit is contained in:
Joe Drew 2008-11-07 14:35:22 -05:00
Родитель af447b1195
Коммит 16d0ef182e
8 изменённых файлов: 75 добавлений и 19 удалений

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

@ -121,11 +121,11 @@ nsImageLoadingContent::DestroyImageLoadingContent()
{ {
// Cancel our requests so they won't hold stale refs to us // Cancel our requests so they won't hold stale refs to us
if (mCurrentRequest) { if (mCurrentRequest) {
mCurrentRequest->Cancel(NS_ERROR_FAILURE); mCurrentRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mCurrentRequest = nsnull; mCurrentRequest = nsnull;
} }
if (mPendingRequest) { if (mPendingRequest) {
mPendingRequest->Cancel(NS_ERROR_FAILURE); mPendingRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mPendingRequest = nsnull; mPendingRequest = nsnull;
} }
} }

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

@ -74,7 +74,7 @@ nsImageLoader::~nsImageLoader()
mPresContext = nsnull; mPresContext = nsnull;
if (mRequest) { if (mRequest) {
mRequest->Cancel(NS_ERROR_FAILURE); mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
} }
} }
@ -95,7 +95,7 @@ nsImageLoader::Destroy()
mPresContext = nsnull; mPresContext = nsnull;
if (mRequest) { if (mRequest) {
mRequest->Cancel(NS_ERROR_FAILURE); mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
} }
mRequest = nsnull; mRequest = nsnull;
@ -122,7 +122,7 @@ nsImageLoader::Load(imgIRequest *aImage)
} }
// Now cancel the old request so it won't hold a stale ref to us. // Now cancel the old request so it won't hold a stale ref to us.
mRequest->Cancel(NS_ERROR_FAILURE); mRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
mRequest = nsnull; mRequest = nsnull;
} }

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

@ -307,11 +307,11 @@ private:
{ {
// in case the pref service releases us later // in case the pref service releases us later
if (mLoadingImage) { if (mLoadingImage) {
mLoadingImage->Cancel(NS_ERROR_FAILURE); mLoadingImage->CancelAndForgetObserver(NS_ERROR_FAILURE);
mLoadingImage = nsnull; mLoadingImage = nsnull;
} }
if (mBrokenImage) { if (mBrokenImage) {
mBrokenImage->Cancel(NS_ERROR_FAILURE); mBrokenImage->CancelAndForgetObserver(NS_ERROR_FAILURE);
mBrokenImage = nsnull; mBrokenImage = nsnull;
} }
} }

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

@ -207,7 +207,7 @@ nsImageBoxFrame::Destroy()
{ {
// Release image loader first so that it's refcnt can go to zero // Release image loader first so that it's refcnt can go to zero
if (mImageRequest) if (mImageRequest)
mImageRequest->Cancel(NS_ERROR_FAILURE); mImageRequest->CancelAndForgetObserver(NS_ERROR_FAILURE);
if (mListener) if (mListener)
reinterpret_cast<nsImageBoxListener*>(mListener.get())->SetFrame(nsnull); // set the frame to null so we don't send messages to a dead object. reinterpret_cast<nsImageBoxListener*>(mListener.get())->SetFrame(nsnull); // set the frame to null so we don't send messages to a dead object.

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

@ -104,5 +104,11 @@ interface imgIRequest : nsIRequest
* The principal gotten from the channel the image was loaded from. * The principal gotten from the channel the image was loaded from.
*/ */
readonly attribute nsIPrincipal imagePrincipal; readonly attribute nsIPrincipal imagePrincipal;
/**
* Cancels this request as in nsIRequest::Cancel(); further, also nulls out
* decoderObserver so it gets no further notifications from us.
*/
void cancelAndForgetObserver(in nsresult aStatus);
}; };

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

@ -197,6 +197,8 @@ NS_IMETHODIMP imgRequestProxy::IsPending(PRBool *_retval)
/* readonly attribute nsresult status; */ /* readonly attribute nsresult status; */
NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus) NS_IMETHODIMP imgRequestProxy::GetStatus(nsresult *aStatus)
{ {
// XXXbz this is wrong... Canceling with a status should make that
// status the status of the request, generally.
if (!mOwner) if (!mOwner)
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
@ -215,13 +217,18 @@ NS_IMETHODIMP imgRequestProxy::Cancel(nsresult status)
mCanceled = PR_TRUE; mCanceled = PR_TRUE;
nsCOMPtr<nsIRunnable> ev = new imgCancelRunnable(this, status);
return NS_DispatchToCurrentThread(ev);
}
void
imgRequestProxy::DoCancel(nsresult status)
{
// Passing false to aNotify means that mListener will still get // Passing false to aNotify means that mListener will still get
// OnStopRequest, if needed. // OnStopRequest, if needed.
mOwner->RemoveProxy(this, status, PR_FALSE); mOwner->RemoveProxy(this, status, PR_FALSE);
NullOutListener(); NullOutListener();
return NS_OK;
} }
/* void suspend (); */ /* void suspend (); */
@ -360,6 +367,21 @@ NS_IMETHODIMP imgRequestProxy::GetImagePrincipal(nsIPrincipal **aPrincipal)
return mOwner->GetPrincipal(aPrincipal); return mOwner->GetPrincipal(aPrincipal);
} }
/* void cancelAndForgetObserver (in nsresult aStatus); */
NS_IMETHODIMP imgRequestProxy::CancelAndForgetObserver(nsresult aStatus)
{
if (mCanceled || !mOwner)
return NS_ERROR_FAILURE;
LOG_SCOPE(gImgLog, "imgRequestProxy::CancelAndForgetObserver");
nsresult rv = Cancel(aStatus);
NullOutListener();
return rv;
}
/** nsISupportsPriority methods **/ /** nsISupportsPriority methods **/
NS_IMETHODIMP imgRequestProxy::GetPriority(PRInt32 *priority) NS_IMETHODIMP imgRequestProxy::GetPriority(PRInt32 *priority)
@ -400,7 +422,7 @@ void imgRequestProxy::FrameChanged(imgIContainer *container, gfxIImageFrame *new
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged"); LOG_FUNC(gImgLog, "imgRequestProxy::FrameChanged");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->FrameChanged(container, newframe, dirtyRect); mListener->FrameChanged(container, newframe, dirtyRect);
@ -413,7 +435,7 @@ void imgRequestProxy::OnStartDecode()
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStartDecode");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartDecode(this); mListener->OnStartDecode(this);
@ -424,7 +446,7 @@ void imgRequestProxy::OnStartContainer(imgIContainer *image)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStartContainer");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartContainer(this, image); mListener->OnStartContainer(this, image);
@ -435,7 +457,7 @@ void imgRequestProxy::OnStartFrame(gfxIImageFrame *frame)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStartFrame");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStartFrame(this, frame); mListener->OnStartFrame(this, frame);
@ -446,7 +468,7 @@ void imgRequestProxy::OnDataAvailable(gfxIImageFrame *frame, const nsIntRect * r
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable"); LOG_FUNC(gImgLog, "imgRequestProxy::OnDataAvailable");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnDataAvailable(this, frame, rect); mListener->OnDataAvailable(this, frame, rect);
@ -457,7 +479,7 @@ void imgRequestProxy::OnStopFrame(gfxIImageFrame *frame)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStopFrame");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStopFrame(this, frame); mListener->OnStopFrame(this, frame);
@ -468,7 +490,7 @@ void imgRequestProxy::OnStopContainer(imgIContainer *image)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopContainer"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStopContainer");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStopContainer(this, image); mListener->OnStopContainer(this, image);
@ -479,7 +501,7 @@ void imgRequestProxy::OnStopDecode(nsresult status, const PRUnichar *statusArg)
{ {
LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode"); LOG_FUNC(gImgLog, "imgRequestProxy::OnStopDecode");
if (mListener) { if (mListener && !mCanceled) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);
mListener->OnStopDecode(this, status, statusArg); mListener->OnStopDecode(this, status, statusArg);
@ -496,6 +518,8 @@ void imgRequestProxy::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get()); LOG_FUNC_WITH_PARAM(gImgLog, "imgRequestProxy::OnStartRequest", "name", name.get());
#endif #endif
// Notify even if mCanceled, since OnStartRequest is guaranteed by the
// nsIStreamListener contract so it makes sense to do the same here.
if (mListener) { if (mListener) {
// Hold a ref to the listener while we call it, just in case. // Hold a ref to the listener while we call it, just in case.
nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener); nsCOMPtr<imgIDecoderObserver> kungFuDeathGrip(mListener);

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

@ -49,6 +49,7 @@
#include "nsISupportsPriority.h" #include "nsISupportsPriority.h"
#include "nsCOMPtr.h" #include "nsCOMPtr.h"
#include "nsAutoPtr.h" #include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "imgRequest.h" #include "imgRequest.h"
@ -85,6 +86,28 @@ public:
protected: protected:
friend class imgRequest; friend class imgRequest;
class imgCancelRunnable;
friend class imgCancelRunnable;
class imgCancelRunnable : public nsRunnable
{
public:
imgCancelRunnable(imgRequestProxy* owner, nsresult status)
: mOwner(owner), mStatus(status)
{}
NS_IMETHOD Run() {
mOwner->DoCancel(mStatus);
return NS_OK;
}
private:
nsRefPtr<imgRequestProxy> mOwner;
nsresult mStatus;
};
/* non-virtual imgIDecoderObserver methods */ /* non-virtual imgIDecoderObserver methods */
void OnStartDecode (); void OnStartDecode ();
void OnStartContainer(imgIContainer *aContainer); void OnStartContainer(imgIContainer *aContainer);
@ -105,6 +128,9 @@ protected:
return mListener != nsnull; return mListener != nsnull;
} }
/* Finish up canceling ourselves */
void DoCancel(nsresult status);
/* Do the proper refcount management to null out mListener */ /* Do the proper refcount management to null out mListener */
void NullOutListener(); void NullOutListener();

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

@ -98,7 +98,7 @@ nsMenuItemIconX::nsMenuItemIconX(nsMenuObjectX* aMenuItem,
nsMenuItemIconX::~nsMenuItemIconX() nsMenuItemIconX::~nsMenuItemIconX()
{ {
if (mIconRequest) if (mIconRequest)
mIconRequest->Cancel(NS_BINDING_ABORTED); mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
} }