tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HRTFDatabaseLoader.cpp (7197B)


      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 */
     28 
     29 #include "HRTFDatabaseLoader.h"
     30 
     31 #include "GeckoProfiler.h"
     32 #include "HRTFDatabase.h"
     33 #include "nsThreadUtils.h"
     34 
     35 using namespace mozilla;
     36 
     37 namespace WebCore {
     38 
     39 // Singleton
     40 nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
     41    HRTFDatabaseLoader::s_loaderMap = nullptr;
     42 
     43 size_t HRTFDatabaseLoader::sizeOfLoaders(mozilla::MallocSizeOf aMallocSizeOf) {
     44  return s_loaderMap ? s_loaderMap->SizeOfIncludingThis(aMallocSizeOf) : 0;
     45 }
     46 
     47 already_AddRefed<HRTFDatabaseLoader>
     48 HRTFDatabaseLoader::createAndLoadAsynchronouslyIfNecessary(float sampleRate) {
     49  MOZ_ASSERT(NS_IsMainThread());
     50 
     51  RefPtr<HRTFDatabaseLoader> loader;
     52 
     53  if (!s_loaderMap) {
     54    s_loaderMap = new nsTHashtable<LoaderByRateEntry>();
     55  }
     56 
     57  LoaderByRateEntry* entry = s_loaderMap->PutEntry(sampleRate);
     58  loader = entry->mLoader;
     59  if (loader) {  // existing entry
     60    MOZ_ASSERT(sampleRate == loader->databaseSampleRate());
     61    return loader.forget();
     62  }
     63 
     64  loader = new HRTFDatabaseLoader(sampleRate);
     65  entry->mLoader = loader;
     66 
     67  loader->loadAsynchronously();
     68 
     69  return loader.forget();
     70 }
     71 
     72 HRTFDatabaseLoader::HRTFDatabaseLoader(float sampleRate)
     73    : m_refCnt(0),
     74      m_threadLock("HRTFDatabaseLoader"),
     75      m_databaseLoaderThread(nullptr),
     76      m_databaseSampleRate(sampleRate),
     77      m_databaseLoaded(false) {
     78  MOZ_ASSERT(NS_IsMainThread());
     79 }
     80 
     81 HRTFDatabaseLoader::~HRTFDatabaseLoader() {
     82  MOZ_ASSERT(NS_IsMainThread());
     83 
     84  waitForLoaderThreadCompletion();
     85  m_hrtfDatabase.reset();
     86 
     87  if (s_loaderMap) {
     88    // Remove ourself from the map.
     89    s_loaderMap->RemoveEntry(m_databaseSampleRate);
     90    if (s_loaderMap->Count() == 0) {
     91      delete s_loaderMap;
     92      s_loaderMap = nullptr;
     93    }
     94  }
     95 }
     96 
     97 size_t HRTFDatabaseLoader::sizeOfIncludingThis(
     98    mozilla::MallocSizeOf aMallocSizeOf) const {
     99  size_t amount = aMallocSizeOf(this);
    100 
    101  // NB: Need to make sure we're not competing with the loader thread.
    102  const_cast<HRTFDatabaseLoader*>(this)->waitForLoaderThreadCompletion();
    103 
    104  if (m_hrtfDatabase) {
    105    amount += m_hrtfDatabase->sizeOfIncludingThis(aMallocSizeOf);
    106  }
    107 
    108  return amount;
    109 }
    110 
    111 class HRTFDatabaseLoader::ProxyReleaseEvent final : public Runnable {
    112 public:
    113  explicit ProxyReleaseEvent(HRTFDatabaseLoader* loader)
    114      : mozilla::Runnable("WebCore::HRTFDatabaseLoader::ProxyReleaseEvent"),
    115        mLoader(loader) {}
    116  NS_IMETHOD Run() override {
    117    mLoader->MainThreadRelease();
    118    return NS_OK;
    119  }
    120 
    121 private:
    122  // Ownership transferred by ProxyRelease
    123  HRTFDatabaseLoader* MOZ_OWNING_REF mLoader;
    124 };
    125 
    126 void HRTFDatabaseLoader::ProxyRelease() {
    127  nsCOMPtr<nsIEventTarget> mainTarget = GetMainThreadSerialEventTarget();
    128  if (MOZ_LIKELY(mainTarget)) {
    129    RefPtr<ProxyReleaseEvent> event = new ProxyReleaseEvent(this);
    130    DebugOnly<nsresult> rv = mainTarget->Dispatch(event, NS_DISPATCH_NORMAL);
    131    MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to dispatch release event");
    132  } else {
    133    // Should be in XPCOM shutdown.
    134    MOZ_ASSERT(NS_IsMainThread(), "Main thread is not available for dispatch.");
    135    MainThreadRelease();
    136  }
    137 }
    138 
    139 void HRTFDatabaseLoader::MainThreadRelease() {
    140  MOZ_ASSERT(NS_IsMainThread());
    141  int count = --m_refCnt;
    142  MOZ_ASSERT(count >= 0, "extra release");
    143  NS_LOG_RELEASE(this, count, "HRTFDatabaseLoader");
    144  if (count == 0) {
    145    // It is safe to delete here as the first reference can only be added
    146    // on this (main) thread.
    147    delete this;
    148  }
    149 }
    150 
    151 // Asynchronously load the database in this thread.
    152 static void databaseLoaderEntry(void* threadData) {
    153  AUTO_PROFILER_REGISTER_THREAD("HRTFDatabaseLdr");
    154  NS_SetCurrentThreadName("HRTFDatabaseLdr");
    155 
    156  HRTFDatabaseLoader* loader =
    157      reinterpret_cast<HRTFDatabaseLoader*>(threadData);
    158  MOZ_ASSERT(loader);
    159  loader->load();
    160 }
    161 
    162 void HRTFDatabaseLoader::load() {
    163  MOZ_ASSERT(!NS_IsMainThread());
    164  MOZ_ASSERT(!m_hrtfDatabase.get(), "Called twice");
    165  // Load the default HRTF database.
    166  m_hrtfDatabase = HRTFDatabase::create(m_databaseSampleRate);
    167  m_databaseLoaded = true;
    168  // Notifies the main thread of completion.  See loadAsynchronously().
    169  Release();
    170 }
    171 
    172 void HRTFDatabaseLoader::loadAsynchronously() {
    173  MOZ_ASSERT(NS_IsMainThread());
    174  MOZ_ASSERT(m_refCnt, "Must not be called before a reference is added");
    175 
    176  // Add a reference so that the destructor won't run and wait for the
    177  // loader thread, until load() has completed.
    178  AddRef();
    179 
    180  MutexAutoLock locker(m_threadLock);
    181 
    182  MOZ_ASSERT(!m_hrtfDatabase.get() && !m_databaseLoaderThread, "Called twice");
    183  // Start the asynchronous database loading process.
    184  m_databaseLoaderThread = PR_CreateThread(
    185      PR_USER_THREAD, databaseLoaderEntry, this, PR_PRIORITY_NORMAL,
    186      PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
    187 }
    188 
    189 bool HRTFDatabaseLoader::isLoaded() const { return m_hrtfDatabase.get(); }
    190 
    191 void HRTFDatabaseLoader::waitForLoaderThreadCompletion() {
    192  MutexAutoLock locker(m_threadLock);
    193 
    194  // waitForThreadCompletion() should not be called twice for the same thread.
    195  if (m_databaseLoaderThread) {
    196    DebugOnly<PRStatus> status = PR_JoinThread(m_databaseLoaderThread);
    197    MOZ_ASSERT(status == PR_SUCCESS, "PR_JoinThread failed");
    198  }
    199  m_databaseLoaderThread = nullptr;
    200 }
    201 
    202 void HRTFDatabaseLoader::shutdown() {
    203  MOZ_ASSERT(NS_IsMainThread());
    204  if (s_loaderMap) {
    205    // Set s_loaderMap to nullptr so that the hashtable is not modified on
    206    // reference release during enumeration.
    207    nsTHashtable<LoaderByRateEntry>* loaderMap = s_loaderMap;
    208    s_loaderMap = nullptr;
    209    for (auto iter = loaderMap->Iter(); !iter.Done(); iter.Next()) {
    210      iter.Get()->mLoader->waitForLoaderThreadCompletion();
    211    }
    212    delete loaderMap;
    213  }
    214 }
    215 
    216 }  // namespace WebCore