Bug 1353936 - Use PREF_RegisterPriorityCallback from Add*VarCache. r=froydnj
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Wed, 12 Apr 2017 00:17:52 +0900
changeset 353076 60b966337731cd2ff219a5bda2bd03a596ef12fd
parent 353075 86e51288bb415068998208765fc4712a40e20850
child 353077 edbc280464588c955d0b184e37b661cc5985ccc7
push id31656
push userihsiao@mozilla.com
push dateFri, 14 Apr 2017 09:10:41 +0000
treeherdermozilla-central@cda24082bff8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1353936
milestone55.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 1353936 - Use PREF_RegisterPriorityCallback from Add*VarCache. r=froydnj MozReview-Commit-ID: LOxPTBqol9X
modules/libpref/Preferences.cpp
modules/libpref/prefapi.h
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -1714,16 +1714,44 @@ Preferences::RemoveObservers(nsIObserver
 
   for (uint32_t i = 0; aPrefs[i]; i++) {
     nsresult rv = RemoveObserver(aObserver, aPrefs[i]);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
+static void NotifyObserver(const char* aPref, void* aClosure)
+{
+  nsCOMPtr<nsIObserver> observer = static_cast<nsIObserver*>(aClosure);
+  observer->Observe(nullptr, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID,
+                    NS_ConvertASCIItoUTF16(aPref).get());
+}
+
+static void RegisterPriorityCallback(PrefChangedFunc aCallback,
+                                     const char* aPref,
+                                     void* aClosure)
+{
+  MOZ_ASSERT(Preferences::IsServiceAvailable());
+
+  ValueObserverHashKey hashKey(aPref, aCallback, Preferences::ExactMatch);
+  RefPtr<ValueObserver> observer;
+  gObserverTable->Get(&hashKey, getter_AddRefs(observer));
+  if (observer) {
+    observer->AppendClosure(aClosure);
+    return;
+  }
+
+  observer = new ValueObserver(aPref, aCallback, Preferences::ExactMatch);
+  observer->AppendClosure(aClosure);
+  PREF_RegisterPriorityCallback(aPref, NotifyObserver,
+                                static_cast<nsIObserver*>(observer));
+  gObserverTable->Put(observer, observer);
+}
+
 // static
 nsresult
 Preferences::RegisterCallback(PrefChangedFunc aCallback,
                               const char* aPref,
                               void* aClosure,
                               MatchKind aMatchKind)
 {
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
@@ -1781,16 +1809,20 @@ Preferences::UnregisterCallback(PrefChan
   observer->RemoveClosure(aClosure);
   if (observer->HasNoClosures()) {
     // Delete the callback since its list of closures is empty.
     gObserverTable->Remove(observer);
   }
   return NS_OK;
 }
 
+// We insert cache observers using RegisterPriorityCallback to ensure they
+// are called prior to ordinary pref observers.  Doing this ensures that
+// ordinary observers will never get stale values from cache variables.
+
 static void BoolVarChanged(const char* aPref, void* aClosure)
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *((bool*)cache->cacheLocation) =
     Preferences::GetBool(aPref, cache->defaultValueBool);
 }
 
 // static
@@ -1804,17 +1836,18 @@ Preferences::AddBoolVarCache(bool* aCach
 #ifdef DEBUG
   AssertNotAlreadyCached("bool", aPref, aCache);
 #endif
   *aCache = GetBool(aPref, aDefault);
   CacheData* data = new CacheData();
   data->cacheLocation = aCache;
   data->defaultValueBool = aDefault;
   gCacheData->AppendElement(data);
-  return RegisterCallback(BoolVarChanged, aPref, data, ExactMatch);
+  RegisterPriorityCallback(BoolVarChanged, aPref, data);
+  return NS_OK;
 }
 
 static void IntVarChanged(const char* aPref, void* aClosure)
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *((int32_t*)cache->cacheLocation) =
     Preferences::GetInt(aPref, cache->defaultValueInt);
 }
@@ -1830,17 +1863,18 @@ Preferences::AddIntVarCache(int32_t* aCa
 #ifdef DEBUG
   AssertNotAlreadyCached("int", aPref, aCache);
 #endif
   *aCache = Preferences::GetInt(aPref, aDefault);
   CacheData* data = new CacheData();
   data->cacheLocation = aCache;
   data->defaultValueInt = aDefault;
   gCacheData->AppendElement(data);
-  return RegisterCallback(IntVarChanged, aPref, data, ExactMatch);
+  RegisterPriorityCallback(IntVarChanged, aPref, data);
+  return NS_OK;
 }
 
 static void UintVarChanged(const char* aPref, void* aClosure)
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *((uint32_t*)cache->cacheLocation) =
     Preferences::GetUint(aPref, cache->defaultValueUint);
 }
@@ -1856,17 +1890,18 @@ Preferences::AddUintVarCache(uint32_t* a
 #ifdef DEBUG
   AssertNotAlreadyCached("uint", aPref, aCache);
 #endif
   *aCache = Preferences::GetUint(aPref, aDefault);
   CacheData* data = new CacheData();
   data->cacheLocation = aCache;
   data->defaultValueUint = aDefault;
   gCacheData->AppendElement(data);
-  return RegisterCallback(UintVarChanged, aPref, data, ExactMatch);
+  RegisterPriorityCallback(UintVarChanged, aPref, data);
+  return NS_OK;
 }
 
 template <MemoryOrdering Order>
 static void AtomicUintVarChanged(const char* aPref, void* aClosure)
 {
   CacheData* cache = static_cast<CacheData*>(aClosure);
   *((Atomic<uint32_t, Order>*)cache->cacheLocation) =
     Preferences::GetUint(aPref, cache->defaultValueUint);
@@ -1884,17 +1919,18 @@ Preferences::AddAtomicUintVarCache(Atomi
 #ifdef DEBUG
   AssertNotAlreadyCached("uint", aPref, aCache);
 #endif
   *aCache = Preferences::GetUint(aPref, aDefault);
   CacheData* data = new CacheData();
   data->cacheLocation = aCache;
   data->defaultValueUint = aDefault;
   gCacheData->AppendElement(data);
-  return RegisterCallback(AtomicUintVarChanged<Order>, aPref, data, ExactMatch);
+  RegisterPriorityCallback(AtomicUintVarChanged<Order>, aPref, data);
+  return NS_OK;
 }
 
 // Since the definition of this template function is not in a header file,
 // we need to explicitly specify the instantiations that are required.
 // Currently only the order=Relaxed variant is needed.
 template
 nsresult Preferences::AddAtomicUintVarCache(Atomic<uint32_t,Relaxed>*,
                                             const char*, uint32_t);
@@ -1917,17 +1953,18 @@ Preferences::AddFloatVarCache(float* aCa
 #ifdef DEBUG
   AssertNotAlreadyCached("float", aPref, aCache);
 #endif
   *aCache = Preferences::GetFloat(aPref, aDefault);
   CacheData* data = new CacheData();
   data->cacheLocation = aCache;
   data->defaultValueFloat = aDefault;
   gCacheData->AppendElement(data);
-  return RegisterCallback(FloatVarChanged, aPref, data, ExactMatch);
+  RegisterPriorityCallback(FloatVarChanged, aPref, data);
+  return NS_OK;
 }
 
 // static
 nsresult
 Preferences::GetDefaultBool(const char* aPref, bool* aResult)
 {
   NS_PRECONDITION(aResult, "aResult must not be NULL");
   NS_ENSURE_TRUE(InitStaticMembers(), NS_ERROR_NOT_AVAILABLE);
--- a/modules/libpref/prefapi.h
+++ b/modules/libpref/prefapi.h
@@ -225,16 +225,19 @@ typedef void (*PrefChangedFunc) (const c
 /*
 // <font color=blue>
 // Register a callback.  This takes a node in the preference tree and will
 // call the callback function if anything below that node is modified.
 // Unregister returns PREF_NOERROR if a callback was found that
 // matched all the parameters; otherwise it returns PREF_ERROR.
 // </font>
 */
+void PREF_RegisterPriorityCallback(const char* domain,
+                                   PrefChangedFunc callback,
+                                   void* instance_data );
 void PREF_RegisterCallback(const char* domain,
                            PrefChangedFunc callback, void* instance_data );
 nsresult PREF_UnregisterCallback(const char* domain,
                                  PrefChangedFunc callback, void* instance_data );
 
 /*
  * Used by nsPrefService as the callback function of the 'pref' parser
  */