Bug 1550422 - P11. Add atomic float preferences support. r?njn! draft
authorJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 14 May 2019 19:49:33 +1000
changeset 2008588 1f51118a5843147af0784215fab26007dcda31e9
parent 2008587 7475652b856d0b9a584d454a2fda7e482556b497
child 2008589 0f5c7e2c981433e460b7afab96cfe4d1aa4f69ad
push id363925
push userjyavenard@mozilla.com
push dateSat, 18 May 2019 07:53:18 +0000
treeherdertry@5082cd581229 [default view] [failures only]
reviewersnjn
bugs1550422
milestone68.0a1
Bug 1550422 - P11. Add atomic float preferences support. r?njn! Differential Revision: https://phabricator.services.mozilla.com/D31255
modules/libpref/Preferences.cpp
modules/libpref/Preferences.h
modules/libpref/StaticPrefs.h
modules/libpref/test/gtest/CallbackAndVarCacheOrder.cpp
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -5279,16 +5279,41 @@ nsresult Preferences::AddFloatVarCache(f
   data->mDefaultValueFloat = aDefault;
   CacheDataAppendElement(data);
   Preferences::RegisterCallback(FloatVarChanged, aPref, data,
                                 Preferences::ExactMatch,
                                 /* isPriority */ true);
   return NS_OK;
 }
 
+static void AtomicFloatVarChanged(const char* aPref, void* aClosure) {
+  CacheData* cache = static_cast<CacheData*>(aClosure);
+  *static_cast<std::atomic<float>*>(cache->mCacheLocation) =
+      Preferences::GetFloat(aPref, cache->mDefaultValueFloat);
+}
+
+/* static */
+nsresult Preferences::AddAtomicFloatVarCache(std::atomic<float>* aCache,
+                                             const nsACString& aPref,
+                                             float aDefault,
+                                             bool aSkipAssignment) {
+  AssertNotAlreadyCached("float", aPref, aCache);
+  if (!aSkipAssignment) {
+    *aCache = GetFloat(PromiseFlatCString(aPref).get(), aDefault);
+  }
+  CacheData* data = new CacheData();
+  data->mCacheLocation = aCache;
+  data->mDefaultValueFloat = aDefault;
+  CacheDataAppendElement(data);
+  Preferences::RegisterCallback(AtomicFloatVarChanged, aPref, data,
+                                Preferences::ExactMatch,
+                                /* isPriority */ true);
+  return NS_OK;
+}
+
 // For a VarCache pref like this:
 //
 //   VARCACHE_PREF("my.varcache", my_varcache, int32_t, 99)
 //
 // we generate a static variable definition:
 //
 //   int32_t StaticPrefs::sVarCache_my_varcache(99);
 //
@@ -5431,16 +5456,28 @@ static void InitVarCachePref(const nsACS
     SetPref_float(PromiseFlatCString(aName).get(), aDefaultValue);
   }
   *aCache = aDefaultValue;
   if (aIsStartup) {
     Preferences::AddFloatVarCache(aCache, aName, aDefaultValue, true);
   }
 }
 
+static void InitVarCachePref(const nsACString& aName,
+                             std::atomic<float>* aCache, float aDefaultValue,
+                             bool aIsStartup, bool aSetValue) {
+  if (aSetValue) {
+    SetPref_float(PromiseFlatCString(aName).get(), aDefaultValue);
+  }
+  *aCache = aDefaultValue;
+  if (aIsStartup) {
+    Preferences::AddAtomicFloatVarCache(aCache, aName, aDefaultValue, true);
+  }
+}
+
 /* static */
 void StaticPrefs::InitAll(bool aIsStartup) {
   // For prefs like these:
   //
   //   PREF("foo.bar.baz", bool, true)
   //   VARCACHE_PREF("my.varcache", my_varcache, int32_t, 99)
   //
   // we generate registration calls:
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -17,16 +17,17 @@
 #include "mozilla/StaticPtr.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsWeakReference.h"
+#include <atomic>
 
 class nsIFile;
 
 // The callback function will get passed the pref name which triggered the call
 // and the void* data which was passed to the registered callback function.
 typedef void (*PrefChangedFunc)(const char* aPref, void* aData);
 
 class nsPrefBranch;
@@ -500,16 +501,21 @@ class Preferences final : public nsIPref
   static nsresult AddAtomicUintVarCache(Atomic<uint32_t, Order>* aVariable,
                                         const nsACString& aPref,
                                         uint32_t aDefault = 0,
                                         bool aSkipAssignment = false);
   static nsresult AddFloatVarCache(float* aVariable, const nsACString& aPref,
                                    float aDefault = 0.0f,
                                    bool aSkipAssignment = false);
 
+  static nsresult AddAtomicFloatVarCache(std::atomic<float>* aVariable,
+                                         const nsACString& aPref,
+                                         float aDefault = 0.0f,
+                                         bool aSkipAssignment = false);
+
   template <int N>
   static nsresult AddBoolVarCache(bool* aVariable, const char (&aPref)[N],
                                   bool aDefault = false,
                                   bool aSkipAssignment = false) {
     return AddBoolVarCache(aVariable, nsLiteralCString(aPref), aDefault,
                            aSkipAssignment);
   }
   template <MemoryOrdering Order, int N>
@@ -553,16 +559,25 @@ class Preferences final : public nsIPref
   template <int N>
   static nsresult AddFloatVarCache(float* aVariable, const char (&aPref)[N],
                                    float aDefault = 0.0f,
                                    bool aSkipAssignment = false) {
     return AddFloatVarCache(aVariable, nsLiteralCString(aPref), aDefault,
                             aSkipAssignment);
   }
 
+  template <int N>
+  static nsresult AddAtomicFloatVarCache(std::atomic<float>* aVariable,
+                                         const char (&aPref)[N],
+                                         float aDefault = 0.0f,
+                                         bool aSkipAssignment = false) {
+    return AddAtomicFloatVarCache(aVariable, nsLiteralCString(aPref), aDefault,
+                                  aSkipAssignment);
+  }
+
   // When a content process is created these methods are used to pass changed
   // prefs in bulk from the parent process, via shared memory.
   static void SerializePreferences(nsCString& aStr);
   static void DeserializePreferences(char* aStr, size_t aPrefsLen);
 
   static mozilla::ipc::FileDescriptor EnsureSnapshot(size_t* aSize);
   static void InitSnapshot(const mozilla::ipc::FileDescriptor&, size_t aSize);
 
--- a/modules/libpref/StaticPrefs.h
+++ b/modules/libpref/StaticPrefs.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_StaticPrefs_h
 #define mozilla_StaticPrefs_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/TypeTraits.h"
 #include "MainThreadUtils.h"
+#include <atomic>
 
 namespace mozilla {
 
 // These typedefs are for use within StaticPrefList.h.
 
 typedef const char* String;
 
 typedef Atomic<bool, Relaxed> RelaxedAtomicBool;
@@ -27,35 +28,47 @@ typedef Atomic<int32_t, ReleaseAcquire> 
 typedef Atomic<int32_t, SequentiallyConsistent>
     SequentiallyConsistentAtomicInt32;
 
 typedef Atomic<uint32_t, Relaxed> RelaxedAtomicUint32;
 typedef Atomic<uint32_t, ReleaseAcquire> ReleaseAcquireAtomicUint32;
 typedef Atomic<uint32_t, SequentiallyConsistent>
     SequentiallyConsistentAtomicUint32;
 
+// Atomic<float> currently doesn't work (see bug 1552086), once this tast has
+// been completed we will be able to use Atomic<float> instead.
+typedef std::atomic<float> AtomicFloat;
+
 template <typename T>
 struct StripAtomicImpl {
   typedef T Type;
 };
 
 template <typename T, MemoryOrdering Order>
 struct StripAtomicImpl<Atomic<T, Order>> {
   typedef T Type;
 };
 
 template <typename T>
+struct StripAtomicImpl<std::atomic<T>> {
+  typedef T Type;
+};
+
+template <typename T>
 using StripAtomic = typename StripAtomicImpl<T>::Type;
 
 template <typename T>
 struct IsAtomic : FalseType {};
 
 template <typename T, MemoryOrdering Order>
 struct IsAtomic<Atomic<T, Order>> : TrueType {};
 
+template <typename T>
+struct IsAtomic<std::atomic<T>> : TrueType {};
+
 class StaticPrefs {
 // For a VarCache pref like this:
 //
 //   VARCACHE_PREF("my.varcache", my_varcache, int32_t, 99)
 //
 // we generate a static variable declaration, a getter and a setter definition.
 // A StaticPref can be set by using the corresponding Set method. For
 // example, if the accessor is Foo() then calling SetFoo(...) will update
--- a/modules/libpref/test/gtest/CallbackAndVarCacheOrder.cpp
+++ b/modules/libpref/test/gtest/CallbackAndVarCacheOrder.cpp
@@ -89,16 +89,21 @@ void AddVarCacheFunc(Atomic<uint32_t, Re
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
 void AddVarCacheFunc(float* aVar, const nsCString& aPrefName) {
   nsresult rv = Preferences::AddFloatVarCache(aVar, aPrefName);
   ASSERT_TRUE(NS_SUCCEEDED(rv));
 }
 
+void AddVarCacheFunc(std::atomic<float>* aVar, const nsCString& aPrefName) {
+  nsresult rv = Preferences::AddAtomicFloatVarCache(aVar, aPrefName);
+  ASSERT_TRUE(NS_SUCCEEDED(rv));
+}
+
 template <typename T, typename U = T>
 void RunTest(const nsCString& aPrefName1, const nsCString& aPrefName2,
              T aValue1, T aValue2) {
   static U var1, var2;
   static Closure<T, U> closure1, closure2;
   nsresult rv;
 
   ASSERT_STRNE(aPrefName1.get(), aPrefName2.get());
@@ -191,9 +196,16 @@ TEST(CallbackAndVarCacheOrder, AtomicUin
 }
 
 TEST(CallbackAndVarCacheOrder, Float)
 {
   RunTest<float>(NS_LITERAL_CSTRING("test_pref.float.1"),
                  NS_LITERAL_CSTRING("test_pref.float.2"), -10.0f, 11.0f);
 }
 
+TEST(CallbackAndVarCacheOrder, AtomicFloat)
+{
+  RunTest<float, std::atomic<float>>(
+      NS_LITERAL_CSTRING("test_pref.atomic_float.1"),
+      NS_LITERAL_CSTRING("test_pref.atomic_float.2"), -12.0f, 13.0f);
+}
+
 }  // namespace mozilla