diff --git a/content/media/webaudio/blink/HRTFDatabaseLoader.cpp b/content/media/webaudio/blink/HRTFDatabaseLoader.cpp index e2ebdd85c135..c7205305cd80 100644 --- a/content/media/webaudio/blink/HRTFDatabaseLoader.cpp +++ b/content/media/webaudio/blink/HRTFDatabaseLoader.cpp @@ -65,7 +65,8 @@ TemporaryRef 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 mainThread = do_GetMainThread(); + if (MOZ_LIKELY(mainThread)) { + nsRefPtr event = new ProxyReleaseEvent(this); + DebugOnly 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) { diff --git a/content/media/webaudio/blink/HRTFDatabaseLoader.h b/content/media/webaudio/blink/HRTFDatabaseLoader.h index f03a25333576..e0b38e0c4f0c 100644 --- a/content/media/webaudio/blink/HRTFDatabaseLoader.h +++ b/content/media/webaudio/blink/HRTFDatabaseLoader.h @@ -39,7 +39,7 @@ namespace WebCore { // HRTFDatabaseLoader will asynchronously load the default HRTFDatabase in a new thread. -class HRTFDatabaseLoader : public mozilla::RefCounted { +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 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 *s_loaderMap; // singleton + mozilla::Atomic m_refCnt; + nsAutoRef m_hrtfDatabase; // Holding a m_threadLock is required when accessing m_databaseLoaderThread.