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:
Gerald Squelart 2019-07-04 04:43:41 +00:00
Родитель 4d91208989
Коммит 5fcb437d2b
2 изменённых файлов: 70 добавлений и 7 удалений

Просмотреть файл

@ -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