dom/indexedDB/TransactionThreadPool.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* vim: set ts=2 et sw=2 tw=80: */
     3 /* This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "TransactionThreadPool.h"
     9 #include "nsIObserverService.h"
    10 #include "nsIThreadPool.h"
    12 #include "nsComponentManagerUtils.h"
    13 #include "nsThreadUtils.h"
    14 #include "nsServiceManagerUtils.h"
    15 #include "nsXPCOMCIDInternal.h"
    17 #include "ProfilerHelpers.h"
    19 using mozilla::MonitorAutoLock;
    21 USING_INDEXEDDB_NAMESPACE
    23 namespace {
    25 const uint32_t kThreadLimit = 20;
    26 const uint32_t kIdleThreadLimit = 5;
    27 const uint32_t kIdleThreadTimeoutMs = 30000;
    29 TransactionThreadPool* gThreadPool = nullptr;
    30 bool gShutdown = false;
    32 #ifdef MOZ_ENABLE_PROFILER_SPS
    34 class TransactionThreadPoolListener : public nsIThreadPoolListener
    35 {
    36 public:
    37   NS_DECL_THREADSAFE_ISUPPORTS
    38   NS_DECL_NSITHREADPOOLLISTENER
    40 private:
    41   virtual ~TransactionThreadPoolListener()
    42   { }
    43 };
    45 #endif // MOZ_ENABLE_PROFILER_SPS
    47 } // anonymous namespace
    49 BEGIN_INDEXEDDB_NAMESPACE
    51 class FinishTransactionRunnable MOZ_FINAL : public nsIRunnable
    52 {
    53 public:
    54   NS_DECL_THREADSAFE_ISUPPORTS
    55   NS_DECL_NSIRUNNABLE
    57   inline FinishTransactionRunnable(IDBTransaction* aTransaction,
    58                                    nsCOMPtr<nsIRunnable>& aFinishRunnable);
    60 private:
    61   IDBTransaction* mTransaction;
    62   nsCOMPtr<nsIRunnable> mFinishRunnable;
    63 };
    65 END_INDEXEDDB_NAMESPACE
    67 TransactionThreadPool::TransactionThreadPool()
    68 {
    69   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    70   NS_ASSERTION(!gThreadPool, "More than one instance!");
    71 }
    73 TransactionThreadPool::~TransactionThreadPool()
    74 {
    75   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    76   NS_ASSERTION(gThreadPool == this, "Different instances!");
    77   gThreadPool = nullptr;
    78 }
    80 // static
    81 TransactionThreadPool*
    82 TransactionThreadPool::GetOrCreate()
    83 {
    84   if (!gThreadPool && !gShutdown) {
    85     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
    86     nsAutoPtr<TransactionThreadPool> pool(new TransactionThreadPool());
    88     nsresult rv = pool->Init();
    89     NS_ENSURE_SUCCESS(rv, nullptr);
    91     gThreadPool = pool.forget();
    92   }
    93   return gThreadPool;
    94 }
    96 // static
    97 TransactionThreadPool*
    98 TransactionThreadPool::Get()
    99 {
   100   return gThreadPool;
   101 }
   103 // static
   104 void
   105 TransactionThreadPool::Shutdown()
   106 {
   107   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   109   gShutdown = true;
   111   if (gThreadPool) {
   112     if (NS_FAILED(gThreadPool->Cleanup())) {
   113       NS_WARNING("Failed to shutdown thread pool!");
   114     }
   115     delete gThreadPool;
   116     gThreadPool = nullptr;
   117   }
   118 }
   120 nsresult
   121 TransactionThreadPool::Init()
   122 {
   123   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   125   nsresult rv;
   126   mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
   127   NS_ENSURE_SUCCESS(rv, rv);
   129   rv = mThreadPool->SetName(NS_LITERAL_CSTRING("IndexedDB Trans"));
   130   NS_ENSURE_SUCCESS(rv, rv);
   132   rv = mThreadPool->SetThreadLimit(kThreadLimit);
   133   NS_ENSURE_SUCCESS(rv, rv);
   135   rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
   136   NS_ENSURE_SUCCESS(rv, rv);
   138   rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
   139   NS_ENSURE_SUCCESS(rv, rv);
   141 #ifdef MOZ_ENABLE_PROFILER_SPS
   142   nsCOMPtr<nsIThreadPoolListener> listener =
   143     new TransactionThreadPoolListener();
   145   rv = mThreadPool->SetListener(listener);
   146   NS_ENSURE_SUCCESS(rv, rv);
   147 #endif
   149   return NS_OK;
   150 }
   152 nsresult
   153 TransactionThreadPool::Cleanup()
   154 {
   155   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   157   PROFILER_MAIN_THREAD_LABEL("IndexedDB", "TransactionThreadPool::Cleanup");
   159   nsresult rv = mThreadPool->Shutdown();
   160   NS_ENSURE_SUCCESS(rv, rv);
   162   // Make sure the pool is still accessible while any callbacks generated from
   163   // the other threads are processed.
   164   rv = NS_ProcessPendingEvents(nullptr);
   165   NS_ENSURE_SUCCESS(rv, rv);
   167   if (!mCompleteCallbacks.IsEmpty()) {
   168     // Run all callbacks manually now.
   169     for (uint32_t index = 0; index < mCompleteCallbacks.Length(); index++) {
   170       mCompleteCallbacks[index].mCallback->Run();
   171     }
   172     mCompleteCallbacks.Clear();
   174     // And make sure they get processed.
   175     rv = NS_ProcessPendingEvents(nullptr);
   176     NS_ENSURE_SUCCESS(rv, rv);
   177   }
   179   return NS_OK;
   180 }
   182 // static
   183 PLDHashOperator
   184 TransactionThreadPool::MaybeUnblockTransaction(nsPtrHashKey<TransactionInfo>* aKey,
   185                                                void* aUserArg)
   186 {
   187   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   189   TransactionInfo* maybeUnblockedInfo = aKey->GetKey();
   190   TransactionInfo* finishedInfo = static_cast<TransactionInfo*>(aUserArg);
   192   NS_ASSERTION(maybeUnblockedInfo->blockedOn.Contains(finishedInfo),
   193                "Huh?");
   194   maybeUnblockedInfo->blockedOn.RemoveEntry(finishedInfo);
   195   if (!maybeUnblockedInfo->blockedOn.Count()) {
   196     // Let this transaction run.
   197     maybeUnblockedInfo->queue->Unblock();
   198   }
   200   return PL_DHASH_NEXT;
   201 }
   203 void
   204 TransactionThreadPool::FinishTransaction(IDBTransaction* aTransaction)
   205 {
   206   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   207   NS_ASSERTION(aTransaction, "Null pointer!");
   209   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
   210                              "TransactionThreadPool::FinishTransaction");
   212   // AddRef here because removing from the hash will call Release.
   213   nsRefPtr<IDBTransaction> transaction(aTransaction);
   215   const nsACString& databaseId = aTransaction->mDatabase->Id();
   217   DatabaseTransactionInfo* dbTransactionInfo;
   218   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
   219     NS_ERROR("We don't know anyting about this database?!");
   220     return;
   221   }
   223   DatabaseTransactionInfo::TransactionHashtable& transactionsInProgress =
   224     dbTransactionInfo->transactions;
   226   uint32_t transactionCount = transactionsInProgress.Count();
   228 #ifdef DEBUG
   229   if (aTransaction->mMode == IDBTransaction::VERSION_CHANGE) {
   230     NS_ASSERTION(transactionCount == 1,
   231                  "More transactions running than should be!");
   232   }
   233 #endif
   235   if (transactionCount == 1) {
   236 #ifdef DEBUG
   237     {
   238       const TransactionInfo* info = transactionsInProgress.Get(aTransaction);
   239       NS_ASSERTION(info->transaction == aTransaction, "Transaction mismatch!");
   240     }
   241 #endif
   242     mTransactionsInProgress.Remove(databaseId);
   244     // See if we need to fire any complete callbacks.
   245     uint32_t index = 0;
   246     while (index < mCompleteCallbacks.Length()) {
   247       if (MaybeFireCallback(mCompleteCallbacks[index])) {
   248         mCompleteCallbacks.RemoveElementAt(index);
   249       }
   250       else {
   251         index++;
   252       }
   253     }
   255     return;
   256   }
   257   TransactionInfo* info = transactionsInProgress.Get(aTransaction);
   258   NS_ASSERTION(info, "We've never heard of this transaction?!?");
   260   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
   261   for (uint32_t index = 0, count = objectStoreNames.Length(); index < count;
   262        index++) {
   263     TransactionInfoPair* blockInfo =
   264       dbTransactionInfo->blockingTransactions.Get(objectStoreNames[index]);
   265     NS_ASSERTION(blockInfo, "Huh?");
   267     if (aTransaction->mMode == IDBTransaction::READ_WRITE &&
   268         blockInfo->lastBlockingReads == info) {
   269       blockInfo->lastBlockingReads = nullptr;
   270     }
   272     uint32_t i = blockInfo->lastBlockingWrites.IndexOf(info);
   273     if (i != blockInfo->lastBlockingWrites.NoIndex) {
   274       blockInfo->lastBlockingWrites.RemoveElementAt(i);
   275     }
   276   }
   278   info->blocking.EnumerateEntries(MaybeUnblockTransaction, info);
   280   transactionsInProgress.Remove(aTransaction);
   281 }
   283 TransactionThreadPool::TransactionQueue&
   284 TransactionThreadPool::GetQueueForTransaction(IDBTransaction* aTransaction)
   285 {
   286   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   287   NS_ASSERTION(aTransaction, "Null pointer!");
   289   const nsACString& databaseId = aTransaction->mDatabase->Id();
   291   const nsTArray<nsString>& objectStoreNames = aTransaction->mObjectStoreNames;
   292   const uint16_t mode = aTransaction->mMode;
   294   // See if we can run this transaction now.
   295   DatabaseTransactionInfo* dbTransactionInfo;
   296   if (!mTransactionsInProgress.Get(databaseId, &dbTransactionInfo)) {
   297     // First transaction for this database.
   298     dbTransactionInfo = new DatabaseTransactionInfo();
   299     mTransactionsInProgress.Put(databaseId, dbTransactionInfo);
   300   }
   302   DatabaseTransactionInfo::TransactionHashtable& transactionsInProgress =
   303     dbTransactionInfo->transactions;
   304   TransactionInfo* info = transactionsInProgress.Get(aTransaction);
   305   if (info) {
   306     // We recognize this one.
   307     return *info->queue;
   308   }
   310   TransactionInfo* transactionInfo = new TransactionInfo(aTransaction);
   312   dbTransactionInfo->transactions.Put(aTransaction, transactionInfo);;
   314   for (uint32_t index = 0, count = objectStoreNames.Length(); index < count;
   315        index++) {
   316     TransactionInfoPair* blockInfo =
   317       dbTransactionInfo->blockingTransactions.Get(objectStoreNames[index]);
   318     if (!blockInfo) {
   319       blockInfo = new TransactionInfoPair();
   320       blockInfo->lastBlockingReads = nullptr;
   321       dbTransactionInfo->blockingTransactions.Put(objectStoreNames[index],
   322                                                   blockInfo);
   323     }
   325     // Mark what we are blocking on.
   326     if (blockInfo->lastBlockingReads) {
   327       TransactionInfo* blockingInfo = blockInfo->lastBlockingReads;
   328       transactionInfo->blockedOn.PutEntry(blockingInfo);
   329       blockingInfo->blocking.PutEntry(transactionInfo);
   330     }
   332     if (mode == IDBTransaction::READ_WRITE &&
   333         blockInfo->lastBlockingWrites.Length()) {
   334       for (uint32_t index = 0,
   335            count = blockInfo->lastBlockingWrites.Length(); index < count;
   336            index++) {
   337         TransactionInfo* blockingInfo = blockInfo->lastBlockingWrites[index];
   338         transactionInfo->blockedOn.PutEntry(blockingInfo);
   339         blockingInfo->blocking.PutEntry(transactionInfo);
   340       }
   341     }
   343     if (mode == IDBTransaction::READ_WRITE) {
   344       blockInfo->lastBlockingReads = transactionInfo;
   345       blockInfo->lastBlockingWrites.Clear();
   346     }
   347     else {
   348       blockInfo->lastBlockingWrites.AppendElement(transactionInfo);
   349     }
   350   }
   352   if (!transactionInfo->blockedOn.Count()) {
   353     transactionInfo->queue->Unblock();
   354   }
   356   return *transactionInfo->queue;
   357 }
   359 nsresult
   360 TransactionThreadPool::Dispatch(IDBTransaction* aTransaction,
   361                                 nsIRunnable* aRunnable,
   362                                 bool aFinish,
   363                                 nsIRunnable* aFinishRunnable)
   364 {
   365   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   366   NS_ASSERTION(aTransaction, "Null pointer!");
   367   NS_ASSERTION(aRunnable, "Null pointer!");
   369   if (aTransaction->mDatabase->IsInvalidated() && !aFinish) {
   370     return NS_ERROR_NOT_AVAILABLE;
   371   }
   373   TransactionQueue& queue = GetQueueForTransaction(aTransaction);
   375   queue.Dispatch(aRunnable);
   376   if (aFinish) {
   377     queue.Finish(aFinishRunnable);
   378   }
   379   return NS_OK;
   380 }
   382 void
   383 TransactionThreadPool::WaitForDatabasesToComplete(
   384                                    nsTArray<nsRefPtr<IDBDatabase> >& aDatabases,
   385                                    nsIRunnable* aCallback)
   386 {
   387   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   388   NS_ASSERTION(!aDatabases.IsEmpty(), "No databases to wait on!");
   389   NS_ASSERTION(aCallback, "Null pointer!");
   391   DatabasesCompleteCallback* callback = mCompleteCallbacks.AppendElement();
   393   callback->mCallback = aCallback;
   394   callback->mDatabases.SwapElements(aDatabases);
   396   if (MaybeFireCallback(*callback)) {
   397     mCompleteCallbacks.RemoveElementAt(mCompleteCallbacks.Length() - 1);
   398   }
   399 }
   401 // static
   402 PLDHashOperator
   403 TransactionThreadPool::CollectTransactions(IDBTransaction* aKey,
   404                                            TransactionInfo* aValue,
   405                                            void* aUserArg)
   406 {
   407   nsAutoTArray<nsRefPtr<IDBTransaction>, 50>* transactionArray =
   408     static_cast<nsAutoTArray<nsRefPtr<IDBTransaction>, 50>*>(aUserArg);
   409   transactionArray->AppendElement(aKey);
   411   return PL_DHASH_NEXT;
   412 }
   414 void
   415 TransactionThreadPool::AbortTransactionsForDatabase(IDBDatabase* aDatabase)
   416 {
   417   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   418   NS_ASSERTION(aDatabase, "Null pointer!");
   420   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
   421                              "TransactionThreadPool::"
   422                              "AbortTransactionsForDatabase");
   424   // Get list of transactions for this database id
   425   DatabaseTransactionInfo* dbTransactionInfo;
   426   if (!mTransactionsInProgress.Get(aDatabase->Id(), &dbTransactionInfo)) {
   427     // If there are no transactions, we're done.
   428     return;
   429   }
   431   // Collect any running transactions
   432   DatabaseTransactionInfo::TransactionHashtable& transactionsInProgress =
   433     dbTransactionInfo->transactions;
   435   NS_ASSERTION(transactionsInProgress.Count(), "Should never be 0!");
   437   nsAutoTArray<nsRefPtr<IDBTransaction>, 50> transactions;
   438   transactionsInProgress.EnumerateRead(CollectTransactions, &transactions);
   440   // Abort transactions. Do this after collecting the transactions in case
   441   // calling Abort() modifies the data structures we're iterating above.
   442   for (uint32_t index = 0; index < transactions.Length(); index++) {
   443     if (transactions[index]->Database() != aDatabase) {
   444       continue;
   445     }
   447     // This can fail, for example if the transaction is in the process of
   448     // being comitted. That is expected and fine, so we ignore any returned
   449     // errors.
   450     ErrorResult rv;
   451     transactions[index]->Abort(rv);
   452   }
   453 }
   455 struct MOZ_STACK_CLASS TransactionSearchInfo
   456 {
   457   TransactionSearchInfo(nsIOfflineStorage* aDatabase)
   458     : db(aDatabase), found(false)
   459   {
   460   }
   462   nsIOfflineStorage* db;
   463   bool found;
   464 };
   466 // static
   467 PLDHashOperator
   468 TransactionThreadPool::FindTransaction(IDBTransaction* aKey,
   469                                        TransactionInfo* aValue,
   470                                        void* aUserArg)
   471 {
   472   TransactionSearchInfo* info = static_cast<TransactionSearchInfo*>(aUserArg);
   474   if (aKey->Database() == info->db) {
   475     info->found = true;
   476     return PL_DHASH_STOP;
   477   }
   479   return PL_DHASH_NEXT;
   480 }
   481 bool
   482 TransactionThreadPool::HasTransactionsForDatabase(IDBDatabase* aDatabase)
   483 {
   484   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   485   NS_ASSERTION(aDatabase, "Null pointer!");
   487   DatabaseTransactionInfo* dbTransactionInfo = nullptr;
   488   dbTransactionInfo = mTransactionsInProgress.Get(aDatabase->Id());
   489   if (!dbTransactionInfo) {
   490     return false;
   491   }
   493   TransactionSearchInfo info(aDatabase);
   494   dbTransactionInfo->transactions.EnumerateRead(FindTransaction, &info);
   496   return info.found;
   497 }
   499 bool
   500 TransactionThreadPool::MaybeFireCallback(DatabasesCompleteCallback aCallback)
   501 {
   502   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   504   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
   505                              "TransactionThreadPool::MaybeFireCallback");
   507   for (uint32_t index = 0; index < aCallback.mDatabases.Length(); index++) {
   508     IDBDatabase* database = aCallback.mDatabases[index];
   509     if (!database) {
   510       MOZ_CRASH();
   511     }
   513     if (mTransactionsInProgress.Get(database->Id(), nullptr)) {
   514       return false;
   515     }
   516   }
   518   aCallback.mCallback->Run();
   519   return true;
   520 }
   522 TransactionThreadPool::
   523 TransactionQueue::TransactionQueue(IDBTransaction* aTransaction)
   524 : mMonitor("TransactionQueue::mMonitor"),
   525   mTransaction(aTransaction),
   526   mShouldFinish(false)
   527 {
   528   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   529   NS_ASSERTION(aTransaction, "Null pointer!");
   530 }
   532 void
   533 TransactionThreadPool::TransactionQueue::Unblock()
   534 {
   535   MonitorAutoLock lock(mMonitor);
   537   // NB: Finish may be called before Unblock.
   539   TransactionThreadPool::Get()->mThreadPool->
   540     Dispatch(this, NS_DISPATCH_NORMAL);
   541 }
   543 void
   544 TransactionThreadPool::TransactionQueue::Dispatch(nsIRunnable* aRunnable)
   545 {
   546   MonitorAutoLock lock(mMonitor);
   548   NS_ASSERTION(!mShouldFinish, "Dispatch called after Finish!");
   550   mQueue.AppendElement(aRunnable);
   552   mMonitor.Notify();
   553 }
   555 void
   556 TransactionThreadPool::TransactionQueue::Finish(nsIRunnable* aFinishRunnable)
   557 {
   558   MonitorAutoLock lock(mMonitor);
   560   NS_ASSERTION(!mShouldFinish, "Finish called more than once!");
   562   mShouldFinish = true;
   563   mFinishRunnable = aFinishRunnable;
   565   mMonitor.Notify();
   566 }
   568 NS_IMPL_ISUPPORTS(TransactionThreadPool::TransactionQueue, nsIRunnable)
   570 NS_IMETHODIMP
   571 TransactionThreadPool::TransactionQueue::Run()
   572 {
   573   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   574   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   576   PROFILER_LABEL("IndexedDB", "TransactionQueue::Run");
   578   IDB_PROFILER_MARK("IndexedDB Transaction %llu: Beginning database work",
   579                     "IDBTransaction[%llu] DT Start",
   580                     mTransaction->GetSerialNumber());
   582   nsAutoTArray<nsCOMPtr<nsIRunnable>, 10> queue;
   583   nsCOMPtr<nsIRunnable> finishRunnable;
   584   bool shouldFinish = false;
   586   do {
   587     NS_ASSERTION(queue.IsEmpty(), "Should have cleared this!");
   589     {
   590       MonitorAutoLock lock(mMonitor);
   591       while (!mShouldFinish && mQueue.IsEmpty()) {
   592         if (NS_FAILED(mMonitor.Wait())) {
   593           NS_ERROR("Failed to wait!");
   594         }
   595       }
   597       mQueue.SwapElements(queue);
   598       if (mShouldFinish) {
   599         mFinishRunnable.swap(finishRunnable);
   600         shouldFinish = true;
   601       }
   602     }
   604     uint32_t count = queue.Length();
   605     for (uint32_t index = 0; index < count; index++) {
   606       nsCOMPtr<nsIRunnable>& runnable = queue[index];
   607       runnable->Run();
   608       runnable = nullptr;
   609     }
   611     if (count) {
   612       queue.Clear();
   613     }
   614   } while (!shouldFinish);
   616   IDB_PROFILER_MARK("IndexedDB Transaction %llu: Finished database work",
   617                     "IDBTransaction[%llu] DT Done",
   618                     mTransaction->GetSerialNumber());
   620   nsCOMPtr<nsIRunnable> finishTransactionRunnable =
   621     new FinishTransactionRunnable(mTransaction, finishRunnable);
   622   if (NS_FAILED(NS_DispatchToMainThread(finishTransactionRunnable,
   623                                         NS_DISPATCH_NORMAL))) {
   624     NS_WARNING("Failed to dispatch finishTransactionRunnable!");
   625   }
   627   return NS_OK;
   628 }
   630 FinishTransactionRunnable::FinishTransactionRunnable(
   631                                          IDBTransaction* aTransaction,
   632                                          nsCOMPtr<nsIRunnable>& aFinishRunnable)
   633 : mTransaction(aTransaction)
   634 {
   635   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   636   NS_ASSERTION(aTransaction, "Null pointer!");
   637   mFinishRunnable.swap(aFinishRunnable);
   638 }
   640 NS_IMPL_ISUPPORTS(FinishTransactionRunnable, nsIRunnable)
   642 NS_IMETHODIMP
   643 FinishTransactionRunnable::Run()
   644 {
   645   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   647   PROFILER_MAIN_THREAD_LABEL("IndexedDB", "FinishTransactionRunnable::Run");
   649   if (!gThreadPool) {
   650     NS_ERROR("Running after shutdown!");
   651     return NS_ERROR_FAILURE;
   652   }
   654   gThreadPool->FinishTransaction(mTransaction);
   656   if (mFinishRunnable) {
   657     mFinishRunnable->Run();
   658     mFinishRunnable = nullptr;
   659   }
   661   return NS_OK;
   662 }
   664 #ifdef MOZ_ENABLE_PROFILER_SPS
   666 NS_IMPL_ISUPPORTS(TransactionThreadPoolListener, nsIThreadPoolListener)
   668 NS_IMETHODIMP
   669 TransactionThreadPoolListener::OnThreadCreated()
   670 {
   671   MOZ_ASSERT(!NS_IsMainThread());
   672   char aLocal;
   673   profiler_register_thread("IndexedDB Transaction", &aLocal);
   674   return NS_OK;
   675 }
   677 NS_IMETHODIMP
   678 TransactionThreadPoolListener::OnThreadShuttingDown()
   679 {
   680   MOZ_ASSERT(!NS_IsMainThread());
   681   profiler_unregister_thread();
   682   return NS_OK;
   683 }
   685 #endif // MOZ_ENABLE_PROFILER_SPS

mercurial