Bug 420521 - Leaking nsThread and nsTimerImpl running full set of Mochitests. This fixes the last refcounted leak on OS X Mochitests! Zounds! r=brendan, sr=dbaron, a=blocker

This commit is contained in:
jwalden@mit.edu 2008-03-10 14:05:46 -07:00
parent 85f2f1318d
commit 10d6312b8c
3 changed files with 33 additions and 10 deletions

View File

@ -277,7 +277,23 @@ NS_IMETHODIMP TimerThread::Run()
// We are going to let the call to PostTimerEvent here handle the
// release of the timer so that we don't end up releasing the timer
// on the TimerThread instead of on the thread it targets.
timer->PostTimerEvent();
if (NS_FAILED(timer->PostTimerEvent())) {
nsrefcnt rc;
NS_RELEASE2(timer, rc);
// The nsITimer interface requires that its users keep a reference
// to the timers they use while those timers are initialized but
// have not yet fired. If this ever happens, it is a bug in the
// code that created and used the timer.
//
// Further, note that this should never happen even with a
// misbehaving user, because nsTimerImpl::Release checks for a
// refcount of 1 with an armed timer (a timer whose only reference
// is from the timer thread) and when it hits this will remove the
// timer from the timer thread and thus destroy the last reference,
// preventing this situation from occurring.
NS_ASSERTION(rc != 0, "destroyed timer off its target thread!");
}
timer = nsnull;
lock.lock();
@ -329,7 +345,7 @@ nsresult TimerThread::AddTimer(nsTimerImpl *aTimer)
// Add the timer to our list.
PRInt32 i = AddTimerInternal(aTimer);
if (i < 0)
return NS_ERROR_FAILURE;
return NS_ERROR_OUT_OF_MEMORY;
// Awaken the timer thread.
if (mCondVar && mWaiting && i == 0)

View File

@ -450,6 +450,7 @@ public:
nsTimerEvent(nsTimerImpl *timer, PRInt32 generation)
: mTimer(timer), mGeneration(generation) {
// timer is already addref'd for us
MOZ_COUNT_CTOR(nsTimerEvent);
}
#ifdef DEBUG_TIMERS
@ -462,6 +463,7 @@ private:
if (mTimer)
NS_WARNING("leaking reference to nsTimerImpl");
#endif
MOZ_COUNT_DTOR(nsTimerEvent);
}
nsTimerImpl *mTimer;
@ -490,7 +492,7 @@ NS_IMETHODIMP nsTimerEvent::Run()
return NS_OK;
}
void nsTimerImpl::PostTimerEvent()
nsresult nsTimerImpl::PostTimerEvent()
{
// XXX we may want to reuse this nsTimerEvent in the case of repeating timers.
@ -499,9 +501,9 @@ void nsTimerImpl::PostTimerEvent()
// from this timer into the event, so we can avoid firing a timer that was
// re-initialized after being canceled.
nsTimerEvent* event = new nsTimerEvent(this, mGeneration);
nsRefPtr<nsTimerEvent> event = new nsTimerEvent(this, mGeneration);
if (!event)
return;
return NS_ERROR_OUT_OF_MEMORY;
#ifdef DEBUG_TIMERS
if (PR_LOG_TEST(gTimerLog, PR_LOG_DEBUG)) {
@ -513,11 +515,17 @@ void nsTimerImpl::PostTimerEvent()
// the next timer to fire before we make the callback.
if (mType == TYPE_REPEATING_PRECISE) {
SetDelayInternal(mDelay);
if (gThread)
gThread->AddTimer(this);
if (gThread) {
nsresult rv = gThread->AddTimer(this);
if (NS_FAILED(rv))
return rv;
}
}
mCallingThread->Dispatch(event, NS_DISPATCH_NORMAL);
nsresult rv = mCallingThread->Dispatch(event, NS_DISPATCH_NORMAL);
if (NS_FAILED(rv) && gThread)
gThread->RemoveTimer(this);
return rv;
}
void nsTimerImpl::SetDelayInternal(PRUint32 aDelay)

View File

@ -44,7 +44,6 @@
//#define FORCE_PR_LOG /* Allow logging in the release build */
#include "nsITimer.h"
#include "nsVoidArray.h"
#include "nsIThread.h"
#include "nsIObserver.h"
@ -96,7 +95,7 @@ public:
friend class TimerThread;
void Fire();
void PostTimerEvent();
nsresult PostTimerEvent();
void SetDelayInternal(PRUint32 aDelay);
NS_DECL_ISUPPORTS