Bug 1362957 - Refactor lock-protected TelemetryScalar code. r=Dexter
authorFernando <mortificador@gmail.com>
Sun, 15 Oct 2017 05:42:00 -0400
changeset 387019 c830f5c33251d347c8f20f49c264c13c57d96614
parent 387018 99f3aa7d125f85c1ed8b4a82b7284a05df59f91b
child 387020 9473b60e5eeb8279bebe21edf7b4a00e821997a4
push id32705
push userryanvm@gmail.com
push dateThu, 19 Oct 2017 01:01:49 +0000
treeherdermozilla-central@a21099ce055f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersDexter
bugs1362957
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1362957 - Refactor lock-protected TelemetryScalar code. r=Dexter
toolkit/components/telemetry/TelemetryScalar.cpp
--- a/toolkit/components/telemetry/TelemetryScalar.cpp
+++ b/toolkit/components/telemetry/TelemetryScalar.cpp
@@ -48,30 +48,29 @@ using mozilla::Telemetry::ProcessID;
 namespace TelemetryIPCAccumulator = mozilla::TelemetryIPCAccumulator;
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
 // Naming: there are two kinds of functions in this file:
 //
 // * Functions named internal_*: these can only be reached via an
-//   interface function (TelemetryScalar::*). They expect the interface
-//   function to have acquired |gTelemetryScalarsMutex|, so they do not
-//   have to be thread-safe.
+//   interface function (TelemetryScalar::*). If they access shared
+//   state, they require the interface function to have acquired
+//   |gTelemetryScalarMutex| to ensure thread safety.
 //
 // * Functions named TelemetryScalar::*. This is the external interface.
 //   Entries and exits to these functions are serialised using
 //   |gTelemetryScalarsMutex|.
 //
 // Avoiding races and deadlocks:
 //
 // All functions in the external interface (TelemetryScalar::*) are
 // serialised using the mutex |gTelemetryScalarsMutex|. This means
-// that the external interface is thread-safe, and many of the
-// internal_* functions can ignore thread safety. But it also brings
+// that the external interface is thread-safe. But it also brings
 // a danger of deadlock if any function in the external interface can
 // get back to that interface. That is, we will deadlock on any call
 // chain like this
 //
 // TelemetryScalar::* -> .. any functions .. -> TelemetryScalar::*
 //
 // To reduce the danger of that happening, observe the following rules:
 //
@@ -175,35 +174,33 @@ DynamicScalarInfo::expiration() const
 
 typedef nsBaseHashtableET<nsDepCharHashKey, ScalarKey> CharPtrEntryType;
 typedef AutoHashtable<CharPtrEntryType> ScalarMapType;
 
 // Dynamic scalar definitions.
 StaticAutoPtr<nsTArray<DynamicScalarInfo>> gDynamicScalarInfo;
 
 const BaseScalarInfo&
-internal_GetScalarInfo(const ScalarKey& aId)
+internal_GetScalarInfo(const StaticMutexAutoLock& lock, const ScalarKey& aId)
 {
   if (!aId.dynamic) {
     return gScalars[aId.id];
   }
 
   return (*gDynamicScalarInfo)[aId.id];
 }
 
 bool
 IsValidEnumId(mozilla::Telemetry::ScalarID aID)
 {
   return aID < mozilla::Telemetry::ScalarID::ScalarCount;
 }
 
-// TODO: We should explicitly pass a lock here. Unfortunately this needs
-// some refactoring of the callers as well. See bug 1362957.
 bool
-internal_IsValidId(const ScalarKey& aId)
+internal_IsValidId(const StaticMutexAutoLock& lock, const ScalarKey& aId)
 {
   // Please note that this function needs to be called with the scalar
   // mutex being acquired: other functions might be messing with
   // |gDynamicScalarInfo|.
   return aId.dynamic ? (aId.id < gDynamicScalarInfo->Length()) :
     IsValidEnumId(static_cast<mozilla::Telemetry::ScalarID>(aId.id));
 }
 
@@ -941,122 +938,131 @@ internal_LogScalarError(const nsACString
   LogToBrowserConsole(nsIScriptError::warningFlag, errorMessage);
 }
 
 } // namespace
 
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 //
-// PRIVATE: thread-unsafe helpers for the external interface
+// PRIVATE: helpers for the external interface
 
 namespace {
 
 bool
-internal_CanRecordBase()
+internal_CanRecordBase(const StaticMutexAutoLock& lock)
 {
   return gCanRecordBase;
 }
 
 bool
-internal_CanRecordExtended()
+internal_CanRecordExtended(const StaticMutexAutoLock& lock)
 {
   return gCanRecordExtended;
 }
 
 /**
  * Check if the given scalar is a keyed scalar.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aId The scalar identifier.
  * @return true if aId refers to a keyed scalar, false otherwise.
  */
 bool
-internal_IsKeyedScalar(const ScalarKey& aId)
+internal_IsKeyedScalar(const StaticMutexAutoLock& lock, const ScalarKey& aId)
 {
-  return internal_GetScalarInfo(aId).keyed;
+  return internal_GetScalarInfo(lock, aId).keyed;
 }
 
 /**
  * Check if we're allowed to record the given scalar in the current
  * process.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aId The scalar identifier.
  * @return true if the scalar is allowed to be recorded in the current process, false
  *         otherwise.
  */
 bool
-internal_CanRecordProcess(const ScalarKey& aId)
+internal_CanRecordProcess(const StaticMutexAutoLock& lock,
+                          const ScalarKey& aId)
 {
-  const BaseScalarInfo &info = internal_GetScalarInfo(aId);
+  const BaseScalarInfo &info = internal_GetScalarInfo(lock, aId);
   return CanRecordInProcess(info.record_in_processes, XRE_GetProcessType());
 }
 
 bool
-internal_CanRecordForScalarID(const ScalarKey& aId)
+internal_CanRecordForScalarID(const StaticMutexAutoLock& lock,
+                              const ScalarKey& aId)
 {
   // Get the scalar info from the id.
-  const BaseScalarInfo &info = internal_GetScalarInfo(aId);
+  const BaseScalarInfo &info = internal_GetScalarInfo(lock, aId);
 
   // Can we record at all?
-  bool canRecordBase = internal_CanRecordBase();
+  bool canRecordBase = internal_CanRecordBase(lock);
   if (!canRecordBase) {
     return false;
   }
 
   bool canRecordDataset = CanRecordDataset(info.dataset,
                                            canRecordBase,
-                                           internal_CanRecordExtended());
+                                           internal_CanRecordExtended(lock));
   if (!canRecordDataset) {
     return false;
   }
 
   return true;
 }
 
 /**
  * Check if we are allowed to record the provided scalar.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aId The scalar identifier.
  * @param aKeyed Are we attempting to write a keyed scalar?
  * @return ScalarResult::Ok if we can record, an error code otherwise.
  */
 ScalarResult
-internal_CanRecordScalar(const ScalarKey& aId, bool aKeyed)
+internal_CanRecordScalar(const StaticMutexAutoLock& lock, const ScalarKey& aId,
+                         bool aKeyed)
 {
   // Make sure that we have a keyed scalar if we are trying to change one.
-  if (internal_IsKeyedScalar(aId) != aKeyed) {
+  if (internal_IsKeyedScalar(lock, aId) != aKeyed) {
     return ScalarResult::KeyedTypeMismatch;
   }
 
   // Are we allowed to record this scalar based on the current Telemetry
   // settings?
-  if (!internal_CanRecordForScalarID(aId)) {
+  if (!internal_CanRecordForScalarID(lock, aId)) {
     return ScalarResult::CannotRecordDataset;
   }
 
   // Can we record in this process?
-  if (!internal_CanRecordProcess(aId)) {
+  if (!internal_CanRecordProcess(lock, aId)) {
     return ScalarResult::CannotRecordInProcess;
   }
 
   return ScalarResult::Ok;
 }
 
 /**
  * Get the scalar enum id from the scalar name.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aName The scalar name.
  * @param aId The output variable to contain the enum.
  * @return
  *   NS_ERROR_FAILURE if this was called before init is completed.
  *   NS_ERROR_INVALID_ARG if the name can't be found in the scalar definitions.
  *   NS_OK if the scalar was found and aId contains a valid enum id.
  */
 nsresult
-internal_GetEnumByScalarName(const nsACString& aName, ScalarKey* aId)
+internal_GetEnumByScalarName(const StaticMutexAutoLock& lock,
+                             const nsACString& aName,
+                             ScalarKey* aId)
 {
   if (!gInitDone) {
     return NS_ERROR_FAILURE;
   }
 
   CharPtrEntryType *entry = gScalarNameIDMap.GetEntry(PromiseFlatCString(aName).get());
   if (!entry) {
     return NS_ERROR_INVALID_ARG;
@@ -1064,40 +1070,42 @@ internal_GetEnumByScalarName(const nsACS
   *aId = entry->mData;
   return NS_OK;
 }
 
 /**
  * Get a scalar object by its enum id. This implicitly allocates the scalar
  * object in the storage if it wasn't previously allocated.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aId The scalar identifier.
  * @param aProcessStorage This drives the selection of the map to use to store
  *        the scalar data coming from child processes. This is only meaningful when
  *        this function is called in parent process. If that's the case, if
  *        this is not |GeckoProcessType_Default|, the process id is used to
  *        allocate and store the scalars.
  * @param aRes The output variable that stores scalar object.
  * @return
  *   NS_ERROR_INVALID_ARG if the scalar id is unknown.
  *   NS_ERROR_NOT_AVAILABLE if the scalar is expired.
  *   NS_OK if the scalar was found. If that's the case, aResult contains a
  *   valid pointer to a scalar type.
  */
 nsresult
-internal_GetScalarByEnum(const ScalarKey& aId,
+internal_GetScalarByEnum(const StaticMutexAutoLock& lock,
+                         const ScalarKey& aId,
                          ProcessID aProcessStorage,
                          ScalarBase** aRet)
 {
-  if (!internal_IsValidId(aId)) {
+  if (!internal_IsValidId(lock, aId)) {
     MOZ_ASSERT(false, "Requested a scalar with an invalid id.");
     return NS_ERROR_INVALID_ARG;
   }
 
-  const BaseScalarInfo &info = internal_GetScalarInfo(aId);
+  const BaseScalarInfo &info = internal_GetScalarInfo(lock, aId);
 
   // Dynamic scalars fixup: they are always stored in the "dynamic" process.
   if (aId.dynamic) {
     aProcessStorage = ProcessID::Dynamic;
   }
 
   ScalarBase* scalar = nullptr;
   ScalarStorageMapType* scalarStorage = nullptr;
@@ -1130,58 +1138,59 @@ internal_GetScalarByEnum(const ScalarKey
   scalarStorage->Put(aId.id, scalar);
   *aRet = scalar;
   return NS_OK;
 }
 
 /**
  * Update the scalar with the provided value. This is used by the JS API.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aName The scalar name.
  * @param aType The action type for updating the scalar.
  * @param aValue The value to use for updating the scalar.
  * @return a ScalarResult error value.
  */
 ScalarResult
-internal_UpdateScalar(const nsACString& aName, ScalarActionType aType,
-                      nsIVariant* aValue)
+internal_UpdateScalar(const StaticMutexAutoLock& lock, const nsACString& aName,
+                      ScalarActionType aType, nsIVariant* aValue)
 {
   ScalarKey uniqueId;
-  nsresult rv = internal_GetEnumByScalarName(aName, &uniqueId);
+  nsresult rv = internal_GetEnumByScalarName(lock, aName, &uniqueId);
   if (NS_FAILED(rv)) {
     return (rv == NS_ERROR_FAILURE) ?
            ScalarResult::NotInitialized : ScalarResult::UnknownScalar;
   }
 
-  ScalarResult sr = internal_CanRecordScalar(uniqueId, false);
+  ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, false);
   if (sr != ScalarResult::Ok) {
     if (sr == ScalarResult::CannotRecordDataset) {
       return ScalarResult::Ok;
     }
     return sr;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
-    const BaseScalarInfo &info = internal_GetScalarInfo(uniqueId);
+    const BaseScalarInfo &info = internal_GetScalarInfo(lock, uniqueId);
     // Convert the nsIVariant to a Variant.
     mozilla::Maybe<ScalarVariant> variantValue;
     sr = GetVariantFromIVariant(aValue, info.kind, variantValue);
     if (sr != ScalarResult::Ok) {
       MOZ_ASSERT(false, "Unable to convert nsIVariant to mozilla::Variant.");
       return sr;
     }
     TelemetryIPCAccumulator::RecordChildScalarAction(
       uniqueId.id, uniqueId.dynamic, aType, variantValue.ref());
     return ScalarResult::Ok;
   }
 
   // Finally get the scalar.
   ScalarBase* scalar = nullptr;
-  rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  rv = internal_GetScalarByEnum(lock, uniqueId, ProcessID::Parent, &scalar);
   if (NS_FAILED(rv)) {
     // Don't throw on expired scalars.
     if (rv == NS_ERROR_NOT_AVAILABLE) {
       return ScalarResult::Ok;
     }
     return ScalarResult::UnknownScalar;
   }
 
@@ -1205,41 +1214,43 @@ internal_UpdateScalar(const nsACString& 
 // PRIVATE: thread-unsafe helpers for the keyed scalars
 
 namespace {
 
 /**
  * Get a keyed scalar object by its enum id. This implicitly allocates the keyed
  * scalar object in the storage if it wasn't previously allocated.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aId The scalar identifier.
  * @param aProcessStorage This drives the selection of the map to use to store
  *        the scalar data coming from child processes. This is only meaningful when
  *        this function is called in parent process. If that's the case, if
  *        this is not |GeckoProcessType_Default|, the process id is used to
  *        allocate and store the scalars.
  * @param aRet The output variable that stores scalar object.
  * @return
  *   NS_ERROR_INVALID_ARG if the scalar id is unknown or a this is a keyed string
  *                        scalar.
  *   NS_ERROR_NOT_AVAILABLE if the scalar is expired.
  *   NS_OK if the scalar was found. If that's the case, aResult contains a
  *   valid pointer to a scalar type.
  */
 nsresult
-internal_GetKeyedScalarByEnum(const ScalarKey& aId,
+internal_GetKeyedScalarByEnum(const StaticMutexAutoLock& lock,
+                              const ScalarKey& aId,
                               ProcessID aProcessStorage,
                               KeyedScalar** aRet)
 {
-  if (!internal_IsValidId(aId)) {
+  if (!internal_IsValidId(lock, aId)) {
     MOZ_ASSERT(false, "Requested a keyed scalar with an invalid id.");
     return NS_ERROR_INVALID_ARG;
   }
 
-  const BaseScalarInfo &info = internal_GetScalarInfo(aId);
+  const BaseScalarInfo &info = internal_GetScalarInfo(lock, aId);
 
   // Dynamic scalars fixup: they are always stored in the "dynamic" process.
   if (aId.dynamic) {
     aProcessStorage = ProcessID::Dynamic;
   }
 
   KeyedScalar* scalar = nullptr;
   KeyedScalarStorageMapType* scalarStorage = nullptr;
@@ -1277,59 +1288,62 @@ internal_GetKeyedScalarByEnum(const Scal
   scalarStorage->Put(aId.id, scalar);
   *aRet = scalar;
   return NS_OK;
 }
 
 /**
  * Update the keyed scalar with the provided value. This is used by the JS API.
  *
+ * @param lock Instance of a lock locking gTelemetryHistogramMutex
  * @param aName The scalar name.
  * @param aKey The key name.
  * @param aType The action type for updating the scalar.
  * @param aValue The value to use for updating the scalar.
  * @return a ScalarResult error value.
  */
 ScalarResult
-internal_UpdateKeyedScalar(const nsACString& aName, const nsAString& aKey,
+internal_UpdateKeyedScalar(const StaticMutexAutoLock& lock,
+                           const nsACString& aName, const nsAString& aKey,
                            ScalarActionType aType, nsIVariant* aValue)
 {
   ScalarKey uniqueId;
-  nsresult rv = internal_GetEnumByScalarName(aName, &uniqueId);
+  nsresult rv = internal_GetEnumByScalarName(lock, aName, &uniqueId);
   if (NS_FAILED(rv)) {
     return (rv == NS_ERROR_FAILURE) ?
            ScalarResult::NotInitialized : ScalarResult::UnknownScalar;
   }
 
-  ScalarResult sr = internal_CanRecordScalar(uniqueId, true);
+  ScalarResult sr = internal_CanRecordScalar(lock, uniqueId, true);
   if (sr != ScalarResult::Ok) {
     if (sr == ScalarResult::CannotRecordDataset) {
       return ScalarResult::Ok;
     }
     return sr;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
-    const BaseScalarInfo &info = internal_GetScalarInfo(uniqueId);
+    const BaseScalarInfo &info = internal_GetScalarInfo(lock, uniqueId);
     // Convert the nsIVariant to a Variant.
     mozilla::Maybe<ScalarVariant> variantValue;
     sr = GetVariantFromIVariant(aValue, info.kind, variantValue);
     if (sr != ScalarResult::Ok) {
       MOZ_ASSERT(false, "Unable to convert nsIVariant to mozilla::Variant.");
       return sr;
     }
     TelemetryIPCAccumulator::RecordChildKeyedScalarAction(
       uniqueId.id, uniqueId.dynamic, aKey, aType, variantValue.ref());
     return ScalarResult::Ok;
   }
 
   // Finally get the scalar.
   KeyedScalar* scalar = nullptr;
-  rv = internal_GetKeyedScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  rv = internal_GetKeyedScalarByEnum(lock, uniqueId, ProcessID::Parent,
+                                     &scalar);
   if (NS_FAILED(rv)) {
     // Don't throw on expired scalars.
     if (rv == NS_ERROR_NOT_AVAILABLE) {
       return ScalarResult::Ok;
     }
     return ScalarResult::UnknownScalar;
   }
 
@@ -1343,17 +1357,18 @@ internal_UpdateKeyedScalar(const nsACStr
   return scalar->SetMaximum(aKey, aValue);
 }
 
 /**
  * Helper function to convert an array of |DynamicScalarInfo|
  * to |DynamicScalarDefinition| used by the IPC calls.
  */
 void
-internal_DynamicScalarToIPC(const nsTArray<DynamicScalarInfo>& aDynamicScalarInfos,
+internal_DynamicScalarToIPC(const StaticMutexAutoLock& lock,
+                            const nsTArray<DynamicScalarInfo>& aDynamicScalarInfos,
                             nsTArray<DynamicScalarDefinition>& aIPCDefs)
 {
   for (auto info : aDynamicScalarInfos) {
     DynamicScalarDefinition stubDefinition;
     stubDefinition.type = info.kind;
     stubDefinition.dataset = info.dataset;
     stubDefinition.expired = info.mDynamicExpiration;
     stubDefinition.keyed = info.keyed;
@@ -1362,27 +1377,28 @@ internal_DynamicScalarToIPC(const nsTArr
   }
 }
 
 /**
  * Broadcasts the dynamic scalar definitions to all the other
  * content processes.
  */
 void
-internal_BroadcastDefinitions(const nsTArray<DynamicScalarInfo>& scalarInfos)
+internal_BroadcastDefinitions(const StaticMutexAutoLock& lock,
+                              const nsTArray<DynamicScalarInfo>& scalarInfos)
 {
   nsTArray<mozilla::dom::ContentParent*> parents;
   mozilla::dom::ContentParent::GetAll(parents);
   if (!parents.Length()) {
      return;
   }
 
   // Convert the internal scalar representation to a stripped down IPC one.
   nsTArray<DynamicScalarDefinition> ipcDefinitions;
-  internal_DynamicScalarToIPC(scalarInfos, ipcDefinitions);
+  internal_DynamicScalarToIPC(lock, scalarInfos, ipcDefinitions);
 
   // Broadcast the definitions to the other content processes.
   for (auto parent : parents) {
       mozilla::Unused << parent->SendAddDynamicScalars(ipcDefinitions);
   }
 }
 
 ScalarResult
@@ -1496,17 +1512,18 @@ TelemetryScalar::Add(const nsACString& a
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateScalar(aName, ScalarActionType::eAdd, unpackedVal);
+    sr = internal_UpdateScalar(locker, aName, ScalarActionType::eAdd,
+                               unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1533,17 +1550,19 @@ TelemetryScalar::Add(const nsACString& a
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eAdd, unpackedVal);
+    sr = internal_UpdateKeyedScalar(locker, aName, aKey,
+                                    ScalarActionType::eAdd,
+                                    unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1561,31 +1580,32 @@ TelemetryScalar::Add(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, false) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, false) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildScalarAction(uniqueId.id, uniqueId.dynamic,
                                                      ScalarActionType::eAdd,
                                                      ScalarVariant(aValue));
     return;
   }
 
   ScalarBase* scalar = nullptr;
-  nsresult rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                         &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->AddValue(aValue);
 }
 
 /**
@@ -1602,30 +1622,32 @@ TelemetryScalar::Add(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, true) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, true) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildKeyedScalarAction(uniqueId.id, uniqueId.dynamic,
       aKey, ScalarActionType::eAdd, ScalarVariant(aValue));
     return;
   }
 
   KeyedScalar* scalar = nullptr;
-  nsresult rv = internal_GetKeyedScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
+                                              ProcessID::Parent,
+                                              &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->AddValue(aKey, aValue);
 }
 
 /**
@@ -1647,17 +1669,18 @@ TelemetryScalar::Set(const nsACString& a
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateScalar(aName, ScalarActionType::eSet, unpackedVal);
+    sr = internal_UpdateScalar(locker, aName, ScalarActionType::eSet,
+                               unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1684,17 +1707,19 @@ TelemetryScalar::Set(const nsACString& a
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eSet, unpackedVal);
+    sr = internal_UpdateKeyedScalar(locker, aName, aKey,
+                                    ScalarActionType::eSet,
+                                    unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1712,31 +1737,32 @@ TelemetryScalar::Set(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, false) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, false) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildScalarAction(uniqueId.id, uniqueId.dynamic,
                                                      ScalarActionType::eSet,
                                                      ScalarVariant(aValue));
     return;
   }
 
   ScalarBase* scalar = nullptr;
-  nsresult rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                         &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetValue(aValue);
 }
 
 /**
@@ -1751,31 +1777,32 @@ TelemetryScalar::Set(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, false) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, false) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildScalarAction(uniqueId.id, uniqueId.dynamic,
                                                      ScalarActionType::eSet,
                                                      ScalarVariant(nsString(aValue)));
     return;
   }
 
   ScalarBase* scalar = nullptr;
-  nsresult rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                         &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetValue(aValue);
 }
 
 /**
@@ -1790,31 +1817,32 @@ TelemetryScalar::Set(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, false) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, false) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildScalarAction(uniqueId.id, uniqueId.dynamic,
                                                      ScalarActionType::eSet,
                                                      ScalarVariant(aValue));
     return;
   }
 
   ScalarBase* scalar = nullptr;
-  nsresult rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                         &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetValue(aValue);
 }
 
 /**
@@ -1831,30 +1859,32 @@ TelemetryScalar::Set(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, true) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, true) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildKeyedScalarAction(uniqueId.id, uniqueId.dynamic,
       aKey, ScalarActionType::eSet, ScalarVariant(aValue));
     return;
   }
 
   KeyedScalar* scalar = nullptr;
-  nsresult rv = internal_GetKeyedScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
+                                              ProcessID::Parent,
+                                              &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetValue(aKey, aValue);
 }
 
 /**
@@ -1871,30 +1901,32 @@ TelemetryScalar::Set(mozilla::Telemetry:
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, true) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, true) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildKeyedScalarAction(uniqueId.id, uniqueId.dynamic,
       aKey, ScalarActionType::eSet, ScalarVariant(aValue));
     return;
   }
 
   KeyedScalar* scalar = nullptr;
-  nsresult rv = internal_GetKeyedScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId,
+                                              ProcessID::Parent,
+                                              &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetValue(aKey, aValue);
 }
 
 /**
@@ -1916,17 +1948,18 @@ TelemetryScalar::SetMaximum(const nsACSt
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateScalar(aName, ScalarActionType::eSetMaximum, unpackedVal);
+    sr = internal_UpdateScalar(locker, aName, ScalarActionType::eSetMaximum,
+                               unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1953,17 +1986,19 @@ TelemetryScalar::SetMaximum(const nsACSt
   if (NS_FAILED(rv)) {
     internal_LogScalarError(aName, ScalarResult::CannotUnpackVariant);
     return NS_OK;
   }
 
   ScalarResult sr;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-    sr = internal_UpdateKeyedScalar(aName, aKey, ScalarActionType::eSetMaximum, unpackedVal);
+    sr = internal_UpdateKeyedScalar(locker, aName, aKey,
+                                    ScalarActionType::eSetMaximum,
+                                    unpackedVal);
   }
 
   // Warn the user about the error if we need to.
   if (sr != ScalarResult::Ok) {
     internal_LogScalarError(aName, sr);
   }
 
   return NS_OK;
@@ -1981,31 +2016,32 @@ TelemetryScalar::SetMaximum(mozilla::Tel
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, false) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, false) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildScalarAction(uniqueId.id, uniqueId.dynamic,
                                                      ScalarActionType::eSetMaximum,
                                                      ScalarVariant(aValue));
     return;
   }
 
   ScalarBase* scalar = nullptr;
-  nsresult rv = internal_GetScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                         &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetMaximum(aValue);
 }
 
 /**
@@ -2022,30 +2058,31 @@ TelemetryScalar::SetMaximum(mozilla::Tel
   if (NS_WARN_IF(!IsValidEnumId(aId))) {
     MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
     return;
   }
 
   ScalarKey uniqueId{static_cast<uint32_t>(aId), false};
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
 
-  if (internal_CanRecordScalar(uniqueId, true) != ScalarResult::Ok) {
+  if (internal_CanRecordScalar(locker, uniqueId, true) != ScalarResult::Ok) {
     // We can't record this scalar. Bail out.
     return;
   }
 
   // Accumulate in the child process if needed.
   if (!XRE_IsParentProcess()) {
     TelemetryIPCAccumulator::RecordChildKeyedScalarAction(uniqueId.id, uniqueId.dynamic,
       aKey, ScalarActionType::eSetMaximum, ScalarVariant(aValue));
     return;
   }
 
   KeyedScalar* scalar = nullptr;
-  nsresult rv = internal_GetKeyedScalarByEnum(uniqueId, ProcessID::Parent, &scalar);
+  nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId, ProcessID::Parent,
+                                              &scalar);
   if (NS_FAILED(rv)) {
     return;
   }
 
   scalar->SetMaximum(aKey, aValue);
 }
 
 /**
@@ -2094,17 +2131,18 @@ TelemetryScalar::CreateSnapshots(unsigne
       bool isDynamicProcess = ProcessID::Dynamic == static_cast<ProcessID>(iter.Key());
 
       // Iterate each available child storage.
       for (auto childIter = scalarStorage->Iter(); !childIter.Done(); childIter.Next()) {
         ScalarBase* scalar = static_cast<ScalarBase*>(childIter.Data());
 
         // Get the informations for this scalar.
         const BaseScalarInfo& info =
-          internal_GetScalarInfo(ScalarKey{childIter.Key(), isDynamicProcess});
+          internal_GetScalarInfo(locker, ScalarKey{childIter.Key(),
+                                 isDynamicProcess});
 
         // Serialize the scalar if it's in the desired dataset.
         if (IsInDataset(info.dataset, aDataset)) {
           // Get the scalar value.
           nsCOMPtr<nsIVariant> scalarValue;
           nsresult rv = scalar->GetValue(scalarValue);
           if (NS_FAILED(rv)) {
             return rv;
@@ -2201,17 +2239,18 @@ TelemetryScalar::CreateKeyedSnapshots(un
       // Are we in the "Dynamic" process?
       bool isDynamicProcess = ProcessID::Dynamic == static_cast<ProcessID>(iter.Key());
 
       for (auto childIter = scalarStorage->Iter(); !childIter.Done(); childIter.Next()) {
         KeyedScalar* scalar = static_cast<KeyedScalar*>(childIter.Data());
 
         // Get the informations for this scalar.
         const BaseScalarInfo& info =
-          internal_GetScalarInfo(ScalarKey{childIter.Key(), isDynamicProcess});
+          internal_GetScalarInfo(locker, ScalarKey{childIter.Key(),
+                                 isDynamicProcess});
 
         // Serialize the scalar if it's in the desired dataset.
         if (IsInDataset(info.dataset, aDataset)) {
           // Get the keys for this scalar.
           nsTArray<KeyedScalar::KeyValuePair> scalarKeyedData;
           nsresult rv = scalar->GetValue(scalarKeyedData);
           if (NS_FAILED(rv)) {
             return rv;
@@ -2384,27 +2423,27 @@ TelemetryScalar::RegisterScalars(const n
     });
   }
 
   // Register the dynamic definition on the parent process.
   ScalarResult res = ScalarResult::Ok;
   {
     StaticMutexAutoLock locker(gTelemetryScalarsMutex);
     res = ::internal_RegisterScalars(locker, newScalarInfos);
-  }
+
 
-  if (res == ScalarResult::AlreadyRegistered) {
-    JS_ReportErrorASCII(cx, "Attempt to register a scalar that is already registered.");
-    return NS_ERROR_INVALID_ARG;
+    if (res == ScalarResult::AlreadyRegistered) {
+      JS_ReportErrorASCII(cx, "Attempt to register a scalar that is already registered.");
+      return NS_ERROR_INVALID_ARG;
+    }
+
+    // Propagate the registration to all the content-processes. Please note that
+    // this does not require to hold the mutex.
+    ::internal_BroadcastDefinitions(locker, newScalarInfos);
   }
-
-  // Propagate the registration to all the content-processes. Please note that
-  // this does not require to hold the mutex.
-  ::internal_BroadcastDefinitions(newScalarInfos);
-
   return NS_OK;
 }
 
 /**
  * Resets all the stored scalars. This is intended to be only used in tests.
  */
 void
 TelemetryScalar::ClearScalars()
@@ -2453,55 +2492,56 @@ TelemetryScalar::GetScalarSizesOfIncludi
 
 void
 TelemetryScalar::UpdateChildData(ProcessID aProcessType,
                                  const nsTArray<mozilla::Telemetry::ScalarAction>& aScalarActions)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "The stored child processes scalar data must be updated from the parent process.");
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-  if (!internal_CanRecordBase()) {
+  if (!internal_CanRecordBase(locker)) {
     return;
   }
 
   for (auto& upd : aScalarActions) {
     ScalarKey uniqueId{upd.mId, upd.mDynamic};
-    if (NS_WARN_IF(!internal_IsValidId(uniqueId))) {
+    if (NS_WARN_IF(!internal_IsValidId(locker, uniqueId))) {
       MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
       continue;
     }
 
-    if (internal_IsKeyedScalar(uniqueId)) {
+    if (internal_IsKeyedScalar(locker, uniqueId)) {
       continue;
     }
 
     // Are we allowed to record this scalar? We don't need to check for
     // allowed processes here, that's taken care of when recording
     // in child processes.
-    if (!internal_CanRecordForScalarID(uniqueId)) {
+    if (!internal_CanRecordForScalarID(locker, uniqueId)) {
       continue;
     }
 
     // Refresh the data in the parent process with the data coming from the child
     // processes.
     ScalarBase* scalar = nullptr;
-    nsresult rv = internal_GetScalarByEnum(uniqueId, aProcessType, &scalar);
+    nsresult rv = internal_GetScalarByEnum(locker, uniqueId, aProcessType,
+                                           &scalar);
     if (NS_FAILED(rv)) {
       NS_WARNING("NS_FAILED internal_GetScalarByEnum for CHILD");
       continue;
     }
 
     if (upd.mData.isNothing()) {
       MOZ_ASSERT(false, "There is no data in the ScalarActionType.");
       continue;
     }
 
     // Get the type of this scalar from the scalar ID. We already checked
     // for its validity a few lines above.
-    const uint32_t scalarType = internal_GetScalarInfo(uniqueId).kind;
+    const uint32_t scalarType = internal_GetScalarInfo(locker, uniqueId).kind;
 
     // Extract the data from the mozilla::Variant.
     switch (upd.mActionType)
     {
       case ScalarActionType::eSet:
         {
           switch (scalarType)
           {
@@ -2545,55 +2585,56 @@ TelemetryScalar::UpdateChildData(Process
 
 void
 TelemetryScalar::UpdateChildKeyedData(ProcessID aProcessType,
                                       const nsTArray<mozilla::Telemetry::KeyedScalarAction>& aScalarActions)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "The stored child processes keyed scalar data must be updated from the parent process.");
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-  if (!internal_CanRecordBase()) {
+  if (!internal_CanRecordBase(locker)) {
     return;
   }
 
   for (auto& upd : aScalarActions) {
     ScalarKey uniqueId{upd.mId, upd.mDynamic};
-    if (NS_WARN_IF(!internal_IsValidId(uniqueId))) {
+    if (NS_WARN_IF(!internal_IsValidId(locker, uniqueId))) {
       MOZ_ASSERT_UNREACHABLE("Scalar usage requires valid ids.");
       continue;
     }
 
-    if (!internal_IsKeyedScalar(uniqueId)) {
+    if (!internal_IsKeyedScalar(locker, uniqueId)) {
       continue;
     }
 
     // Are we allowed to record this scalar? We don't need to check for
     // allowed processes here, that's taken care of when recording
     // in child processes.
-    if (!internal_CanRecordForScalarID(uniqueId)) {
+    if (!internal_CanRecordForScalarID(locker, uniqueId)) {
       continue;
     }
 
     // Refresh the data in the parent process with the data coming from the child
     // processes.
     KeyedScalar* scalar = nullptr;
-    nsresult rv = internal_GetKeyedScalarByEnum(uniqueId, aProcessType, &scalar);
+    nsresult rv = internal_GetKeyedScalarByEnum(locker, uniqueId, aProcessType,
+                                                &scalar);
     if (NS_FAILED(rv)) {
       NS_WARNING("NS_FAILED internal_GetScalarByEnum for CHILD");
       continue;
     }
 
     if (upd.mData.isNothing()) {
       MOZ_ASSERT(false, "There is no data in the KeyedScalarAction.");
       continue;
     }
 
     // Get the type of this scalar from the scalar ID. We already checked
     // for its validity a few lines above.
-    const uint32_t scalarType = internal_GetScalarInfo(uniqueId).kind;
+    const uint32_t scalarType = internal_GetScalarInfo(locker, uniqueId).kind;
 
     // Extract the data from the mozilla::Variant.
     switch (upd.mActionType)
     {
       case ScalarActionType::eSet:
         {
           switch (scalarType)
           {
@@ -2636,48 +2677,48 @@ TelemetryScalar::UpdateChildKeyedData(Pr
 
 void
 TelemetryScalar::RecordDiscardedData(ProcessID aProcessType,
                                      const mozilla::Telemetry::DiscardedData& aDiscardedData)
 {
   MOZ_ASSERT(XRE_IsParentProcess(),
              "Discarded Data must be updated from the parent process.");
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-  if (!internal_CanRecordBase()) {
+  if (!internal_CanRecordBase(locker)) {
     return;
   }
 
   ScalarBase* scalar = nullptr;
   mozilla::DebugOnly<nsresult> rv;
 
-  rv = internal_GetScalarByEnum(
+  rv = internal_GetScalarByEnum(locker,
     ScalarKey{static_cast<uint32_t>(ScalarID::TELEMETRY_DISCARDED_ACCUMULATIONS), false},
     aProcessType, &scalar);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   scalar->AddValue(aDiscardedData.mDiscardedHistogramAccumulations);
 
-  rv = internal_GetScalarByEnum(
+  rv = internal_GetScalarByEnum(locker,
     ScalarKey{static_cast<uint32_t>(ScalarID::TELEMETRY_DISCARDED_KEYED_ACCUMULATIONS), false},
     aProcessType, &scalar);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   scalar->AddValue(aDiscardedData.mDiscardedKeyedHistogramAccumulations);
 
-  rv = internal_GetScalarByEnum(
+  rv = internal_GetScalarByEnum(locker,
     ScalarKey{static_cast<uint32_t>(ScalarID::TELEMETRY_DISCARDED_SCALAR_ACTIONS), false},
     aProcessType, &scalar);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   scalar->AddValue(aDiscardedData.mDiscardedScalarActions);
 
-  rv = internal_GetScalarByEnum(
+  rv = internal_GetScalarByEnum(locker,
     ScalarKey{static_cast<uint32_t>(ScalarID::TELEMETRY_DISCARDED_KEYED_SCALAR_ACTIONS), false},
     aProcessType, &scalar);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   scalar->AddValue(aDiscardedData.mDiscardedKeyedScalarActions);
 
-  rv = internal_GetScalarByEnum(
+  rv = internal_GetScalarByEnum(locker,
     ScalarKey{static_cast<uint32_t>(ScalarID::TELEMETRY_DISCARDED_CHILD_EVENTS), false},
     aProcessType, &scalar);
   MOZ_ASSERT(NS_SUCCEEDED(rv));
   scalar->AddValue(aDiscardedData.mDiscardedChildEvents);
 }
 
 /**
  * Get the dynamic scalar definitions in an IPC-friendly
@@ -2689,17 +2730,17 @@ TelemetryScalar::GetDynamicScalarDefinit
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   if (!gDynamicScalarInfo) {
     // Don't have dynamic scalar definitions. Bail out!
     return;
   }
 
   StaticMutexAutoLock locker(gTelemetryScalarsMutex);
-  internal_DynamicScalarToIPC(*gDynamicScalarInfo, aDefArray);
+  internal_DynamicScalarToIPC(locker, *gDynamicScalarInfo, aDefArray);
 }
 
 /**
  * This adds the dynamic scalar definitions coming from
  * the parent process to this child process.
  */
 void
 TelemetryScalar::AddDynamicScalarDefinitions(