Bug 1353936 - Implement PREF_RegisterPriorityCallback. r=froydnj
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Wed, 12 Apr 2017 21:10:57 +0900
changeset 353075 86e51288bb415068998208765fc4712a40e20850
parent 353074 bec1fdf2a886c400062adb77e0bbbb807e6d2b27
child 353076 60b966337731cd2ff219a5bda2bd03a596ef12fd
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 - Implement PREF_RegisterPriorityCallback. r=froydnj MozReview-Commit-ID: 1tdE6boBUVO
modules/libpref/prefapi.cpp
--- a/modules/libpref/prefapi.cpp
+++ b/modules/libpref/prefapi.cpp
@@ -65,17 +65,18 @@ matchPrefEntry(const PLDHashEntryHdr* en
 
     const char *otherKey = reinterpret_cast<const char*>(key);
     return (strcmp(prefEntry->key, otherKey) == 0);
 }
 
 PLDHashTable*       gHashTable;
 static ArenaAllocator<8192,4> gPrefNameArena;
 
-static struct CallbackNode* gCallbacks = nullptr;
+static struct CallbackNode* gFirstCallback = nullptr;
+static struct CallbackNode* gLastPriorityNode = nullptr;
 static bool         gIsAnyPrefLocked = false;
 // These are only used during the call to pref_DoCallback
 static bool         gCallbacksInProgress = false;
 static bool         gShouldCleanupDeadNodes = false;
 
 
 static PLDHashTableOps     pref_HashTableOps = {
     PLDHashTable::HashStringKey,
@@ -152,27 +153,27 @@ void PREF_Init()
     }
 }
 
 /* Frees the callback list. */
 void PREF_Cleanup()
 {
     NS_ASSERTION(!gCallbacksInProgress,
         "PREF_Cleanup was called while gCallbacksInProgress is true!");
-    struct CallbackNode* node = gCallbacks;
+    struct CallbackNode* node = gFirstCallback;
     struct CallbackNode* next_node;
 
     while (node)
     {
         next_node = node->next;
         PL_strfree(node->domain);
         free(node);
         node = next_node;
     }
-    gCallbacks = nullptr;
+    gLastPriorityNode = gFirstCallback = nullptr;
 
     PREF_CleanupPrefs();
 }
 
 /* Frees up all the objects except the callback list. */
 void PREF_CleanupPrefs()
 {
     if (gHashTable) {
@@ -856,17 +857,17 @@ nsresult pref_HashPref(const char *key, 
     }
     return NS_OK;
 }
 
 size_t
 pref_SizeOfPrivateData(MallocSizeOf aMallocSizeOf)
 {
     size_t n = gPrefNameArena.SizeOfExcludingThis(aMallocSizeOf);
-    for (struct CallbackNode* node = gCallbacks; node; node = node->next) {
+    for (struct CallbackNode* node = gFirstCallback; node; node = node->next) {
         n += aMallocSizeOf(node);
         n += aMallocSizeOf(node->domain);
     }
     return n;
 }
 
 PrefType
 PREF_GetPrefType(const char *pref_name)
@@ -893,77 +894,108 @@ PREF_PrefIsLocked(const char *pref_name)
         }
     }
 
     return result;
 }
 
 /* Adds a node to the beginning of the callback list. */
 void
+PREF_RegisterPriorityCallback(const char *pref_node,
+                              PrefChangedFunc callback,
+                              void * instance_data)
+{
+    NS_PRECONDITION(pref_node, "pref_node must not be nullptr");
+    NS_PRECONDITION(callback, "callback must not be nullptr");
+
+    struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
+    if (node)
+    {
+        node->domain = PL_strdup(pref_node);
+        node->func = callback;
+        node->data = instance_data;
+        node->next = gFirstCallback;
+        gFirstCallback = node;
+        if (!gLastPriorityNode) {
+            gLastPriorityNode = node;
+        }
+    }
+}
+
+/* Adds a node to the end of the callback list. */
+void
 PREF_RegisterCallback(const char *pref_node,
                        PrefChangedFunc callback,
                        void * instance_data)
 {
     NS_PRECONDITION(pref_node, "pref_node must not be nullptr");
     NS_PRECONDITION(callback, "callback must not be nullptr");
 
     struct CallbackNode* node = (struct CallbackNode*) malloc(sizeof(struct CallbackNode));
     if (node)
     {
         node->domain = PL_strdup(pref_node);
         node->func = callback;
         node->data = instance_data;
-        node->next = gCallbacks;
-        gCallbacks = node;
+        if (gLastPriorityNode) {
+            node->next = gLastPriorityNode->next;
+            gLastPriorityNode->next = node;
+        } else {
+            node->next = gFirstCallback;
+            gFirstCallback = node;
+        }
     }
-    return;
 }
 
-/* Removes |node| from gCallbacks list.
+/* Removes |node| from callback list.
    Returns the node after the deleted one. */
 struct CallbackNode*
 pref_RemoveCallbackNode(struct CallbackNode* node,
                         struct CallbackNode* prev_node)
 {
     NS_PRECONDITION(!prev_node || prev_node->next == node, "invalid params");
-    NS_PRECONDITION(prev_node || gCallbacks == node, "invalid params");
+    NS_PRECONDITION(prev_node || gFirstCallback == node, "invalid params");
 
     NS_ASSERTION(!gCallbacksInProgress,
         "modifying the callback list while gCallbacksInProgress is true");
 
     struct CallbackNode* next_node = node->next;
-    if (prev_node)
+    if (prev_node) {
         prev_node->next = next_node;
-    else
-        gCallbacks = next_node;
+    } else {
+        gFirstCallback = next_node;
+    }
+    if (gLastPriorityNode == node) {
+        gLastPriorityNode = prev_node;
+    }
     PL_strfree(node->domain);
     free(node);
     return next_node;
 }
 
 /* Deletes a node from the callback list or marks it for deletion. */
 nsresult
 PREF_UnregisterCallback(const char *pref_node,
                          PrefChangedFunc callback,
                          void * instance_data)
 {
     nsresult rv = NS_ERROR_FAILURE;
-    struct CallbackNode* node = gCallbacks;
+    struct CallbackNode* node = gFirstCallback;
     struct CallbackNode* prev_node = nullptr;
 
     while (node != nullptr)
     {
         if ( node->func == callback &&
              node->data == instance_data &&
              strcmp(node->domain, pref_node) == 0)
         {
             if (gCallbacksInProgress)
             {
                 // postpone the node removal until after
-                // gCallbacks enumeration is finished.
+                // callbacks enumeration is finished.
                 node->func = nullptr;
                 gShouldCleanupDeadNodes = true;
                 prev_node = node;
                 node = node->next;
             }
             else
             {
                 node = pref_RemoveCallbackNode(node, prev_node);
@@ -986,33 +1018,33 @@ static nsresult pref_DoCallback(const ch
 
     bool reentered = gCallbacksInProgress;
     gCallbacksInProgress = true;
     // Nodes must not be deleted while gCallbacksInProgress is true.
     // Nodes that need to be deleted are marked for deletion by nulling
     // out the |func| pointer. We release them at the end of this function
     // if we haven't reentered.
 
-    for (node = gCallbacks; node != nullptr; node = node->next)
+    for (node = gFirstCallback; node != nullptr; node = node->next)
     {
         if ( node->func &&
              PL_strncmp(changed_pref,
                         node->domain,
                         strlen(node->domain)) == 0 )
         {
             (*node->func) (changed_pref, node->data);
         }
     }
 
     gCallbacksInProgress = reentered;
 
     if (gShouldCleanupDeadNodes && !gCallbacksInProgress)
     {
         struct CallbackNode* prev_node = nullptr;
-        node = gCallbacks;
+        node = gFirstCallback;
 
         while (node != nullptr)
         {
             if (!node->func)
             {
                 node = pref_RemoveCallbackNode(node, prev_node);
             }
             else