Bug 799142 - Make sure that the allocator for nsTimerEvent objects stays around long enough to deallocate all outstanding objects of that type; r=bsmedberg

This commit is contained in:
Ehsan Akhgari 2013-03-04 19:04:59 -05:00
parent 8631e44d32
commit 615bf8538f
2 changed files with 32 additions and 2 deletions

View File

@ -11,6 +11,7 @@
#include "nsIThread.h"
#include "nsTimerImpl.h"
#include "nsThreadUtils.h"
#include "nsTArray.h"
@ -49,6 +50,11 @@ public:
void DoBeforeSleep();
void DoAfterSleep();
bool IsOnTimerThread() const
{
return mThread == NS_GetCurrentThread();
}
private:
~TimerThread();

View File

@ -96,6 +96,11 @@ public:
: mTimer(timer), mGeneration(generation) {
// timer is already addref'd for us
MOZ_COUNT_CTOR(nsTimerEvent);
MOZ_ASSERT(gThread->IsOnTimerThread(),
"nsTimer must always be allocated on the timer thread");
PR_ATOMIC_INCREMENT(&sAllocatorUsers);
}
#ifdef DEBUG_TIMERS
@ -104,30 +109,41 @@ public:
static void Init();
static void Shutdown();
static void DeleteAllocatorIfNeeded();
static void* operator new(size_t size) CPP_THROW_NEW {
return sAllocator->Alloc(size);
}
void operator delete(void* p) {
sAllocator->Free(p, sizeof(nsTimerEvent));
DeleteAllocatorIfNeeded();
}
private:
nsTimerEvent(); // Not implemented
~nsTimerEvent() {
#ifdef DEBUG
if (mTimer)
NS_WARNING("leaking reference to nsTimerImpl");
#endif
MOZ_COUNT_DTOR(nsTimerEvent);
MOZ_ASSERT(!sCanDeleteAllocator || sAllocatorUsers > 0,
"This will result in us attempting to deallocate the nsTimerEvent allocator twice");
PR_ATOMIC_DECREMENT(&sAllocatorUsers);
}
nsTimerImpl *mTimer;
int32_t mGeneration;
static TimerEventAllocator* sAllocator;
static int32_t sAllocatorUsers;
static bool sCanDeleteAllocator;
};
TimerEventAllocator* nsTimerEvent::sAllocator = nullptr;
int32_t nsTimerEvent::sAllocatorUsers = 0;
bool nsTimerEvent::sCanDeleteAllocator = false;
NS_IMPL_THREADSAFE_QUERY_INTERFACE1(nsTimerImpl, nsITimer)
NS_IMPL_THREADSAFE_ADDREF(nsTimerImpl)
@ -541,8 +557,16 @@ void nsTimerEvent::Init()
void nsTimerEvent::Shutdown()
{
delete sAllocator;
sAllocator = nullptr;
sCanDeleteAllocator = true;
DeleteAllocatorIfNeeded();
}
void nsTimerEvent::DeleteAllocatorIfNeeded()
{
if (sCanDeleteAllocator && sAllocatorUsers == 0) {
delete sAllocator;
sAllocator = nullptr;
}
}
NS_IMETHODIMP nsTimerEvent::Run()