b=865241 make HRTFDatabaseLoader ref-counting thread-safe r=ehsan

--HG--
extra : rebase_source : 8cab96807c111eb103dbe931d14a86a8b97a824e
This commit is contained in:
Karl Tomlinson 2013-08-09 09:59:56 +12:00
parent b446dda0ec
commit 1a98f66b41
2 changed files with 79 additions and 5 deletions

View File

@ -65,7 +65,8 @@ TemporaryRef<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronously
}
HRTFDatabaseLoader::HRTFDatabaseLoader(float sampleRate)
: m_threadLock("HRTFDatabaseLoader")
: m_refCnt(0)
, m_threadLock("HRTFDatabaseLoader")
, m_databaseLoaderThread(nullptr)
, m_databaseSampleRate(sampleRate)
{
@ -87,6 +88,47 @@ HRTFDatabaseLoader::~HRTFDatabaseLoader()
}
}
class HRTFDatabaseLoader::ProxyReleaseEvent MOZ_FINAL : public nsRunnable {
public:
explicit ProxyReleaseEvent(HRTFDatabaseLoader* loader) : mLoader(loader) {}
NS_IMETHOD Run() MOZ_OVERRIDE
{
mLoader->MainThreadRelease();
return NS_OK;
}
private:
HRTFDatabaseLoader* mLoader;
};
void HRTFDatabaseLoader::ProxyRelease()
{
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
if (MOZ_LIKELY(mainThread)) {
nsRefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this);
DebugOnly<nsresult> rv =
mainThread->Dispatch(event, NS_DISPATCH_NORMAL);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch release event");
} else {
// Should be in XPCOM shutdown.
MOZ_ASSERT(NS_IsMainThread(),
"Main thread is not available for dispatch.");
MainThreadRelease();
}
}
void HRTFDatabaseLoader::MainThreadRelease()
{
MOZ_ASSERT(NS_IsMainThread());
int count = --m_refCnt;
MOZ_ASSERT(count >= 0, "extra release");
NS_LOG_RELEASE(this, count, "HRTFDatabaseLoader");
if (count == 0) {
// It is safe to delete here as the first reference can only be added
// on this (main) thread.
delete this;
}
}
// Asynchronously load the database in this thread.
static void databaseLoaderEntry(void* threadData)
{

View File

@ -39,7 +39,7 @@ namespace WebCore {
// HRTFDatabaseLoader will asynchronously load the default HRTFDatabase in a new thread.
class HRTFDatabaseLoader : public mozilla::RefCounted<HRTFDatabaseLoader> {
class HRTFDatabaseLoader {
public:
// Lazily creates a HRTFDatabaseLoader (if not already created) for the given sample-rate
// and starts loading asynchronously (when created the first time).
@ -47,9 +47,34 @@ public:
// Must be called from the main thread.
static mozilla::TemporaryRef<HRTFDatabaseLoader> createAndLoadAsynchronouslyIfNecessary(float sampleRate);
// Both constructor and destructor must be called from the main thread.
~HRTFDatabaseLoader();
// AddRef and Release may be called from any thread.
void AddRef()
{
#if defined(DEBUG) || defined(NS_BUILD_REFCNT_LOGGING)
int count =
#endif
++m_refCnt;
MOZ_ASSERT(count > 0, "invalid ref count");
NS_LOG_ADDREF(this, count, "HRTFDatabaseLoader", sizeof(*this));
}
void Release()
{
// The last reference can't be removed on a non-main thread because
// the object can be accessed on the main thread from the hash
// table via createAndLoadAsynchronouslyIfNecessary().
int count = m_refCnt;
MOZ_ASSERT(count > 0, "extra release");
// Optimization attempt to possibly skip proxying the release to the
// main thread.
if (count != 1 && m_refCnt.compareExchange(count, count - 1)) {
NS_LOG_RELEASE(this, count - 1, "HRTFDatabaseLoader");
return;
}
ProxyRelease();
}
// Returns true once the default database has been completely loaded.
bool isLoaded() const;
@ -67,7 +92,12 @@ public:
private:
// Both constructor and destructor must be called from the main thread.
explicit HRTFDatabaseLoader(float sampleRate);
~HRTFDatabaseLoader();
void ProxyRelease(); // any thread
void MainThreadRelease(); // main thread only
class ProxyReleaseEvent;
// If it hasn't already been loaded, creates a new thread and initiates asynchronous loading of the default database.
// This must be called from the main thread.
void loadAsynchronously();
@ -85,6 +115,8 @@ private:
// Keeps track of loaders on a per-sample-rate basis.
static nsTHashtable<LoaderByRateEntry> *s_loaderMap; // singleton
mozilla::Atomic<int> m_refCnt;
nsAutoRef<HRTFDatabase> m_hrtfDatabase;
// Holding a m_threadLock is required when accessing m_databaseLoaderThread.