bug 1218576 - Ensure IPCTimer is on the main thread. r=froydnj f=gfritzsche

nsTimer fires on the thread that created the timer. An nsTimer instance should
only be manipulated on its target thread (it isn't threadsafe). IPC using
PContent must be on the main thread.

Thus, everything to do with the gIPCTimer must be on the main thread.

This also takes care of bug 1299312.

MozReview-Commit-ID: IcVRYsoX2R9
This commit is contained in:
Chris H-C 2016-08-31 13:31:30 -04:00
parent 608c587bf3
commit d88b9182b1

View File

@ -16,6 +16,7 @@
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/Atomics.h"
#include "mozilla/StartupTimeline.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
@ -194,7 +195,8 @@ base::StatisticsRecorder* gStatisticsRecorder = nullptr;
// For batching and sending child process accumulations to the parent
nsITimer* gIPCTimer = nullptr;
bool gIPCTimerArmed = false;
mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArmed(false);
mozilla::Atomic<bool, mozilla::Relaxed> gIPCTimerArming(false);
StaticAutoPtr<nsTArray<Accumulation>> gAccumulations;
StaticAutoPtr<nsTArray<KeyedAccumulation>> gKeyedAccumulations;
@ -1239,6 +1241,14 @@ internal_AddonReflector(AddonEntryType *entry, JSContext *cx,
//
// PRIVATE: thread-unsafe helpers for the external interface
// This is a StaticMutex rather than a plain Mutex (1) so that
// it gets initialised in a thread-safe manner the first time
// it is used, and (2) because it is never de-initialised, and
// a normal Mutex would show up as a leak in BloatView. StaticMutex
// also has the "OffTheBooks" property, so it won't show as a leak
// in BloatView.
static StaticMutex gTelemetryHistogramMutex;
namespace {
void
@ -1268,8 +1278,10 @@ internal_SetHistogramRecordingEnabled(mozilla::Telemetry::ID aID, bool aEnabled)
MOZ_ASSERT(false, "Telemetry::SetHistogramRecordingEnabled(...) id not found");
}
void internal_armIPCTimer()
void internal_armIPCTimerMainThread()
{
MOZ_ASSERT(NS_IsMainThread());
gIPCTimerArming = false;
if (gIPCTimerArmed) {
return;
}
@ -1284,6 +1296,22 @@ void internal_armIPCTimer()
}
}
void internal_armIPCTimer()
{
if (gIPCTimerArmed || gIPCTimerArming) {
return;
}
gIPCTimerArming = true;
if (NS_IsMainThread()) {
internal_armIPCTimerMainThread();
} else {
NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
StaticMutexAutoLock locker(gTelemetryHistogramMutex);
internal_armIPCTimerMainThread();
}));
}
}
bool
internal_RemoteAccumulate(mozilla::Telemetry::ID aId, uint32_t aSample)
{
@ -1890,14 +1918,6 @@ internal_WrapAndReturnKeyedHistogram(KeyedHistogram *h, JSContext *cx,
//
// EXTERNALLY VISIBLE FUNCTIONS in namespace TelemetryHistogram::
// This is a StaticMutex rather than a plain Mutex (1) so that
// it gets initialised in a thread-safe manner the first time
// it is used, and (2) because it is never de-initialised, and
// a normal Mutex would show up as a leak in BloatView. StaticMutex
// also has the "OffTheBooks" property, so it won't show as a leak
// in BloatView.
static StaticMutex gTelemetryHistogramMutex;
// All of these functions are actually in namespace TelemetryHistogram::,
// but the ::TelemetryHistogram prefix is given explicitly. This is
// because it is critical to see which calls from these functions are
@ -2597,11 +2617,11 @@ TelemetryHistogram::GetHistogramSizesofIncludingThis(mozilla::MallocSizeOf
// To ensure we don't loop IPCTimerFired->AccumulateChild->arm timer, we don't
// unset gIPCTimerArmed until the IPC completes
//
// This function may be re-entered. The shared datastructures gAccumulations and
// gKeyedAccumulations are guarded by the lock.
// This function must be called on the main thread, otherwise IPC will fail.
void
TelemetryHistogram::IPCTimerFired(nsITimer* aTimer, void* aClosure)
{
MOZ_ASSERT(NS_IsMainThread());
nsTArray<Accumulation> accumulationsToSend;
nsTArray<KeyedAccumulation> keyedAccumulationsToSend;
{