1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is Mozilla Communicator.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Netscape Communications Corporation.
18 : * Portions created by the Initial Developer are Copyright (C) 2002
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Kai Engert <kaie@netscape.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifndef _INC_NSSShutDown_H
39 : #define _INC_NSSShutDown_H
40 :
41 : #include "nscore.h"
42 : #include "nspr.h"
43 : #include "pldhash.h"
44 : #include "mozilla/CondVar.h"
45 : #include "mozilla/Mutex.h"
46 :
47 : class nsNSSShutDownObject;
48 : class nsOnPK11LogoutCancelObject;
49 :
50 : // Singleton, owner by nsNSSShutDownList
51 : class nsNSSActivityState
52 : {
53 : public:
54 : nsNSSActivityState();
55 : ~nsNSSActivityState();
56 :
57 : // Call enter/leave when PSM enters a scope during which
58 : // shutting down NSS is prohibited.
59 : void enter();
60 : void leave();
61 :
62 : // Call enter/leave when PSM is about to show a UI
63 : // while still holding resources.
64 : void enterBlockingUIState();
65 : void leaveBlockingUIState();
66 :
67 : // Is the activity aware of any blocking PSM UI currently shown?
68 : bool isBlockingUIActive();
69 :
70 : // Is it forbidden to bring up an UI while holding resources?
71 : bool isUIForbidden();
72 :
73 : // Check whether setting the current thread restriction is possible.
74 : // If it is possible, and the "do_it_for_real" flag is used,
75 : // the state tracking will have ensured that we will stay in this state.
76 : // As of writing, this includes forbidding PSM UI.
77 : enum RealOrTesting {test_only, do_it_for_real};
78 : bool ifPossibleDisallowUI(RealOrTesting rot);
79 :
80 : // Notify the state tracking that going to the restricted state is
81 : // no longer planned.
82 : // As of writing, this includes clearing the "PSM UI forbidden" flag.
83 : void allowUI();
84 :
85 : // If currently no UI is shown, wait for all activity to stop,
86 : // and block any other thread on entering relevant PSM code.
87 : PRStatus restrictActivityToCurrentThread();
88 :
89 : // Go back to normal state.
90 : void releaseCurrentThreadActivityRestriction();
91 :
92 : private:
93 : // The lock protecting all our member variables.
94 : mozilla::Mutex mNSSActivityStateLock;
95 :
96 : // The activity variable, bound to our lock,
97 : // used either to signal the activity counter reaches zero,
98 : // or a thread restriction has been released.
99 : mozilla::CondVar mNSSActivityChanged;
100 :
101 : // The number of active scopes holding resources.
102 : int mNSSActivityCounter;
103 :
104 : // The number of scopes holding resources while blocked
105 : // showing an UI.
106 : int mBlockingUICounter;
107 :
108 : // Whether bringing up UI is currently forbidden
109 : bool mIsUIForbidden;
110 :
111 : // nsnull means "no restriction"
112 : // if != nsnull, activity is only allowed on that thread
113 : PRThread* mNSSRestrictedThread;
114 : };
115 :
116 : // Helper class that automatically enters/leaves the global activity state
117 : class nsNSSShutDownPreventionLock
118 : {
119 : public:
120 : nsNSSShutDownPreventionLock();
121 : ~nsNSSShutDownPreventionLock();
122 : };
123 :
124 : // Helper class that automatically enters/leaves the global UI tracking
125 : class nsPSMUITracker
126 : {
127 : public:
128 : nsPSMUITracker();
129 : ~nsPSMUITracker();
130 :
131 : bool isUIForbidden();
132 : };
133 :
134 : // Singleton, used by nsNSSComponent to track the list of PSM objects,
135 : // which hold NSS resources and support the "early cleanup mechanism".
136 : class nsNSSShutDownList
137 : {
138 : public:
139 : ~nsNSSShutDownList();
140 :
141 : static nsNSSShutDownList *construct();
142 :
143 : // track instances that support early cleanup
144 : static void remember(nsNSSShutDownObject *o);
145 : static void forget(nsNSSShutDownObject *o);
146 :
147 : // track instances that would like notification when
148 : // a PK11 logout operation is performed.
149 : static void remember(nsOnPK11LogoutCancelObject *o);
150 : static void forget(nsOnPK11LogoutCancelObject *o);
151 :
152 : // track the creation and destruction of SSL sockets
153 : // performed by clients using PSM services
154 : static void trackSSLSocketCreate();
155 : static void trackSSLSocketClose();
156 : static bool areSSLSocketsActive();
157 :
158 : // Are we able to do the early cleanup?
159 : // Returns failure if at the current time "early cleanup" is not possible.
160 : bool isUIActive();
161 :
162 : // If possible to do "early cleanup" at the current time, remember that we want to
163 : // do it, and disallow actions that would change the possibility.
164 : bool ifPossibleDisallowUI();
165 :
166 : // Notify that it is no longer planned to do the "early cleanup".
167 : void allowUI();
168 :
169 : // Do the "early cleanup", if possible.
170 : nsresult evaporateAllNSSResources();
171 :
172 : // PSM has been asked to log out of a token.
173 : // Notify all registered instances that want to react to that event.
174 : nsresult doPK11Logout();
175 :
176 182410 : static nsNSSActivityState *getActivityState()
177 : {
178 182410 : return singleton ? &singleton->mActivityState : nsnull;
179 : }
180 :
181 : private:
182 : nsNSSShutDownList();
183 : static PLDHashOperator PR_CALLBACK
184 : evaporateAllNSSResourcesHelper(PLDHashTable *table, PLDHashEntryHdr *hdr,
185 : PRUint32 number, void *arg);
186 :
187 : static PLDHashOperator PR_CALLBACK
188 : doPK11LogoutHelper(PLDHashTable *table, PLDHashEntryHdr *hdr,
189 : PRUint32 number, void *arg);
190 : protected:
191 : mozilla::Mutex mListLock;
192 : static nsNSSShutDownList *singleton;
193 : PLDHashTable mObjects;
194 : PRUint32 mActiveSSLSockets;
195 : PLDHashTable mPK11LogoutCancelObjects;
196 : nsNSSActivityState mActivityState;
197 : };
198 :
199 : /*
200 : A class deriving from nsNSSShutDownObject will have its instances
201 : automatically tracked in a list. However, it must follow some rules
202 : to assure correct behaviour.
203 :
204 : The tricky part is that it is not possible to call virtual
205 : functions from a destructor.
206 :
207 : The deriving class must override virtualDestroyNSSReference().
208 : Within this function, it should clean up all resources held to NSS.
209 : The function will be called by the global list, if it is time to
210 : shut down NSS before all references have been freed.
211 :
212 : The same code that goes into virtualDestroyNSSReference must
213 : also be called from the destructor of the deriving class,
214 : which is the standard cleanup (not called from the tracking list).
215 :
216 : Because of that duplication, it is suggested to implement a
217 : function destructorSafeDestroyNSSReference() in the deriving
218 : class, and make the implementation of virtualDestroyNSSReference()
219 : call destructorSafeDestroyNSSReference().
220 :
221 : The destructor of the derived class should call
222 : destructorSafeDestroyNSSReference() and afterwards call
223 : shutdown(calledFromObject), in order to deregister with the
224 : tracking list, to ensure no additional attempt to free the resources
225 : will be made.
226 :
227 : Function destructorSafeDestroyNSSReference() must
228 : also ensure, that NSS resources have not been freed already.
229 : To achieve this, the deriving class should call
230 : isAlreadyShutDown() to check.
231 :
232 : It is important that you make your implementation
233 : failsafe, and check whether the resources have already been freed,
234 : in each function that requires the resources.
235 :
236 : class derivedClass : public nsISomeInterface,
237 : public nsNSSShutDownObject
238 : {
239 : virtual void virtualDestroyNSSReference()
240 : {
241 : destructorSafeDestroyNSSReference();
242 : }
243 :
244 : void destructorSafeDestroyNSSReference()
245 : {
246 : if (isAlreadyShutDown())
247 : return;
248 :
249 : // clean up all NSS resources here
250 : }
251 :
252 : virtual ~derivedClass()
253 : {
254 : destructorSafeDestroyNSSReference();
255 : shutdown(calledFromObject);
256 : }
257 :
258 : NS_IMETHODIMP doSomething()
259 : {
260 : if (isAlreadyShutDown())
261 : return NS_ERROR_NOT_AVAILABLE;
262 :
263 : // use the NSS resources and do something
264 : }
265 : };
266 : */
267 :
268 : class nsNSSShutDownObject
269 : {
270 : public:
271 :
272 : enum CalledFromType {calledFromList, calledFromObject};
273 :
274 3654 : nsNSSShutDownObject()
275 3654 : {
276 3654 : mAlreadyShutDown = false;
277 3654 : nsNSSShutDownList::remember(this);
278 3654 : }
279 :
280 3654 : virtual ~nsNSSShutDownObject()
281 3654 : {
282 : // the derived class must call
283 : // shutdown(calledFromObject);
284 : // in its destructor
285 7308 : }
286 :
287 3654 : void shutdown(CalledFromType calledFrom)
288 : {
289 3654 : if (!mAlreadyShutDown) {
290 3654 : if (calledFromObject == calledFrom) {
291 1835 : nsNSSShutDownList::forget(this);
292 : }
293 3654 : if (calledFromList == calledFrom) {
294 1819 : virtualDestroyNSSReference();
295 : }
296 3654 : mAlreadyShutDown = true;
297 : }
298 3654 : }
299 :
300 10914 : bool isAlreadyShutDown() { return mAlreadyShutDown; }
301 :
302 : protected:
303 : virtual void virtualDestroyNSSReference() = 0;
304 : private:
305 : volatile bool mAlreadyShutDown;
306 : };
307 :
308 : class nsOnPK11LogoutCancelObject
309 : {
310 : public:
311 4 : nsOnPK11LogoutCancelObject()
312 4 : :mIsLoggedOut(false)
313 : {
314 4 : nsNSSShutDownList::remember(this);
315 4 : }
316 :
317 4 : virtual ~nsOnPK11LogoutCancelObject()
318 4 : {
319 4 : nsNSSShutDownList::forget(this);
320 8 : }
321 :
322 0 : void logout()
323 : {
324 : // We do not care for a race condition.
325 : // Once the bool arrived at false,
326 : // later calls to isPK11LoggedOut() will see it.
327 : // This is a one-time change from 0 to 1.
328 :
329 0 : mIsLoggedOut = true;
330 0 : }
331 :
332 326 : bool isPK11LoggedOut()
333 : {
334 326 : return mIsLoggedOut;
335 : }
336 :
337 : private:
338 : volatile bool mIsLoggedOut;
339 : };
340 :
341 : #endif
|