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.

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

mercurial