зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1577937 - Throw a StaticDataMutex around sTelemetry r=janerik,froydnj
It could very well happen that someone calls into a static method of TelemetryImpl during Telemetry shutdown. There could be a race where sTelemetry is non-null at the top of a method like CanRecordExtended, but is null by the time we try to use it. So let's put a StaticDataMutex around it. This isn't trying to mutex the data itself. Instead I'm just trying to protect places where the pointer is being read or changed. Differential Revision: https://phabricator.services.mozilla.com/D44905 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
73a8e158b7
Коммит
6458a36928
|
@ -28,6 +28,7 @@
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/BackgroundHangMonitor.h"
|
#include "mozilla/BackgroundHangMonitor.h"
|
||||||
#include "mozilla/Components.h"
|
#include "mozilla/Components.h"
|
||||||
|
#include "mozilla/DataMutex.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/FStream.h"
|
#include "mozilla/FStream.h"
|
||||||
#include "mozilla/IOInterposer.h"
|
#include "mozilla/IOInterposer.h"
|
||||||
|
@ -186,7 +187,7 @@ class TelemetryImpl final : public nsITelemetry, public nsIMemoryReporter {
|
||||||
|
|
||||||
void ReadLateWritesStacks(nsIFile* aProfileDir);
|
void ReadLateWritesStacks(nsIFile* aProfileDir);
|
||||||
|
|
||||||
static TelemetryImpl* sTelemetry;
|
static StaticDataMutex<TelemetryImpl*> sTelemetry;
|
||||||
AutoHashtable<SlowSQLEntryType> mPrivateSQL;
|
AutoHashtable<SlowSQLEntryType> mPrivateSQL;
|
||||||
AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
|
AutoHashtable<SlowSQLEntryType> mSanitizedSQL;
|
||||||
Mutex mHashMutex;
|
Mutex mHashMutex;
|
||||||
|
@ -211,7 +212,7 @@ class TelemetryImpl final : public nsITelemetry, public nsIMemoryReporter {
|
||||||
WebrtcTelemetry mWebrtcTelemetry;
|
WebrtcTelemetry mWebrtcTelemetry;
|
||||||
};
|
};
|
||||||
|
|
||||||
TelemetryImpl* TelemetryImpl::sTelemetry = nullptr;
|
StaticDataMutex<TelemetryImpl*> TelemetryImpl::sTelemetry(nullptr, nullptr);
|
||||||
|
|
||||||
MOZ_DEFINE_MALLOC_SIZE_OF(TelemetryMallocSizeOf)
|
MOZ_DEFINE_MALLOC_SIZE_OF(TelemetryMallocSizeOf)
|
||||||
|
|
||||||
|
@ -343,32 +344,39 @@ class nsFetchTelemetryData : public Runnable {
|
||||||
: mozilla::Runnable("nsFetchTelemetryData"),
|
: mozilla::Runnable("nsFetchTelemetryData"),
|
||||||
mShutdownTimeFilename(aShutdownTimeFilename),
|
mShutdownTimeFilename(aShutdownTimeFilename),
|
||||||
mFailedProfileLockFile(aFailedProfileLockFile),
|
mFailedProfileLockFile(aFailedProfileLockFile),
|
||||||
mTelemetry(TelemetryImpl::sTelemetry),
|
|
||||||
mProfileDir(aProfileDir) {}
|
mProfileDir(aProfileDir) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PathCharPtr mShutdownTimeFilename;
|
PathCharPtr mShutdownTimeFilename;
|
||||||
nsCOMPtr<nsIFile> mFailedProfileLockFile;
|
nsCOMPtr<nsIFile> mFailedProfileLockFile;
|
||||||
RefPtr<TelemetryImpl> mTelemetry;
|
|
||||||
nsCOMPtr<nsIFile> mProfileDir;
|
nsCOMPtr<nsIFile> mProfileDir;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void MainThread() {
|
void MainThread() {
|
||||||
mTelemetry->mCachedTelemetryData = true;
|
auto lock = TelemetryImpl::sTelemetry.Lock();
|
||||||
for (unsigned int i = 0, n = mTelemetry->mCallbacks.Count(); i < n; ++i) {
|
auto telemetry = lock.ref();
|
||||||
mTelemetry->mCallbacks[i]->Complete();
|
telemetry->mCachedTelemetryData = true;
|
||||||
|
for (unsigned int i = 0, n = telemetry->mCallbacks.Count(); i < n; ++i) {
|
||||||
|
telemetry->mCallbacks[i]->Complete();
|
||||||
}
|
}
|
||||||
mTelemetry->mCallbacks.Clear();
|
telemetry->mCallbacks.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run() override {
|
NS_IMETHOD Run() override {
|
||||||
LoadFailedLockCount(mTelemetry->mFailedLockCount);
|
uint32_t failedLockCount = 0;
|
||||||
mTelemetry->mLastShutdownTime =
|
uint32_t lastShutdownDuration = 0;
|
||||||
ReadLastShutdownDuration(mShutdownTimeFilename);
|
LoadFailedLockCount(failedLockCount);
|
||||||
mTelemetry->ReadLateWritesStacks(mProfileDir);
|
lastShutdownDuration = ReadLastShutdownDuration(mShutdownTimeFilename);
|
||||||
|
{
|
||||||
|
auto lock = TelemetryImpl::sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
|
telemetry->mFailedLockCount = failedLockCount;
|
||||||
|
telemetry->mLastShutdownTime = lastShutdownDuration;
|
||||||
|
telemetry->ReadLateWritesStacks(mProfileDir);
|
||||||
|
}
|
||||||
|
|
||||||
TelemetryScalar::Set(Telemetry::ScalarID::BROWSER_TIMINGS_LAST_SHUTDOWN,
|
TelemetryScalar::Set(Telemetry::ScalarID::BROWSER_TIMINGS_LAST_SHUTDOWN,
|
||||||
mTelemetry->mLastShutdownTime);
|
lastShutdownDuration);
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> e =
|
nsCOMPtr<nsIRunnable> e =
|
||||||
NewRunnableMethod("nsFetchTelemetryData::MainThread", this,
|
NewRunnableMethod("nsFetchTelemetryData::MainThread", this,
|
||||||
|
@ -1175,9 +1183,12 @@ TelemetryImpl::GetIsOfficialTelemetry(bool* ret) {
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsITelemetry> TelemetryImpl::CreateTelemetryInstance() {
|
already_AddRefed<nsITelemetry> TelemetryImpl::CreateTelemetryInstance() {
|
||||||
MOZ_ASSERT(
|
{
|
||||||
sTelemetry == nullptr,
|
auto lock = sTelemetry.Lock();
|
||||||
"CreateTelemetryInstance may only be called once, via GetService()");
|
MOZ_ASSERT(
|
||||||
|
*lock == nullptr,
|
||||||
|
"CreateTelemetryInstance may only be called once, via GetService()");
|
||||||
|
}
|
||||||
|
|
||||||
bool useTelemetry = false;
|
bool useTelemetry = false;
|
||||||
#ifndef FUZZING
|
#ifndef FUZZING
|
||||||
|
@ -1202,17 +1213,21 @@ already_AddRefed<nsITelemetry> TelemetryImpl::CreateTelemetryInstance() {
|
||||||
TelemetryOrigin::InitializeGlobalState();
|
TelemetryOrigin::InitializeGlobalState();
|
||||||
|
|
||||||
// Now, create and initialize the Telemetry global state.
|
// Now, create and initialize the Telemetry global state.
|
||||||
sTelemetry = new TelemetryImpl();
|
TelemetryImpl* telemetry = new TelemetryImpl();
|
||||||
|
{
|
||||||
|
auto lock = sTelemetry.Lock();
|
||||||
|
*lock = telemetry;
|
||||||
|
}
|
||||||
|
|
||||||
// AddRef for the local reference
|
// AddRef for the local reference
|
||||||
NS_ADDREF(sTelemetry);
|
NS_ADDREF(telemetry);
|
||||||
// AddRef for the caller
|
// AddRef for the caller
|
||||||
nsCOMPtr<nsITelemetry> ret = sTelemetry;
|
nsCOMPtr<nsITelemetry> ret = telemetry;
|
||||||
|
|
||||||
sTelemetry->mCanRecordBase = useTelemetry;
|
telemetry->mCanRecordBase = useTelemetry;
|
||||||
sTelemetry->mCanRecordExtended = useTelemetry;
|
telemetry->mCanRecordExtended = useTelemetry;
|
||||||
|
|
||||||
sTelemetry->InitMemoryReporter();
|
telemetry->InitMemoryReporter();
|
||||||
InitHistogramRecordingEnabled(); // requires sTelemetry to exist
|
InitHistogramRecordingEnabled(); // requires sTelemetry to exist
|
||||||
|
|
||||||
#if defined(MOZ_TELEMETRY_GECKOVIEW)
|
#if defined(MOZ_TELEMETRY_GECKOVIEW)
|
||||||
|
@ -1230,7 +1245,10 @@ already_AddRefed<nsITelemetry> TelemetryImpl::CreateTelemetryInstance() {
|
||||||
void TelemetryImpl::ShutdownTelemetry() {
|
void TelemetryImpl::ShutdownTelemetry() {
|
||||||
// No point in collecting IO beyond this point
|
// No point in collecting IO beyond this point
|
||||||
ClearIOReporting();
|
ClearIOReporting();
|
||||||
NS_IF_RELEASE(sTelemetry);
|
{
|
||||||
|
auto lock = sTelemetry.Lock();
|
||||||
|
NS_IF_RELEASE(lock.ref());
|
||||||
|
}
|
||||||
|
|
||||||
// Lastly, de-initialise the TelemetryHistogram and TelemetryScalar global
|
// Lastly, de-initialise the TelemetryHistogram and TelemetryScalar global
|
||||||
// states, so as to release any heap storage that would otherwise be kept
|
// states, so as to release any heap storage that would otherwise be kept
|
||||||
|
@ -1250,13 +1268,15 @@ void TelemetryImpl::ShutdownTelemetry() {
|
||||||
|
|
||||||
void TelemetryImpl::StoreSlowSQL(const nsACString& sql, uint32_t delay,
|
void TelemetryImpl::StoreSlowSQL(const nsACString& sql, uint32_t delay,
|
||||||
SanitizedState state) {
|
SanitizedState state) {
|
||||||
|
auto lock = sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
AutoHashtable<SlowSQLEntryType>* slowSQLMap = nullptr;
|
AutoHashtable<SlowSQLEntryType>* slowSQLMap = nullptr;
|
||||||
if (state == Sanitized)
|
if (state == Sanitized)
|
||||||
slowSQLMap = &(sTelemetry->mSanitizedSQL);
|
slowSQLMap = &(telemetry->mSanitizedSQL);
|
||||||
else
|
else
|
||||||
slowSQLMap = &(sTelemetry->mPrivateSQL);
|
slowSQLMap = &(telemetry->mPrivateSQL);
|
||||||
|
|
||||||
MutexAutoLock hashMutex(sTelemetry->mHashMutex);
|
MutexAutoLock hashMutex(telemetry->mHashMutex);
|
||||||
|
|
||||||
SlowSQLEntryType* entry = slowSQLMap->GetEntry(sql);
|
SlowSQLEntryType* entry = slowSQLMap->GetEntry(sql);
|
||||||
if (!entry) {
|
if (!entry) {
|
||||||
|
@ -1455,7 +1475,12 @@ void TelemetryImpl::RecordSlowStatement(const nsACString& sql,
|
||||||
MOZ_ASSERT(!sql.IsEmpty());
|
MOZ_ASSERT(!sql.IsEmpty());
|
||||||
MOZ_ASSERT(!dbName.IsEmpty());
|
MOZ_ASSERT(!dbName.IsEmpty());
|
||||||
|
|
||||||
if (!sTelemetry || !TelemetryHistogram::CanRecordExtended()) return;
|
{
|
||||||
|
auto lock = sTelemetry.Lock();
|
||||||
|
if (!lock.ref() || !TelemetryHistogram::CanRecordExtended()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool recordStatement = false;
|
bool recordStatement = false;
|
||||||
|
|
||||||
|
@ -1504,17 +1529,21 @@ void TelemetryImpl::RecordSlowStatement(const nsACString& sql,
|
||||||
|
|
||||||
void TelemetryImpl::RecordIceCandidates(const uint32_t iceCandidateBitmask,
|
void TelemetryImpl::RecordIceCandidates(const uint32_t iceCandidateBitmask,
|
||||||
const bool success) {
|
const bool success) {
|
||||||
if (!sTelemetry || !TelemetryHistogram::CanRecordExtended()) return;
|
auto lock = sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
|
if (!telemetry || !TelemetryHistogram::CanRecordExtended()) return;
|
||||||
|
|
||||||
sTelemetry->mWebrtcTelemetry.RecordIceCandidateMask(iceCandidateBitmask,
|
telemetry->mWebrtcTelemetry.RecordIceCandidateMask(iceCandidateBitmask,
|
||||||
success);
|
success);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MOZ_GECKO_PROFILER)
|
#if defined(MOZ_GECKO_PROFILER)
|
||||||
|
|
||||||
void TelemetryImpl::DoStackCapture(const nsACString& aKey) {
|
void TelemetryImpl::DoStackCapture(const nsACString& aKey) {
|
||||||
if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
|
if (Telemetry::CanRecordExtended() && XRE_IsParentProcess()) {
|
||||||
sTelemetry->mStackCapturer.Capture(aKey);
|
auto lock = sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
|
telemetry->mStackCapturer.Capture(aKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1527,20 +1556,24 @@ nsresult TelemetryImpl::CaptureStack(const nsACString& aKey) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TelemetryImpl::CanRecordBase() {
|
bool TelemetryImpl::CanRecordBase() {
|
||||||
if (!sTelemetry) {
|
auto lock = sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
|
if (!telemetry) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool canRecordBase;
|
bool canRecordBase;
|
||||||
nsresult rv = sTelemetry->GetCanRecordBase(&canRecordBase);
|
nsresult rv = telemetry->GetCanRecordBase(&canRecordBase);
|
||||||
return NS_SUCCEEDED(rv) && canRecordBase;
|
return NS_SUCCEEDED(rv) && canRecordBase;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TelemetryImpl::CanRecordExtended() {
|
bool TelemetryImpl::CanRecordExtended() {
|
||||||
if (!sTelemetry) {
|
auto lock = sTelemetry.Lock();
|
||||||
|
auto telemetry = lock.ref();
|
||||||
|
if (!telemetry) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool canRecordExtended;
|
bool canRecordExtended;
|
||||||
nsresult rv = sTelemetry->GetCanRecordExtended(&canRecordExtended);
|
nsresult rv = telemetry->GetCanRecordExtended(&canRecordExtended);
|
||||||
return NS_SUCCEEDED(rv) && canRecordExtended;
|
return NS_SUCCEEDED(rv) && canRecordExtended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче