content/media/webaudio/blink/HRTFDatabaseLoader.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /*
michael@0 2 * Copyright (C) 2010 Google Inc. All rights reserved.
michael@0 3 *
michael@0 4 * Redistribution and use in source and binary forms, with or without
michael@0 5 * modification, are permitted provided that the following conditions
michael@0 6 * are met:
michael@0 7 *
michael@0 8 * 1. Redistributions of source code must retain the above copyright
michael@0 9 * notice, this list of conditions and the following disclaimer.
michael@0 10 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 11 * notice, this list of conditions and the following disclaimer in the
michael@0 12 * documentation and/or other materials provided with the distribution.
michael@0 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
michael@0 14 * its contributors may be used to endorse or promote products derived
michael@0 15 * from this software without specific prior written permission.
michael@0 16 *
michael@0 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
michael@0 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
michael@0 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
michael@0 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
michael@0 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
michael@0 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
michael@0 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
michael@0 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
michael@0 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 27 */
michael@0 28
michael@0 29 #include "HRTFDatabaseLoader.h"
michael@0 30 #include "HRTFDatabase.h"
michael@0 31
michael@0 32 using namespace mozilla;
michael@0 33
michael@0 34 namespace WebCore {
michael@0 35
michael@0 36 // Singleton
michael@0 37 nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
michael@0 38 HRTFDatabaseLoader::s_loaderMap = nullptr;
michael@0 39
michael@0 40 TemporaryRef<HRTFDatabaseLoader> HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(float sampleRate)
michael@0 41 {
michael@0 42 MOZ_ASSERT(NS_IsMainThread());
michael@0 43
michael@0 44 RefPtr<HRTFDatabaseLoader> loader;
michael@0 45
michael@0 46 if (!s_loaderMap) {
michael@0 47 s_loaderMap = new nsTHashtable<LoaderByRateEntry>();
michael@0 48 }
michael@0 49
michael@0 50 LoaderByRateEntry* entry = s_loaderMap->PutEntry(sampleRate);
michael@0 51 loader = entry->mLoader;
michael@0 52 if (loader) { // existing entry
michael@0 53 MOZ_ASSERT(sampleRate == loader->databaseSampleRate());
michael@0 54 return loader;
michael@0 55 }
michael@0 56
michael@0 57 loader = new HRTFDatabaseLoader(sampleRate);
michael@0 58 entry->mLoader = loader;
michael@0 59
michael@0 60 loader->loadAsynchronously();
michael@0 61
michael@0 62 return loader;
michael@0 63 }
michael@0 64
michael@0 65 HRTFDatabaseLoader::HRTFDatabaseLoader(float sampleRate)
michael@0 66 : m_refCnt(0)
michael@0 67 , m_threadLock("HRTFDatabaseLoader")
michael@0 68 , m_databaseLoaderThread(nullptr)
michael@0 69 , m_databaseSampleRate(sampleRate)
michael@0 70 {
michael@0 71 MOZ_ASSERT(NS_IsMainThread());
michael@0 72 }
michael@0 73
michael@0 74 HRTFDatabaseLoader::~HRTFDatabaseLoader()
michael@0 75 {
michael@0 76 MOZ_ASSERT(NS_IsMainThread());
michael@0 77
michael@0 78 waitForLoaderThreadCompletion();
michael@0 79 m_hrtfDatabase.reset();
michael@0 80
michael@0 81 if (s_loaderMap) {
michael@0 82 // Remove ourself from the map.
michael@0 83 s_loaderMap->RemoveEntry(m_databaseSampleRate);
michael@0 84 if (s_loaderMap->Count() == 0) {
michael@0 85 delete s_loaderMap;
michael@0 86 s_loaderMap = nullptr;
michael@0 87 }
michael@0 88 }
michael@0 89 }
michael@0 90
michael@0 91 size_t HRTFDatabaseLoader::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
michael@0 92 {
michael@0 93 size_t amount = aMallocSizeOf(this);
michael@0 94
michael@0 95 // NB: Need to make sure we're not competing with the loader thread.
michael@0 96 const_cast<HRTFDatabaseLoader*>(this)->waitForLoaderThreadCompletion();
michael@0 97
michael@0 98 if (m_hrtfDatabase) {
michael@0 99 amount += m_hrtfDatabase->sizeOfIncludingThis(aMallocSizeOf);
michael@0 100 }
michael@0 101
michael@0 102 return amount;
michael@0 103 }
michael@0 104
michael@0 105 class HRTFDatabaseLoader::ProxyReleaseEvent MOZ_FINAL : public nsRunnable {
michael@0 106 public:
michael@0 107 explicit ProxyReleaseEvent(HRTFDatabaseLoader* loader) : mLoader(loader) {}
michael@0 108 NS_IMETHOD Run() MOZ_OVERRIDE
michael@0 109 {
michael@0 110 mLoader->MainThreadRelease();
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113 private:
michael@0 114 HRTFDatabaseLoader* mLoader;
michael@0 115 };
michael@0 116
michael@0 117 void HRTFDatabaseLoader::ProxyRelease()
michael@0 118 {
michael@0 119 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
michael@0 120 if (MOZ_LIKELY(mainThread)) {
michael@0 121 nsRefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this);
michael@0 122 DebugOnly<nsresult> rv =
michael@0 123 mainThread->Dispatch(event, NS_DISPATCH_NORMAL);
michael@0 124 MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch release event");
michael@0 125 } else {
michael@0 126 // Should be in XPCOM shutdown.
michael@0 127 MOZ_ASSERT(NS_IsMainThread(),
michael@0 128 "Main thread is not available for dispatch.");
michael@0 129 MainThreadRelease();
michael@0 130 }
michael@0 131 }
michael@0 132
michael@0 133 void HRTFDatabaseLoader::MainThreadRelease()
michael@0 134 {
michael@0 135 MOZ_ASSERT(NS_IsMainThread());
michael@0 136 int count = --m_refCnt;
michael@0 137 MOZ_ASSERT(count >= 0, "extra release");
michael@0 138 NS_LOG_RELEASE(this, count, "HRTFDatabaseLoader");
michael@0 139 if (count == 0) {
michael@0 140 // It is safe to delete here as the first reference can only be added
michael@0 141 // on this (main) thread.
michael@0 142 delete this;
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 // Asynchronously load the database in this thread.
michael@0 147 static void databaseLoaderEntry(void* threadData)
michael@0 148 {
michael@0 149 PR_SetCurrentThreadName("HRTFDatabaseLdr");
michael@0 150
michael@0 151 HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
michael@0 152 MOZ_ASSERT(loader);
michael@0 153 loader->load();
michael@0 154 }
michael@0 155
michael@0 156 void HRTFDatabaseLoader::load()
michael@0 157 {
michael@0 158 MOZ_ASSERT(!NS_IsMainThread());
michael@0 159 MOZ_ASSERT(!m_hrtfDatabase.get(), "Called twice");
michael@0 160 // Load the default HRTF database.
michael@0 161 m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate);
michael@0 162 // Notifies the main thread of completion. See loadAsynchronously().
michael@0 163 Release();
michael@0 164 }
michael@0 165
michael@0 166 void HRTFDatabaseLoader::loadAsynchronously()
michael@0 167 {
michael@0 168 MOZ_ASSERT(NS_IsMainThread());
michael@0 169 MOZ_ASSERT(m_refCnt, "Must not be called before a reference is added");
michael@0 170
michael@0 171 // Add a reference so that the destructor won't run and wait for the
michael@0 172 // loader thread, until load() has completed.
michael@0 173 AddRef();
michael@0 174
michael@0 175 MutexAutoLock locker(m_threadLock);
michael@0 176
michael@0 177 MOZ_ASSERT(!m_hrtfDatabase.get() && !m_databaseLoaderThread,
michael@0 178 "Called twice");
michael@0 179 // Start the asynchronous database loading process.
michael@0 180 m_databaseLoaderThread =
michael@0 181 PR_CreateThread(PR_USER_THREAD, databaseLoaderEntry, this,
michael@0 182 PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
michael@0 183 PR_JOINABLE_THREAD, 0);
michael@0 184 }
michael@0 185
michael@0 186 bool HRTFDatabaseLoader::isLoaded() const
michael@0 187 {
michael@0 188 return m_hrtfDatabase.get();
michael@0 189 }
michael@0 190
michael@0 191 void HRTFDatabaseLoader::waitForLoaderThreadCompletion()
michael@0 192 {
michael@0 193 MutexAutoLock locker(m_threadLock);
michael@0 194
michael@0 195 // waitForThreadCompletion() should not be called twice for the same thread.
michael@0 196 if (m_databaseLoaderThread) {
michael@0 197 DebugOnly<PRStatus> status = PR_JoinThread(m_databaseLoaderThread);
michael@0 198 MOZ_ASSERT(status == PR_SUCCESS, "PR_JoinThread failed");
michael@0 199 }
michael@0 200 m_databaseLoaderThread = nullptr;
michael@0 201 }
michael@0 202
michael@0 203 PLDHashOperator
michael@0 204 HRTFDatabaseLoader::shutdownEnumFunc(LoaderByRateEntry *entry, void* unused)
michael@0 205 {
michael@0 206 // Ensure the loader thread's reference is removed for leak analysis.
michael@0 207 entry->mLoader->waitForLoaderThreadCompletion();
michael@0 208 return PLDHashOperator::PL_DHASH_NEXT;
michael@0 209 }
michael@0 210
michael@0 211 void HRTFDatabaseLoader::shutdown()
michael@0 212 {
michael@0 213 MOZ_ASSERT(NS_IsMainThread());
michael@0 214 if (s_loaderMap) {
michael@0 215 // Set s_loaderMap to nullptr so that the hashtable is not modified on
michael@0 216 // reference release during enumeration.
michael@0 217 nsTHashtable<LoaderByRateEntry>* loaderMap = s_loaderMap;
michael@0 218 s_loaderMap = nullptr;
michael@0 219 loaderMap->EnumerateEntries(shutdownEnumFunc, nullptr);
michael@0 220 delete loaderMap;
michael@0 221 }
michael@0 222 }
michael@0 223 } // namespace WebCore

mercurial