Bug 802239: Actually shut down storage threads. r=asuth
authorKyle Huey <khuey@kylehuey.com>
Wed, 17 Oct 2012 11:56:24 -0700
changeset 110708 df42fa3fb07f05f40d5aa09ab4787f1a76c9e0a6
parent 110707 088dfedf36d5d6de360f37f347ca87ca6c15a6ea
child 110709 756d555fc3bfab21090da03c6a7e4ed66b573761
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersasuth
bugs802239
milestone19.0a1
Bug 802239: Actually shut down storage threads. r=asuth
storage/src/mozStorageConnection.cpp
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -330,38 +330,48 @@ WaitForUnlockNotify(sqlite3* aDatabase)
 
 namespace {
 
 class AsyncCloseConnection : public nsRunnable
 {
 public:
   AsyncCloseConnection(Connection *aConnection,
                        nsIEventTarget *aCallingThread,
-                       nsIRunnable *aCallbackEvent)
+                       nsIRunnable *aCallbackEvent,
+                       already_AddRefed<nsIThread> aAsyncExecutionThread)
   : mConnection(aConnection)
   , mCallingThread(aCallingThread)
   , mCallbackEvent(aCallbackEvent)
+  , mAsyncExecutionThread(aAsyncExecutionThread)
   {
   }
 
   NS_METHOD Run()
   {
     // This event is first dispatched to the background thread to ensure that
     // all pending asynchronous events are completed, and then back to the
     // calling thread to actually close and notify.
     bool onCallingThread = false;
     (void)mCallingThread->IsOnCurrentThread(&onCallingThread);
     if (!onCallingThread) {
+#ifdef DEBUG
+      {
+        bool onAsyncThread = false;
+        (void)mAsyncExecutionThread->IsOnCurrentThread(&onAsyncThread);
+        MOZ_ASSERT(onAsyncThread);
+      }
+#endif
       (void)mCallingThread->Dispatch(this, NS_DISPATCH_NORMAL);
       return NS_OK;
     }
 
     (void)mConnection->internalClose();
     if (mCallbackEvent)
       (void)mCallingThread->Dispatch(mCallbackEvent, NS_DISPATCH_NORMAL);
+    (void)mAsyncExecutionThread->Shutdown();
 
     // Because we have no guarantee that the invocation of this method on the
     // asynchronous thread has fully completed (including the Release of the
     // reference to this object held by that event loop), we need to explicitly
     // null out our pointers here.  It is possible this object will be destroyed
     // on the asynchronous thread and if the references are still alive we will
     // release them on that thread. We definitely do not want that for
     // mConnection and it's nice to avoid for mCallbackEvent too.  We do not
@@ -371,16 +381,17 @@ public:
     mCallbackEvent = nullptr;
 
     return NS_OK;
   }
 private:
   nsRefPtr<Connection> mConnection;
   nsCOMPtr<nsIEventTarget> mCallingThread;
   nsCOMPtr<nsIRunnable> mCallbackEvent;
+  nsCOMPtr<nsIThread> mAsyncExecutionThread;
 };
 
 } // anonymous namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Connection
 
 Connection::Connection(Service *aService,
@@ -397,16 +408,18 @@ Connection::Connection(Service *aService
 {
   mFunctions.Init();
   mStorageService->registerConnection(this);
 }
 
 Connection::~Connection()
 {
   (void)Close();
+
+  MOZ_ASSERT(!mAsyncExecutionThread);
 }
 
 NS_IMPL_THREADSAFE_ADDREF(Connection)
 NS_IMPL_THREADSAFE_QUERY_INTERFACE2(
   Connection,
   mozIStorageConnection,
   nsIInterfaceRequestor
 )
@@ -907,23 +920,27 @@ Connection::AsyncClose(mozIStorageComple
 
   nsresult rv = setClosedState();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Create our callback event if we were given a callback.
   nsCOMPtr<nsIRunnable> completeEvent;
   if (aCallback) {
     completeEvent = newCompletionEvent(aCallback);
-    NS_ENSURE_TRUE(completeEvent, NS_ERROR_OUT_OF_MEMORY);
   }
 
   // Create and dispatch our close event to the background thread.
-  nsCOMPtr<nsIRunnable> closeEvent =
-    new AsyncCloseConnection(this, NS_GetCurrentThread(), completeEvent);
-  NS_ENSURE_TRUE(closeEvent, NS_ERROR_OUT_OF_MEMORY);
+  nsCOMPtr<nsIRunnable> closeEvent;
+  {
+    // We need to lock because we're modifying mAsyncExecutionThread
+    MutexAutoLock lockedScope(sharedAsyncExecutionMutex);
+    closeEvent = new AsyncCloseConnection(this, NS_GetCurrentThread(),
+                                          completeEvent,
+                                          mAsyncExecutionThread.forget());
+  }
 
   rv = asyncThread->Dispatch(closeEvent, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP