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