Bug 401137. Silence ASSERTION: RefreshURIList timer callbacks should only be RefreshTimer objects. Docshell expects to be able to getCallback during a Timer fire. r=bzbarsky, sr=brendan, a=mconnor
authorsayrer@gmail.com
Tue, 30 Oct 2007 08:56:59 -0700
changeset 7246 d2bc9103b8ad4be78aa163994ed2562c916b41b0
parent 7245 06bbad4d68a6ec0f75468a146b9cb9bacd0fb812
child 7247 ac118989648679cf8925be03859e3563c0edeb8b
push idunknown
push userunknown
push dateunknown
reviewersbzbarsky, brendan, mconnor
bugs401137
milestone1.9a9pre
Bug 401137. Silence ASSERTION: RefreshURIList timer callbacks should only be RefreshTimer objects. Docshell expects to be able to getCallback during a Timer fire. r=bzbarsky, sr=brendan, a=mconnor
xpcom/threads/nsTimerImpl.cpp
xpcom/threads/nsTimerImpl.h
--- a/xpcom/threads/nsTimerImpl.cpp
+++ b/xpcom/threads/nsTimerImpl.cpp
@@ -333,16 +333,18 @@ NS_IMETHODIMP nsTimerImpl::GetClosure(vo
   return NS_OK;
 }
 
 
 NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback)
 {
   if (mCallbackType == CALLBACK_TYPE_INTERFACE)
     NS_IF_ADDREF(*aCallback = mCallback.i);
+  else if (mTimerCallbackWhileFiring)
+    NS_ADDREF(*aCallback = mTimerCallbackWhileFiring);
   else
     *aCallback = nsnull;
 
   return NS_OK;
 }
 
 
 void nsTimerImpl::Fire()
@@ -374,16 +376,18 @@ void nsTimerImpl::Fire()
   if (mType == TYPE_REPEATING_PRECISE) {
     // Precise repeating timers advance mTimeout by mDelay without fail before
     // calling Fire().
     timeout -= PR_MillisecondsToInterval(mDelay);
   }
   if (gThread)
     gThread->UpdateFilter(mDelay, timeout, now);
 
+  if (mCallbackType == CALLBACK_TYPE_INTERFACE)
+    mTimerCallbackWhileFiring = mCallback.i;
   mFiring = PR_TRUE;
   
   // Handle callbacks that re-init the timer, but avoid leaking.
   // See bug 330128.
   CallbackUnion callback = mCallback;
   PRUintn callbackType = mCallbackType;
   if (callbackType == CALLBACK_TYPE_INTERFACE)
     NS_ADDREF(callback.i);
@@ -415,16 +419,17 @@ void nsTimerImpl::Fire()
     // The timer was a one-shot, or the callback was reinitialized.
     if (callbackType == CALLBACK_TYPE_INTERFACE)
       NS_RELEASE(callback.i);
     else if (callbackType == CALLBACK_TYPE_OBSERVER)
       NS_RELEASE(callback.o);
   }
 
   mFiring = PR_FALSE;
+  mTimerCallbackWhileFiring = nsnull;
 
 #ifdef DEBUG_TIMERS
   if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
     PR_LOG(gTimerLog, PR_LOG_DEBUG,
            ("[this=%p] Took %dms to fire timer callback\n",
             this, PR_IntervalToMilliseconds(PR_IntervalNow() - now)));
   }
 #endif
--- a/xpcom/threads/nsTimerImpl.h
+++ b/xpcom/threads/nsTimerImpl.h
@@ -122,16 +122,20 @@ private:
   void *                mClosure;
 
   union CallbackUnion {
     nsTimerCallbackFunc c;
     nsITimerCallback *  i;
     nsIObserver *       o;
   } mCallback;
 
+  // Some callers expect to be able to access the callback while the
+  // timer is firing.
+  nsCOMPtr<nsITimerCallback> mTimerCallbackWhileFiring;
+
   // These members are set by Init (called from NS_NewTimer) and never reset.
   PRUint8               mCallbackType;
 
   // These members are set by the initiating thread, when the timer's type is
   // changed and during the period where it fires on that thread.
   PRUint8               mType;
   PRPackedBool          mFiring;