Source code

Revision control

Other Tools

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