summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/Shutdown.h
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/Shutdown.h')
-rw-r--r--toolkit/components/places/Shutdown.h171
1 files changed, 171 insertions, 0 deletions
diff --git a/toolkit/components/places/Shutdown.h b/toolkit/components/places/Shutdown.h
new file mode 100644
index 000000000..69023c608
--- /dev/null
+++ b/toolkit/components/places/Shutdown.h
@@ -0,0 +1,171 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_places_Shutdown_h_
+#define mozilla_places_Shutdown_h_
+
+#include "nsIAsyncShutdown.h"
+#include "Database.h"
+#include "nsProxyRelease.h"
+
+namespace mozilla {
+namespace places {
+
+class Database;
+
+/**
+ * This is most of the code responsible for Places shutdown.
+ *
+ * PHASE 1 (Legacy clients shutdown)
+ * The shutdown procedure begins when the Database singleton receives
+ * profile-change-teardown (note that tests will instead notify nsNavHistory,
+ * that forwards the notification to the Database instance).
+ * Database::Observe first of all checks if initialization was completed
+ * properly, to avoid race conditions, then it notifies "places-shutdown" to
+ * legacy clients. Legacy clients are supposed to start and complete any
+ * shutdown critical work in the same tick, since we won't wait for them.
+
+ * PHASE 2 (Modern clients shutdown)
+ * Modern clients should instead register as a blocker by passing a promise to
+ * nsPIPlacesDatabase::shutdownClient (for example see sanitize.js), so they
+ * block Places shutdown until the promise is resolved.
+ * When profile-change-teardown is observed by async shutdown, it calls
+ * ClientsShutdownBlocker::BlockShutdown. This class is registered as a teardown
+ * phase blocker in Database::Init (see Database::mClientsShutdown).
+ * ClientsShutdownBlocker::BlockShudown waits for all the clients registered
+ * through nsPIPlacesDatabase::shutdownClient. When all the clients are done,
+ * its `Done` method is invoked, and it stops blocking the shutdown phase, so
+ * that it can continue.
+ *
+ * PHASE 3 (Connection shutdown)
+ * ConnectionBlocker is registered as a profile-before-change blocker in
+ * Database::Init (see Database::mConnectionShutdown).
+ * When profile-before-change is observer by async shutdown, it calls
+ * ConnectionShutdownBlocker::BlockShutdown.
+ * This is the last chance for any Places internal work, like privacy cleanups,
+ * before the connection is closed. This a places-will-close-connection
+ * notification is sent to legacy clients that must complete any operation in
+ * the same tick, since we won't wait for them.
+ * Then the control is passed to Database::Shutdown, that executes some sanity
+ * checks, clears cached statements and proceeds with asyncClose.
+ * Once the connection is definitely closed, Database will call back
+ * ConnectionBlocker::Complete. At this point a final
+ * places-connection-closed notification is sent, for testing purposes.
+ */
+
+/**
+ * A base AsyncShutdown blocker in charge of shutting down Places.
+ */
+class PlacesShutdownBlocker : public nsIAsyncShutdownBlocker
+{
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIASYNCSHUTDOWNBLOCKER
+
+ explicit PlacesShutdownBlocker(const nsString& aName);
+
+ /**
+ * `true` if we have not started shutdown, i.e. if
+ * `BlockShutdown()` hasn't been called yet, false otherwise.
+ */
+ static bool IsStarted() {
+ return sIsStarted;
+ }
+
+ // The current state, used internally and for forensics/debugging purposes.
+ // Not all the states make sense for all the derived classes.
+ enum States {
+ NOT_STARTED,
+ // Execution of `BlockShutdown` in progress.
+ RECEIVED_BLOCK_SHUTDOWN,
+
+ // Values specific to ClientsShutdownBlocker
+ // a. Set while we are waiting for clients to do their job and unblock us.
+ CALLED_WAIT_CLIENTS,
+ // b. Set when all the clients are done.
+ RECEIVED_DONE,
+
+ // Values specific to ConnectionShutdownBlocker
+ // a. Set after we notified observers that Places is closing the connection.
+ NOTIFIED_OBSERVERS_PLACES_WILL_CLOSE_CONNECTION,
+ // b. Set after we pass control to Database::Shutdown, and wait for it to
+ // close the connection and call our `Complete` method when done.
+ CALLED_STORAGESHUTDOWN,
+ // c. Set when Database has closed the connection and passed control to
+ // us through `Complete`.
+ RECEIVED_STORAGESHUTDOWN_COMPLETE,
+ // d. We have notified observers that Places has closed the connection.
+ NOTIFIED_OBSERVERS_PLACES_CONNECTION_CLOSED,
+ };
+ States State() {
+ return mState;
+ }
+
+protected:
+ // The blocker name, also used as barrier name.
+ nsString mName;
+ // The current state, see States.
+ States mState;
+ // The barrier optionally used to wait for clients.
+ nsMainThreadPtrHandle<nsIAsyncShutdownBarrier> mBarrier;
+ // The parent object who registered this as a blocker.
+ nsMainThreadPtrHandle<nsIAsyncShutdownClient> mParentClient;
+
+ // As tests may resurrect a dead `Database`, we use a counter to
+ // give the instances of `PlacesShutdownBlocker` unique names.
+ uint16_t mCounter;
+ static uint16_t sCounter;
+
+ static Atomic<bool> sIsStarted;
+
+ virtual ~PlacesShutdownBlocker() {}
+};
+
+/**
+ * Blocker also used to wait for clients, through an owned barrier.
+ */
+class ClientsShutdownBlocker final : public PlacesShutdownBlocker
+ , public nsIAsyncShutdownCompletionCallback
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIASYNCSHUTDOWNCOMPLETIONCALLBACK
+
+ explicit ClientsShutdownBlocker();
+
+ NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aParentClient) override;
+
+ already_AddRefed<nsIAsyncShutdownClient> GetClient();
+
+private:
+ ~ClientsShutdownBlocker() {}
+};
+
+/**
+ * Blocker used to wait when closing the database connection.
+ */
+class ConnectionShutdownBlocker final : public PlacesShutdownBlocker
+ , public mozIStorageCompletionCallback
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
+
+ NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aParentClient) override;
+
+ explicit ConnectionShutdownBlocker(mozilla::places::Database* aDatabase);
+
+private:
+ ~ConnectionShutdownBlocker() {}
+
+ // The owning database.
+ // The cycle is broken in method Complete(), once the connection
+ // has been closed by mozStorage.
+ RefPtr<mozilla::places::Database> mDatabase;
+};
+
+} // namespace places
+} // namespace mozilla
+
+#endif // mozilla_places_Shutdown_h_