Bug 330128. Calling cancel() on a timer doesn't drop ref to the callback. r=brendan, sr=bzbarsky, a=beltzner

This commit is contained in:
sayrer@gmail.com 2007-10-24 12:11:41 -07:00
parent 9198190926
commit c3df88ea3b
2 changed files with 33 additions and 7 deletions

View File

@ -285,6 +285,8 @@ NS_IMETHODIMP nsTimerImpl::Cancel()
if (gThread) if (gThread)
gThread->RemoveTimer(this); gThread->RemoveTimer(this);
ReleaseCallback();
return NS_OK; return NS_OK;
} }
@ -378,22 +380,45 @@ void nsTimerImpl::Fire()
gThread->UpdateFilter(mDelay, timeout, now); gThread->UpdateFilter(mDelay, timeout, now);
mFiring = PR_TRUE; 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);
else if (callbackType == CALLBACK_TYPE_OBSERVER)
NS_ADDREF(callback.o);
ReleaseCallback();
switch (mCallbackType) { switch (callbackType) {
case CALLBACK_TYPE_FUNC: case CALLBACK_TYPE_FUNC:
mCallback.c(this, mClosure); callback.c(this, mClosure);
break; break;
case CALLBACK_TYPE_INTERFACE: case CALLBACK_TYPE_INTERFACE:
mCallback.i->Notify(this); callback.i->Notify(this);
break; break;
case CALLBACK_TYPE_OBSERVER: case CALLBACK_TYPE_OBSERVER:
mCallback.o->Observe(static_cast<nsITimer*>(this), callback.o->Observe(static_cast<nsITimer*>(this),
NS_TIMER_CALLBACK_TOPIC, NS_TIMER_CALLBACK_TOPIC,
nsnull); nsnull);
break; break;
default:; default:;
} }
// If the callback didn't re-init the timer, and it's not a one-shot timer,
// restore the callback state.
if (mCallbackType == CALLBACK_TYPE_UNKNOWN && callbackType != TYPE_ONE_SHOT) {
mCallback = callback;
mCallbackType = callbackType;
} else {
// 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; mFiring = PR_FALSE;
#ifdef DEBUG_TIMERS #ifdef DEBUG_TIMERS

View File

@ -114,13 +114,14 @@ private:
NS_RELEASE(mCallback.i); NS_RELEASE(mCallback.i);
else if (mCallbackType == CALLBACK_TYPE_OBSERVER) else if (mCallbackType == CALLBACK_TYPE_OBSERVER)
NS_RELEASE(mCallback.o); NS_RELEASE(mCallback.o);
mCallbackType = CALLBACK_TYPE_UNKNOWN;
} }
nsCOMPtr<nsIThread> mCallingThread; nsCOMPtr<nsIThread> mCallingThread;
void * mClosure; void * mClosure;
union { union CallbackUnion {
nsTimerCallbackFunc c; nsTimerCallbackFunc c;
nsITimerCallback * i; nsITimerCallback * i;
nsIObserver * o; nsIObserver * o;