LCOV - code coverage report
Current view: top level - toolkit/components/places - Shutdown.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 25 103 24.3 %
Date: 2017-07-14 16:53:18 Functions: 13 20 65.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* This Source Code Form is subject to the terms of the Mozilla Public
       2             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       3             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       4             : 
       5             : #include "Shutdown.h"
       6             : #include "mozilla/Unused.h"
       7             : 
       8             : namespace mozilla {
       9             : namespace places {
      10             : 
      11             : uint16_t PlacesShutdownBlocker::sCounter = 0;
      12             : Atomic<bool> PlacesShutdownBlocker::sIsStarted(false);
      13             : 
      14           2 : PlacesShutdownBlocker::PlacesShutdownBlocker(const nsString& aName)
      15             :   : mName(aName)
      16             :   , mState(NOT_STARTED)
      17           2 :   , mCounter(sCounter++)
      18             : {
      19           2 :   MOZ_ASSERT(NS_IsMainThread());
      20             :   // During tests, we can end up with the Database singleton being resurrected.
      21             :   // Make sure that each instance of DatabaseShutdown has a unique name.
      22           2 :   if (mCounter > 1) {
      23           0 :     mName.AppendInt(mCounter);
      24             :   }
      25           2 : }
      26             : 
      27             : // nsIAsyncShutdownBlocker
      28             : NS_IMETHODIMP
      29           8 : PlacesShutdownBlocker::GetName(nsAString& aName)
      30             : {
      31           8 :   aName = mName;
      32           8 :   return NS_OK;
      33             : }
      34             : 
      35             : // nsIAsyncShutdownBlocker
      36             : NS_IMETHODIMP
      37           0 : PlacesShutdownBlocker::GetState(nsIPropertyBag** _state)
      38             : {
      39           0 :   NS_ENSURE_ARG_POINTER(_state);
      40             : 
      41             :   nsCOMPtr<nsIWritablePropertyBag2> bag =
      42           0 :     do_CreateInstance("@mozilla.org/hash-property-bag;1");
      43           0 :   NS_ENSURE_TRUE(bag, NS_ERROR_OUT_OF_MEMORY);
      44           0 :   bag.forget(_state);
      45             : 
      46             :   // Put `mState` in field `progress`
      47           0 :   RefPtr<nsVariant> progress = new nsVariant();
      48           0 :   nsresult rv = progress->SetAsUint8(mState);
      49           0 :   if (NS_WARN_IF(NS_FAILED(rv))) return rv;
      50           0 :   rv = static_cast<nsIWritablePropertyBag2*>(*_state)->SetPropertyAsInterface(
      51           0 :     NS_LITERAL_STRING("progress"), progress);
      52           0 :   if (NS_WARN_IF(NS_FAILED(rv))) return rv;
      53             : 
      54             :   // Put `mBarrier`'s state in field `barrier`, if possible
      55           0 :   if (!mBarrier) {
      56           0 :     return NS_OK;
      57             :   }
      58           0 :   nsCOMPtr<nsIPropertyBag> barrierState;
      59           0 :   rv = mBarrier->GetState(getter_AddRefs(barrierState));
      60           0 :   if (NS_FAILED(rv)) {
      61           0 :     return NS_OK;
      62             :   }
      63             : 
      64           0 :   RefPtr<nsVariant> barrier = new nsVariant();
      65           0 :   rv = barrier->SetAsInterface(NS_GET_IID(nsIPropertyBag), barrierState);
      66           0 :   if (NS_WARN_IF(NS_FAILED(rv))) return rv;
      67           0 :   rv = static_cast<nsIWritablePropertyBag2*>(*_state)->SetPropertyAsInterface(
      68           0 :     NS_LITERAL_STRING("Barrier"), barrier);
      69           0 :   if (NS_WARN_IF(NS_FAILED(rv))) return rv;
      70             : 
      71           0 :   return NS_OK;
      72             : }
      73             : 
      74             : // nsIAsyncShutdownBlocker
      75             : NS_IMETHODIMP
      76           0 : PlacesShutdownBlocker::BlockShutdown(nsIAsyncShutdownClient* aParentClient)
      77             : {
      78           0 :   MOZ_ASSERT(false, "should always be overridden");
      79             :   return NS_ERROR_NOT_IMPLEMENTED;
      80             : }
      81             : 
      82          26 : NS_IMPL_ISUPPORTS(
      83             :   PlacesShutdownBlocker,
      84             :   nsIAsyncShutdownBlocker
      85             : )
      86             : 
      87             : ////////////////////////////////////////////////////////////////////////////////
      88             : 
      89           1 : ClientsShutdownBlocker::ClientsShutdownBlocker()
      90           1 :   : PlacesShutdownBlocker(NS_LITERAL_STRING("Places Clients shutdown"))
      91             : {
      92           1 :   MOZ_ASSERT(NS_IsMainThread());
      93             :   // Create a barrier that will be exposed to clients through GetClient(), so
      94             :   // they can block Places shutdown.
      95           2 :   nsCOMPtr<nsIAsyncShutdownService> asyncShutdown = services::GetAsyncShutdown();
      96           1 :   MOZ_ASSERT(asyncShutdown);
      97           1 :   if (asyncShutdown) {
      98           2 :     nsCOMPtr<nsIAsyncShutdownBarrier> barrier;
      99           1 :     MOZ_ALWAYS_SUCCEEDS(asyncShutdown->MakeBarrier(mName, getter_AddRefs(barrier)));
     100             :     mBarrier = new nsMainThreadPtrHolder<nsIAsyncShutdownBarrier>(
     101           2 :       "ClientsShutdownBlocker::mBarrier", barrier);
     102             :   }
     103           1 : }
     104             : 
     105             : already_AddRefed<nsIAsyncShutdownClient>
     106           0 : ClientsShutdownBlocker::GetClient()
     107             : {
     108           0 :   nsCOMPtr<nsIAsyncShutdownClient> client;
     109           0 :   if (mBarrier) {
     110           0 :     MOZ_ALWAYS_SUCCEEDS(mBarrier->GetClient(getter_AddRefs(client)));
     111             :   }
     112           0 :   return client.forget();
     113             : }
     114             : 
     115             : // nsIAsyncShutdownBlocker
     116             : NS_IMETHODIMP
     117           0 : ClientsShutdownBlocker::BlockShutdown(nsIAsyncShutdownClient* aParentClient)
     118             : {
     119           0 :   MOZ_ASSERT(NS_IsMainThread());
     120             :   mParentClient = new nsMainThreadPtrHolder<nsIAsyncShutdownClient>(
     121           0 :     "ClientsShutdownBlocker::mParentClient", aParentClient);
     122           0 :   mState = RECEIVED_BLOCK_SHUTDOWN;
     123             : 
     124           0 :   if (NS_WARN_IF(!mBarrier)) {
     125           0 :     return NS_ERROR_NOT_AVAILABLE;
     126             :   }
     127             : 
     128             :   // Wait until all the clients have removed their blockers.
     129           0 :   MOZ_ALWAYS_SUCCEEDS(mBarrier->Wait(this));
     130             : 
     131           0 :   mState = CALLED_WAIT_CLIENTS;
     132           0 :   return NS_OK;
     133             : }
     134             : 
     135             : // nsIAsyncShutdownCompletionCallback
     136             : NS_IMETHODIMP
     137           0 : ClientsShutdownBlocker::Done()
     138             : {
     139             :   // At this point all the clients are done, we can stop blocking the shutdown
     140             :   // phase.
     141           0 :   mState = RECEIVED_DONE;
     142             : 
     143             :   // mParentClient is nullptr in tests.
     144           0 :   if (mParentClient) {
     145           0 :     nsresult rv = mParentClient->RemoveBlocker(this);
     146           0 :     if (NS_WARN_IF(NS_FAILED(rv))) return rv;
     147           0 :     mParentClient = nullptr;
     148             :   }
     149           0 :   mBarrier = nullptr;
     150           0 :   return NS_OK;
     151             : }
     152             : 
     153          13 : NS_IMPL_ISUPPORTS_INHERITED(
     154             :   ClientsShutdownBlocker,
     155             :   PlacesShutdownBlocker,
     156             :   nsIAsyncShutdownCompletionCallback
     157             : )
     158             : 
     159             : ////////////////////////////////////////////////////////////////////////////////
     160             : 
     161           1 : ConnectionShutdownBlocker::ConnectionShutdownBlocker(Database* aDatabase)
     162           2 :   : PlacesShutdownBlocker(NS_LITERAL_STRING("Places Connection shutdown"))
     163           2 :   , mDatabase(aDatabase)
     164             : {
     165             :   // Do nothing.
     166           1 : }
     167             : 
     168             : // nsIAsyncShutdownBlocker
     169             : NS_IMETHODIMP
     170           0 : ConnectionShutdownBlocker::BlockShutdown(nsIAsyncShutdownClient* aParentClient)
     171             : {
     172           0 :   MOZ_ASSERT(NS_IsMainThread());
     173             :   mParentClient = new nsMainThreadPtrHolder<nsIAsyncShutdownClient>(
     174           0 :     "ConnectionShutdownBlocker::mParentClient", aParentClient);
     175           0 :   mState = RECEIVED_BLOCK_SHUTDOWN;
     176             :   // Annotate that Database shutdown started.
     177           0 :   sIsStarted = true;
     178             : 
     179             :   // Fire internal database closing notification.
     180           0 :   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
     181           0 :   MOZ_ASSERT(os);
     182           0 :   if (os) {
     183           0 :     Unused << os->NotifyObservers(nullptr, TOPIC_PLACES_WILL_CLOSE_CONNECTION, nullptr);
     184             :   }
     185           0 :   mState = NOTIFIED_OBSERVERS_PLACES_WILL_CLOSE_CONNECTION;
     186             : 
     187             :   // At this stage, any use of this database is forbidden. Get rid of
     188             :   // `gDatabase`. Note, however, that the database could be
     189             :   // resurrected.  This can happen in particular during tests.
     190           0 :   MOZ_ASSERT(Database::gDatabase == nullptr || Database::gDatabase == mDatabase);
     191           0 :   Database::gDatabase = nullptr;
     192             : 
     193             :   // Database::Shutdown will invoke Complete once the connection is closed.
     194           0 :   mDatabase->Shutdown();
     195           0 :   mState = CALLED_STORAGESHUTDOWN;
     196           0 :   return NS_OK;
     197             : }
     198             : 
     199             : // mozIStorageCompletionCallback
     200             : NS_IMETHODIMP
     201           0 : ConnectionShutdownBlocker::Complete(nsresult, nsISupports*)
     202             : {
     203           0 :   MOZ_ASSERT(NS_IsMainThread());
     204           0 :   mState = RECEIVED_STORAGESHUTDOWN_COMPLETE;
     205             : 
     206             :   // The connection is closed, the Database has no more use, so we can break
     207             :   // possible cycles.
     208           0 :   mDatabase = nullptr;
     209             : 
     210             :   // Notify the connection has gone.
     211           0 :   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     212           0 :   MOZ_ASSERT(os);
     213           0 :   if (os) {
     214           0 :     MOZ_ALWAYS_SUCCEEDS(os->NotifyObservers(nullptr,
     215             :               TOPIC_PLACES_CONNECTION_CLOSED,
     216             :               nullptr));
     217             :   }
     218           0 :   mState = NOTIFIED_OBSERVERS_PLACES_CONNECTION_CLOSED;
     219             : 
     220             :   // mParentClient is nullptr in tests
     221           0 :   if (mParentClient) {
     222           0 :     nsresult rv = mParentClient->RemoveBlocker(this);
     223           0 :     if (NS_WARN_IF(NS_FAILED(rv))) return rv;
     224           0 :     mParentClient = nullptr;
     225             :   }
     226           0 :   return NS_OK;
     227             : }
     228             : 
     229          13 : NS_IMPL_ISUPPORTS_INHERITED(
     230             :   ConnectionShutdownBlocker,
     231             :   PlacesShutdownBlocker,
     232             :   mozIStorageCompletionCallback
     233             : )
     234             : 
     235             : } // namespace places
     236             : } // namespace mozilla

Generated by: LCOV version 1.13