gecko-dev/dom/media/CallbackThreadRegistry.cpp
Andreas Pehrson 756131fd16 Bug 1796069 - Ignore registrations in CallbackThreadRegistry if refcnt logging is enabled. r=padenot
Callback threads that need to be registered with CallbackThreadRegistry are by
definition externally managed; otherwise they wouldn't need to be registered in
the first place.

We may not have any control of the lifetime of the externally managed thread,
which, when registered with the profiler has an nsThread wrapper created
around it. If the thread outlives all xpcom shutdown stages, the nsThread
wrapper instance will leak (it implements nsIThread and nsISupports!). If
refcnt logging is enabled when it leaks, this particular instance will be
flagged as a leak, and could mark a run on try as failed.

To work around this potential leak, this patch makes CallbackThreadRegistry
registration and unregistration noops when refcnt logging is enabled.

I will also note, that the lifetime issues found with externally managed
threads were most notable on Mac with Grand Central Dispatch's Dispatch Queues.
Over time a large number of real threads could be seen, and the risk of one of
them outliving xpcom shutdown was close to 100% for a common use case involving
camera capture (though timing dependent).

Differential Revision: https://phabricator.services.mozilla.com/D163207
2022-12-01 09:52:53 +00:00

102 lines
2.9 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CallbackThreadRegistry.h"
#include "mozilla/ClearOnShutdown.h"
namespace mozilla {
struct CallbackThreadRegistrySingleton {
CallbackThreadRegistrySingleton()
: mRegistry(MakeUnique<CallbackThreadRegistry>()) {
NS_DispatchToMainThread(
NS_NewRunnableFunction(__func__, [registry = &mRegistry] {
const auto phase = ShutdownPhase::XPCOMShutdownFinal;
MOZ_DIAGNOSTIC_ASSERT(!PastShutdownPhase(phase));
ClearOnShutdown(registry, phase);
}));
}
UniquePtr<CallbackThreadRegistry> mRegistry;
};
CallbackThreadRegistry::CallbackThreadRegistry()
: mThreadIds("CallbackThreadRegistry::mThreadIds") {}
/* static */
CallbackThreadRegistry* CallbackThreadRegistry::Get() {
static CallbackThreadRegistrySingleton sSingleton;
return sSingleton.mRegistry.get();
}
static bool CanLeak() {
#ifdef NS_BUILD_REFCNT_LOGGING
static const bool logging =
getenv("XPCOM_MEM_LEAK_LOG") || getenv("XPCOM_MEM_BLOAT_LOG") ||
getenv("XPCOM_MEM_REFCNT_LOG") || getenv("XPCOM_MEM_ALLOC_LOG") ||
getenv("XPCOM_MEM_COMPTR_LOG");
return logging;
#else
return false;
#endif
}
void CallbackThreadRegistry::Register(ProfilerThreadId aThreadId,
const char* aName) {
if (!aThreadId.IsSpecified()) {
// profiler_current_thread_id is unspecified on unsupported platforms.
return;
}
if (CanLeak()) {
NS_WARNING(
"Not registering callback thread due to refcount logging; it may show "
"up as a leak of the TLS-backed nsThread wrapper if the thread "
"outlives xpcom shutdown.");
return;
}
auto threadIds = mThreadIds.Lock();
for (uint32_t i = 0; i < threadIds->Length(); i++) {
if ((*threadIds)[i].mId == aThreadId) {
(*threadIds)[i].mUserCount++;
return;
}
}
ThreadUserCount tuc;
tuc.mId = aThreadId;
tuc.mUserCount = 1;
threadIds->AppendElement(tuc);
PROFILER_REGISTER_THREAD(aName);
}
void CallbackThreadRegistry::Unregister(ProfilerThreadId aThreadId) {
if (!aThreadId.IsSpecified()) {
// profiler_current_thread_id is unspedified on unsupported platforms.
return;
}
if (CanLeak()) {
return;
}
auto threadIds = mThreadIds.Lock();
for (uint32_t i = 0; i < threadIds->Length(); i++) {
if ((*threadIds)[i].mId == aThreadId) {
MOZ_ASSERT((*threadIds)[i].mUserCount > 0);
(*threadIds)[i].mUserCount--;
if ((*threadIds)[i].mUserCount == 0) {
PROFILER_UNREGISTER_THREAD();
threadIds->RemoveElementAt(i);
}
return;
}
}
MOZ_ASSERT_UNREACHABLE("Current thread was not registered");
}
} // namespace mozilla