зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1559000 - Make AutoProfilerLabel thread-safe - r=mstange
Profilers will soon be able to set/reset entry&exit functions at different times, but simultaneously other code may want to use AutoProfilerLabel, so we need to make this all thread-safe. All shared static information is now encapsulated in an RAII class that enforces proper locking before giving access to this information. Also added a "generation" count, so that if an AutoProfilerLabel is in-flight when entry&exit functions are changed, the context given by the old entry function will not be passed to a mismatched new exit function. Differential Revision: https://phabricator.services.mozilla.com/D34807 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
4d91208989
Коммит
5fcb437d2b
|
@ -6,15 +6,67 @@
|
|||
|
||||
#include "mozilla/AutoProfilerLabel.h"
|
||||
|
||||
#include "mozilla/PlatformMutex.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
static ProfilerLabelEnter sEnter = nullptr;
|
||||
static ProfilerLabelExit sExit = nullptr;
|
||||
// RAII class that encapsulates all shared static data, and enforces locking
|
||||
// when accessing this data.
|
||||
class MOZ_RAII AutoProfilerLabelData {
|
||||
public:
|
||||
AutoProfilerLabelData() { sAPLMutex.Lock(); }
|
||||
|
||||
~AutoProfilerLabelData() { sAPLMutex.Unlock(); }
|
||||
|
||||
AutoProfilerLabelData(const AutoProfilerLabelData&) = delete;
|
||||
void operator=(const AutoProfilerLabelData&) = delete;
|
||||
|
||||
const ProfilerLabelEnter& EnterCRef() const { return sEnter; }
|
||||
ProfilerLabelEnter& EnterRef() { return sEnter; }
|
||||
|
||||
const ProfilerLabelExit& ExitCRef() const { return sExit; }
|
||||
ProfilerLabelExit& ExitRef() { return sExit; }
|
||||
|
||||
const uint32_t& GenerationCRef() const { return sGeneration; }
|
||||
uint32_t& GenerationRef() { return sGeneration; }
|
||||
|
||||
private:
|
||||
// Thin shell around mozglue PlatformMutex, for local internal use.
|
||||
// Does not preserve behavior in JS record/replay.
|
||||
class Mutex : private mozilla::detail::MutexImpl {
|
||||
public:
|
||||
Mutex()
|
||||
: mozilla::detail::MutexImpl(
|
||||
mozilla::recordreplay::Behavior::DontPreserve) {}
|
||||
void Lock() { mozilla::detail::MutexImpl::lock(); }
|
||||
void Unlock() { mozilla::detail::MutexImpl::unlock(); }
|
||||
};
|
||||
|
||||
// Mutex protecting access to the following static members.
|
||||
static Mutex sAPLMutex;
|
||||
|
||||
static ProfilerLabelEnter sEnter;
|
||||
static ProfilerLabelExit sExit;
|
||||
|
||||
// Current "generation" of RegisterProfilerLabelEnterExit calls.
|
||||
static uint32_t sGeneration;
|
||||
};
|
||||
|
||||
/* static */ AutoProfilerLabelData::Mutex AutoProfilerLabelData::sAPLMutex;
|
||||
/* static */ ProfilerLabelEnter AutoProfilerLabelData::sEnter = nullptr;
|
||||
/* static */ ProfilerLabelExit AutoProfilerLabelData::sExit = nullptr;
|
||||
/* static */ uint32_t AutoProfilerLabelData::sGeneration = 0;
|
||||
|
||||
void RegisterProfilerLabelEnterExit(ProfilerLabelEnter aEnter,
|
||||
ProfilerLabelExit aExit) {
|
||||
sEnter = aEnter;
|
||||
sExit = aExit;
|
||||
MOZ_ASSERT(!aEnter == !aExit, "Must provide both null or both non-null");
|
||||
|
||||
AutoProfilerLabelData data;
|
||||
MOZ_ASSERT(!aEnter != !data.EnterRef(),
|
||||
"Must go from null to non-null, or from non-null to null");
|
||||
data.EnterRef() = aEnter;
|
||||
data.ExitRef() = aExit;
|
||||
++data.GenerationRef();
|
||||
}
|
||||
|
||||
AutoProfilerLabel::AutoProfilerLabel(
|
||||
|
@ -22,12 +74,20 @@ AutoProfilerLabel::AutoProfilerLabel(
|
|||
const char* aDynamicString MOZ_GUARD_OBJECT_NOTIFIER_PARAM_IN_IMPL) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
mEntryContext = sEnter ? sEnter(aLabel, aDynamicString, this) : nullptr;
|
||||
const AutoProfilerLabelData data;
|
||||
mEntryContext = (data.EnterCRef())
|
||||
? data.EnterCRef()(aLabel, aDynamicString, this)
|
||||
: nullptr;
|
||||
mGeneration = data.GenerationCRef();
|
||||
}
|
||||
|
||||
AutoProfilerLabel::~AutoProfilerLabel() {
|
||||
if (sExit && mEntryContext) {
|
||||
sExit(mEntryContext);
|
||||
if (!mEntryContext) {
|
||||
return;
|
||||
}
|
||||
const AutoProfilerLabelData data;
|
||||
if (data.ExitCRef() && (mGeneration == data.GenerationCRef())) {
|
||||
data.ExitCRef()(mEntryContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,9 @@ class MOZ_RAII AutoProfilerLabel {
|
|||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
void* mEntryContext;
|
||||
// Number of RegisterProfilerLabelEnterExit calls, to avoid giving an entry
|
||||
// context from one generation to the next.
|
||||
uint32_t mGeneration;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче