tor-browser

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

CallbackThreadRegistry.cpp (3033B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "CallbackThreadRegistry.h"
      8 
      9 #include "mozilla/ClearOnShutdown.h"
     10 #include "nsThreadUtils.h"
     11 
     12 namespace mozilla {
     13 struct CallbackThreadRegistrySingleton {
     14  CallbackThreadRegistrySingleton()
     15      : mRegistry(MakeUnique<CallbackThreadRegistry>()) {
     16    NS_DispatchToMainThread(
     17        NS_NewRunnableFunction(__func__, [registry = &mRegistry] {
     18          const auto phase = ShutdownPhase::XPCOMShutdownFinal;
     19          MOZ_DIAGNOSTIC_ASSERT(!PastShutdownPhase(phase));
     20          ClearOnShutdown(registry, phase);
     21        }));
     22  }
     23 
     24  UniquePtr<CallbackThreadRegistry> mRegistry;
     25 };
     26 
     27 CallbackThreadRegistry::CallbackThreadRegistry()
     28    : mThreadIds("CallbackThreadRegistry::mThreadIds") {}
     29 
     30 /* static */
     31 CallbackThreadRegistry* CallbackThreadRegistry::Get() {
     32  static CallbackThreadRegistrySingleton sSingleton;
     33  return sSingleton.mRegistry.get();
     34 }
     35 
     36 static bool CanLeak() {
     37 #ifdef NS_BUILD_REFCNT_LOGGING
     38  static const bool logging =
     39      getenv("XPCOM_MEM_LEAK_LOG") || getenv("XPCOM_MEM_BLOAT_LOG") ||
     40      getenv("XPCOM_MEM_REFCNT_LOG") || getenv("XPCOM_MEM_ALLOC_LOG") ||
     41      getenv("XPCOM_MEM_COMPTR_LOG");
     42  return logging;
     43 #else
     44  return false;
     45 #endif
     46 }
     47 
     48 void CallbackThreadRegistry::Register(ProfilerThreadId aThreadId,
     49                                      const char* aName) {
     50  if (!aThreadId.IsSpecified()) {
     51    // profiler_current_thread_id is unspecified on unsupported platforms.
     52    return;
     53  }
     54 
     55  if (CanLeak()) {
     56    NS_WARNING(
     57        "Not registering callback thread due to refcount logging; it may show "
     58        "up as a leak of the TLS-backed nsThread wrapper if the thread "
     59        "outlives xpcom shutdown.");
     60    return;
     61  }
     62 
     63  auto threadIds = mThreadIds.Lock();
     64  for (uint32_t i = 0; i < threadIds->Length(); i++) {
     65    if ((*threadIds)[i].mId == aThreadId) {
     66      (*threadIds)[i].mUserCount++;
     67      return;
     68    }
     69  }
     70  ThreadUserCount tuc;
     71  tuc.mId = aThreadId;
     72  tuc.mUserCount = 1;
     73  threadIds->AppendElement(tuc);
     74  PROFILER_REGISTER_THREAD(aName);
     75 }
     76 
     77 void CallbackThreadRegistry::Unregister(ProfilerThreadId aThreadId) {
     78  if (!aThreadId.IsSpecified()) {
     79    // profiler_current_thread_id is unspedified on unsupported platforms.
     80    return;
     81  }
     82 
     83  if (CanLeak()) {
     84    return;
     85  }
     86 
     87  auto threadIds = mThreadIds.Lock();
     88  for (uint32_t i = 0; i < threadIds->Length(); i++) {
     89    if ((*threadIds)[i].mId == aThreadId) {
     90      MOZ_ASSERT((*threadIds)[i].mUserCount > 0);
     91      (*threadIds)[i].mUserCount--;
     92 
     93      if ((*threadIds)[i].mUserCount == 0) {
     94        PROFILER_UNREGISTER_THREAD();
     95        threadIds->RemoveElementAt(i);
     96      }
     97      return;
     98    }
     99  }
    100  MOZ_ASSERT_UNREACHABLE("Current thread was not registered");
    101 }
    102 
    103 }  // namespace mozilla