/work/obj-fuzz/dist/include/mozilla/places/Shutdown.h
Line | Count | Source (jump to first uncovered line) |
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 | | * nsINavHistoryService::shutdownClient (for example see Sanitizer.jsm), 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 nsINavHistoryService::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 | | * Then the control is passed to Database::Shutdown, that executes some sanity |
47 | | * checks, clears cached statements and proceeds with asyncClose. |
48 | | * Once the connection is definitely closed, Database will call back |
49 | | * ConnectionBlocker::Complete. At this point a final |
50 | | * places-connection-closed notification is sent, for testing purposes. |
51 | | */ |
52 | | |
53 | | /** |
54 | | * A base AsyncShutdown blocker in charge of shutting down Places. |
55 | | */ |
56 | | class PlacesShutdownBlocker : public nsIAsyncShutdownBlocker |
57 | | , public nsIAsyncShutdownCompletionCallback |
58 | | { |
59 | | public: |
60 | | NS_DECL_THREADSAFE_ISUPPORTS |
61 | | NS_DECL_NSIASYNCSHUTDOWNBLOCKER |
62 | | NS_DECL_NSIASYNCSHUTDOWNCOMPLETIONCALLBACK |
63 | | |
64 | | explicit PlacesShutdownBlocker(const nsString& aName); |
65 | | |
66 | | already_AddRefed<nsIAsyncShutdownClient> GetClient(); |
67 | | |
68 | | /** |
69 | | * `true` if we have not started shutdown, i.e. if |
70 | | * `BlockShutdown()` hasn't been called yet, false otherwise. |
71 | | */ |
72 | | static bool IsStarted() { |
73 | | 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 | | States State() { |
102 | | 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 | | 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 | | { |
130 | | public: |
131 | | NS_INLINE_DECL_REFCOUNTING_INHERITED(ClientsShutdownBlocker, |
132 | | PlacesShutdownBlocker) |
133 | | |
134 | | explicit ClientsShutdownBlocker(); |
135 | | |
136 | | NS_IMETHOD Done() override; |
137 | | private: |
138 | 0 | ~ClientsShutdownBlocker() {} |
139 | | }; |
140 | | |
141 | | /** |
142 | | * Blocker used to wait when closing the database connection. |
143 | | */ |
144 | | class ConnectionShutdownBlocker final : public PlacesShutdownBlocker |
145 | | , public mozIStorageCompletionCallback |
146 | | { |
147 | | public: |
148 | | NS_DECL_ISUPPORTS_INHERITED |
149 | | NS_DECL_MOZISTORAGECOMPLETIONCALLBACK |
150 | | |
151 | | explicit ConnectionShutdownBlocker(mozilla::places::Database* aDatabase); |
152 | | |
153 | | NS_IMETHOD Done() override; |
154 | | |
155 | | private: |
156 | | ~ConnectionShutdownBlocker() {} |
157 | | |
158 | | // The owning database. |
159 | | // The cycle is broken in method Complete(), once the connection |
160 | | // has been closed by mozStorage. |
161 | | RefPtr<mozilla::places::Database> mDatabase; |
162 | | }; |
163 | | |
164 | | } // namespace places |
165 | | } // namespace mozilla |
166 | | |
167 | | #endif // mozilla_places_Shutdown_h_ |