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 : #ifndef mozilla_places_Shutdown_h_
6 : #define mozilla_places_Shutdown_h_
7 :
8 : #include "nsIAsyncShutdown.h"
9 : #include "Database.h"
10 : #include "nsProxyRelease.h"
11 :
12 : namespace mozilla {
13 : namespace places {
14 :
15 : class Database;
16 :
17 : /**
18 : * This is most of the code responsible for Places shutdown.
19 : *
20 : * PHASE 1 (Legacy clients shutdown)
21 : * The shutdown procedure begins when the Database singleton receives
22 : * profile-change-teardown (note that tests will instead notify nsNavHistory,
23 : * that forwards the notification to the Database instance).
24 : * Database::Observe first of all checks if initialization was completed
25 : * properly, to avoid race conditions, then it notifies "places-shutdown" to
26 : * legacy clients. Legacy clients are supposed to start and complete any
27 : * shutdown critical work in the same tick, since we won't wait for them.
28 :
29 : * PHASE 2 (Modern clients shutdown)
30 : * Modern clients should instead register as a blocker by passing a promise to
31 : * nsPIPlacesDatabase::shutdownClient (for example see sanitize.js), so they
32 : * block Places shutdown until the promise is resolved.
33 : * When profile-change-teardown is observed by async shutdown, it calls
34 : * ClientsShutdownBlocker::BlockShutdown. This class is registered as a teardown
35 : * phase blocker in Database::Init (see Database::mClientsShutdown).
36 : * ClientsShutdownBlocker::BlockShudown waits for all the clients registered
37 : * through nsPIPlacesDatabase::shutdownClient. When all the clients are done,
38 : * its `Done` method is invoked, and it stops blocking the shutdown phase, so
39 : * that it can continue.
40 : *
41 : * PHASE 3 (Connection shutdown)
42 : * ConnectionBlocker is registered as a profile-before-change blocker in
43 : * Database::Init (see Database::mConnectionShutdown).
44 : * When profile-before-change is observer by async shutdown, it calls
45 : * ConnectionShutdownBlocker::BlockShutdown.
46 : * This is the last chance for any Places internal work, like privacy cleanups,
47 : * before the connection is closed. This a places-will-close-connection
48 : * notification is sent to legacy clients that must complete any operation in
49 : * the same tick, since we won't wait for them.
50 : * Then the control is passed to Database::Shutdown, that executes some sanity
51 : * checks, clears cached statements and proceeds with asyncClose.
52 : * Once the connection is definitely closed, Database will call back
53 : * ConnectionBlocker::Complete. At this point a final
54 : * places-connection-closed notification is sent, for testing purposes.
55 : */
56 :
57 : /**
58 : * A base AsyncShutdown blocker in charge of shutting down Places.
59 : */
60 : class PlacesShutdownBlocker : public nsIAsyncShutdownBlocker
61 : {
62 : public:
63 : NS_DECL_THREADSAFE_ISUPPORTS
64 : NS_DECL_NSIASYNCSHUTDOWNBLOCKER
65 :
66 : explicit PlacesShutdownBlocker(const nsString& aName);
67 :
68 : /**
69 : * `true` if we have not started shutdown, i.e. if
70 : * `BlockShutdown()` hasn't been called yet, false otherwise.
71 : */
72 19 : static bool IsStarted() {
73 19 : return sIsStarted;
74 : }
75 :
76 : // The current state, used internally and for forensics/debugging purposes.
77 : // Not all the states make sense for all the derived classes.
78 : enum States {
79 : NOT_STARTED,
80 : // Execution of `BlockShutdown` in progress.
81 : RECEIVED_BLOCK_SHUTDOWN,
82 :
83 : // Values specific to ClientsShutdownBlocker
84 : // a. Set while we are waiting for clients to do their job and unblock us.
85 : CALLED_WAIT_CLIENTS,
86 : // b. Set when all the clients are done.
87 : RECEIVED_DONE,
88 :
89 : // Values specific to ConnectionShutdownBlocker
90 : // a. Set after we notified observers that Places is closing the connection.
91 : NOTIFIED_OBSERVERS_PLACES_WILL_CLOSE_CONNECTION,
92 : // b. Set after we pass control to Database::Shutdown, and wait for it to
93 : // close the connection and call our `Complete` method when done.
94 : CALLED_STORAGESHUTDOWN,
95 : // c. Set when Database has closed the connection and passed control to
96 : // us through `Complete`.
97 : RECEIVED_STORAGESHUTDOWN_COMPLETE,
98 : // d. We have notified observers that Places has closed the connection.
99 : NOTIFIED_OBSERVERS_PLACES_CONNECTION_CLOSED,
100 : };
101 0 : States State() {
102 0 : return mState;
103 : }
104 :
105 : protected:
106 : // The blocker name, also used as barrier name.
107 : nsString mName;
108 : // The current state, see States.
109 : States mState;
110 : // The barrier optionally used to wait for clients.
111 : nsMainThreadPtrHandle<nsIAsyncShutdownBarrier> mBarrier;
112 : // The parent object who registered this as a blocker.
113 : nsMainThreadPtrHandle<nsIAsyncShutdownClient> mParentClient;
114 :
115 : // As tests may resurrect a dead `Database`, we use a counter to
116 : // give the instances of `PlacesShutdownBlocker` unique names.
117 : uint16_t mCounter;
118 : static uint16_t sCounter;
119 :
120 : static Atomic<bool> sIsStarted;
121 :
122 0 : virtual ~PlacesShutdownBlocker() {}
123 : };
124 :
125 : /**
126 : * Blocker also used to wait for clients, through an owned barrier.
127 : */
128 : class ClientsShutdownBlocker final : public PlacesShutdownBlocker
129 : , public nsIAsyncShutdownCompletionCallback
130 : {
131 : public:
132 : NS_DECL_ISUPPORTS_INHERITED
133 : NS_DECL_NSIASYNCSHUTDOWNCOMPLETIONCALLBACK
134 :
135 : explicit ClientsShutdownBlocker();
136 :
137 : NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aParentClient) override;
138 :
139 : already_AddRefed<nsIAsyncShutdownClient> GetClient();
140 :
141 : private:
142 0 : ~ClientsShutdownBlocker() {}
143 : };
144 :
145 : /**
146 : * Blocker used to wait when closing the database connection.
147 : */
148 : class ConnectionShutdownBlocker final : public PlacesShutdownBlocker
149 : , public mozIStorageCompletionCallback
150 : {
151 : public:
152 : NS_DECL_ISUPPORTS_INHERITED
153 : NS_DECL_MOZISTORAGECOMPLETIONCALLBACK
154 :
155 : NS_IMETHOD BlockShutdown(nsIAsyncShutdownClient* aParentClient) override;
156 :
157 : explicit ConnectionShutdownBlocker(mozilla::places::Database* aDatabase);
158 :
159 : private:
160 0 : ~ConnectionShutdownBlocker() {}
161 :
162 : // The owning database.
163 : // The cycle is broken in method Complete(), once the connection
164 : // has been closed by mozStorage.
165 : RefPtr<mozilla::places::Database> mDatabase;
166 : };
167 :
168 : } // namespace places
169 : } // namespace mozilla
170 :
171 : #endif // mozilla_places_Shutdown_h_
|