Bug 676110 - Part 3: Replace 'places-updateplaces-complete' observer notification with mozIVisitInfoCallback::handleCompletion. r=mak
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Fri, 19 Aug 2011 10:11:41 -0700
changeset 75722 d8fa1eccdbbe852a45414db3ba9a982abe9ce67f
parent 75721 ba8de1dee071c2cb926f7b618910b1b6ba16d58b
child 75723 fda809e5d6e9cffa40659b8101824001cf877377
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersmak
bugs676110
milestone9.0a1
Bug 676110 - Part 3: Replace 'places-updateplaces-complete' observer notification with mozIVisitInfoCallback::handleCompletion. r=mak
toolkit/components/places/History.cpp
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -57,19 +57,16 @@
 #include "nsNetUtil.h"
 #include "nsIXPConnect.h"
 #include "mozilla/Util.h"
 #include "nsContentUtils.h"
 
 // Initial size for the cache holding visited status observers.
 #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128
 
-// Topic used to notify that work in mozIAsyncHistory::updatePlaces is done.
-#define TOPIC_UPDATEPLACES_COMPLETE "places-updatePlaces-complete"
-
 using namespace mozilla::dom;
 
 namespace mozilla {
 namespace places {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Global Defines
 
@@ -584,16 +581,54 @@ private:
    * this object (and therefore cannot hold a strong reference to it).
    */
   mozIVisitInfoCallback* mCallback;
   VisitData mPlace;
   const nsresult mResult;
 };
 
 /**
+ * Notifies a callback object when the operation is complete.
+ */
+class NotifyCompletion : public nsRunnable
+{
+public:
+  NotifyCompletion(mozIVisitInfoCallback* aCallback)
+  : mCallback(aCallback)
+  {
+    NS_PRECONDITION(aCallback, "Must pass a non-null callback!");
+  }
+
+  NS_IMETHOD Run()
+  {
+    if (NS_IsMainThread()) {
+      (void)mCallback->HandleCompletion();
+    }
+    else {
+      (void)NS_DispatchToMainThread(this);
+
+      // Also dispatch an event to release the reference to the callback after
+      // we have run.
+      nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
+      (void)NS_ProxyRelease(mainThread, mCallback, PR_TRUE);
+    }
+    return NS_OK;
+  }
+
+private:
+  /**
+   * Callers MUST hold a strong reference to this because we may be created
+   * off of the main thread, and therefore cannot call AddRef on this object
+   * (and therefore cannot hold a strong reference to it). If invoked from a
+   * background thread, NotifyCompletion will release the reference to this.
+   */
+  mozIVisitInfoCallback* mCallback;
+};
+
+/**
  * Checks to see if we can add aURI to history, and dispatches an error to
  * aCallback (if provided) if we cannot.
  *
  * @param aURI
  *        The URI to check.
  * @param [optional] aGUID
  *        The guid of the URI to check.  This is passed back to the callback.
  * @param [optional] aCallback
@@ -1967,24 +2002,32 @@ History::UpdatePlaces(const jsval& aPlac
   // It is possible that all of the visits we were passed were dissallowed by
   // CanAddURI, which isn't an error.  If we have no visits to add, however,
   // we should not call InsertVisitedURIs::Start.
   if (visitData.Length()) {
     nsresult rv = InsertVisitedURIs::Start(dbConn, visitData, aCallback);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  // Be sure to notify that all of our operations are complete.  This is
-  // double enqueued to make sure that all database notifications and all embed
-  // or canAddURI notifications have finished.
-  nsCOMPtr<nsIEventTarget> backgroundThread = do_GetInterface(dbConn);
-  NS_ENSURE_TRUE(backgroundThread, NS_ERROR_UNEXPECTED);
-  nsRefPtr<PlacesEvent> completeEvent =
-    new PlacesEvent(TOPIC_UPDATEPLACES_COMPLETE, true);
-  (void)backgroundThread->Dispatch(completeEvent, 0);
+  // Be sure to notify that all of our operations are complete.  This
+  // is dispatched to the background thread first and redirected to the
+  // main thread from there to make sure that all database notifications
+  // and all embed or canAddURI notifications have finished.
+  if (aCallback) {
+    // NotifyCompletion does not hold a strong reference to the callback,
+    // so we have to manage it by AddRefing now. NotifyCompletion will
+    // release it for us once it has dispatched the callback to the main
+    // thread.
+    NS_ADDREF(aCallback);
+
+    nsCOMPtr<nsIEventTarget> backgroundThread = do_GetInterface(dbConn);
+    NS_ENSURE_TRUE(backgroundThread, NS_ERROR_UNEXPECTED);
+    nsCOMPtr<nsIRunnable> event = new NotifyCompletion(aCallback);
+    (void)backgroundThread->Dispatch(event, NS_DISPATCH_NORMAL);
+  }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsIObserver
 
 NS_IMETHODIMP