Back to index

lightning-sunbird  0.9+nobinonly
nsNSSShutDown.h
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 2002
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Kai Engert <kaie@netscape.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _INC_NSSShutDown_H
00039 #define _INC_NSSShutDown_H
00040 
00041 #include "nscore.h"
00042 #include "nspr.h"
00043 #include "pldhash.h"
00044 
00045 class nsNSSShutDownObject;
00046 class nsOnPK11LogoutCancelObject;
00047 
00048 // Singleton, owner by nsNSSShutDownList
00049 class nsNSSActivityState
00050 {
00051 public:
00052   nsNSSActivityState();
00053   ~nsNSSActivityState();
00054 
00055   // Call enter/leave when PSM enters a scope during which
00056   // shutting down NSS is prohibited.
00057   void enter();
00058   void leave();
00059   
00060   // Call enter/leave when PSM is about to show a UI
00061   // while still holding resources.
00062   void enterBlockingUIState();
00063   void leaveBlockingUIState();
00064   
00065   // Is the activity aware of any blocking PSM UI currently shown?
00066   PRBool isBlockingUIActive();
00067 
00068   // Is it forbidden to bring up an UI while holding resources?
00069   PRBool isUIForbidden();
00070   
00071   // Check whether setting the current thread restriction is possible.
00072   // If it is possible, and the "do_it_for_real" flag is used,
00073   // the state tracking will have ensured that we will stay in this state.
00074   // As of writing, this includes forbidding PSM UI.
00075   enum RealOrTesting {test_only, do_it_for_real};
00076   PRBool ifPossibleDisallowUI(RealOrTesting rot);
00077 
00078   // Notify the state tracking that going to the restricted state is
00079   // no longer planned.
00080   // As of writing, this includes clearing the "PSM UI forbidden" flag.
00081   void allowUI();
00082 
00083   // If currently no UI is shown, wait for all activity to stop,
00084   // and block any other thread on entering relevant PSM code.
00085   PRStatus restrictActivityToCurrentThread();
00086   
00087   // Go back to normal state.
00088   void releaseCurrentThreadActivityRestriction();
00089 
00090 private:
00091   // The lock protecting all our member variables.
00092   PRLock *mNSSActivityStateLock;
00093 
00094   // The activity variable, bound to our lock,
00095   // used either to signal the activity counter reaches zero,
00096   // or a thread restriction has been released.
00097   PRCondVar *mNSSActivityChanged;
00098 
00099   // The number of active scopes holding resources.
00100   int mNSSActivityCounter;
00101 
00102   // The number of scopes holding resources while blocked
00103   // showing an UI.
00104   int mBlockingUICounter;
00105 
00106   // Whether bringing up UI is currently forbidden
00107   PRBool mIsUIForbidden;
00108 
00109   // nsnull means "no restriction"
00110   // if != nsnull, activity is only allowed on that thread
00111   PRThread* mNSSRestrictedThread;
00112 };
00113 
00114 // Helper class that automatically enters/leaves the global activity state
00115 class nsNSSShutDownPreventionLock
00116 {
00117 public:
00118   nsNSSShutDownPreventionLock();
00119   ~nsNSSShutDownPreventionLock();
00120 };
00121 
00122 // Helper class that automatically enters/leaves the global UI tracking
00123 class nsPSMUITracker
00124 {
00125 public:
00126   nsPSMUITracker();
00127   ~nsPSMUITracker();
00128   
00129   PRBool isUIForbidden();
00130 };
00131 
00132 // Singleton, used by nsNSSComponent to track the list of PSM objects,
00133 // which hold NSS resources and support the "early cleanup mechanism".
00134 class nsNSSShutDownList
00135 {
00136 public:
00137   ~nsNSSShutDownList();
00138 
00139   static nsNSSShutDownList *construct();
00140   
00141   // track instances that support early cleanup
00142   static void remember(nsNSSShutDownObject *o);
00143   static void forget(nsNSSShutDownObject *o);
00144 
00145   // track instances that would like notification when
00146   // a PK11 logout operation is performed.
00147   static void remember(nsOnPK11LogoutCancelObject *o);
00148   static void forget(nsOnPK11LogoutCancelObject *o);
00149 
00150   // track the creation and destruction of SSL sockets
00151   // performed by clients using PSM services
00152   static void trackSSLSocketCreate();
00153   static void trackSSLSocketClose();
00154   static PRBool areSSLSocketsActive();
00155   
00156   // Are we able to do the early cleanup?
00157   // Returns failure if at the current time "early cleanup" is not possible.
00158   PRBool isUIActive();
00159 
00160   // If possible to do "early cleanup" at the current time, remember that we want to
00161   // do it, and disallow actions that would change the possibility.
00162   PRBool ifPossibleDisallowUI();
00163 
00164   // Notify that it is no longer planned to do the "early cleanup".
00165   void allowUI();
00166   
00167   // Do the "early cleanup", if possible.
00168   nsresult evaporateAllNSSResources();
00169 
00170   // PSM has been asked to log out of a token.
00171   // Notify all registered instances that want to react to that event.
00172   nsresult doPK11Logout();
00173   
00174   static nsNSSActivityState *getActivityState()
00175   {
00176     return singleton ? &singleton->mActivityState : nsnull;
00177   }
00178   
00179 private:
00180   nsNSSShutDownList();
00181   static PLDHashOperator PR_CALLBACK
00182   evaporateAllNSSResourcesHelper(PLDHashTable *table, PLDHashEntryHdr *hdr,
00183                                                         PRUint32 number, void *arg);
00184 
00185   static PLDHashOperator PR_CALLBACK
00186   doPK11LogoutHelper(PLDHashTable *table, PLDHashEntryHdr *hdr,
00187                                                     PRUint32 number, void *arg);
00188 protected:
00189   PRLock* mListLock;
00190   static nsNSSShutDownList *singleton;
00191   PLDHashTable mObjects;
00192   PRUint32 mActiveSSLSockets;
00193   PLDHashTable mPK11LogoutCancelObjects;
00194   nsNSSActivityState mActivityState;
00195 };
00196 
00197 /*
00198   A class deriving from nsNSSShutDownObject will have its instances
00199   automatically tracked in a list. However, it must follow some rules
00200   to assure correct behaviour.
00201   
00202   The tricky part is that it is not possible to call virtual
00203   functions from a destructor.
00204   
00205   The deriving class must override virtualDestroyNSSReference().
00206   Within this function, it should clean up all resources held to NSS.
00207   The function will be called by the global list, if it is time to
00208   shut down NSS before all references have been freed.
00209 
00210   The same code that goes into virtualDestroyNSSReference must
00211   also be called from the destructor of the deriving class,
00212   which is the standard cleanup (not called from the tracking list).
00213 
00214   Because of that duplication, it is suggested to implement a
00215   function destructorSafeDestroyNSSReference() in the deriving
00216   class, and make the implementation of virtualDestroyNSSReference()
00217   call destructorSafeDestroyNSSReference().
00218 
00219   The destructor of the derived class should call 
00220   destructorSafeDestroyNSSReference() and afterwards call
00221   shutdown(calledFromObject), in order to deregister with the
00222   tracking list, to ensure no additional attempt to free the resources
00223   will be made.
00224   
00225   Function destructorSafeDestroyNSSReference() must
00226   also ensure, that NSS resources have not been freed already.
00227   To achieve this, the deriving class should call 
00228   isAlreadyShutDown() to check.
00229   
00230   It is important that you make your implementation
00231   failsafe, and check whether the resources have already been freed,
00232   in each function that requires the resources.
00233   
00234   class derivedClass : public nsISomeInterface,
00235                        public nsNSSShutDownObject
00236   {
00237     virtual void virtualDestroyNSSReference()
00238     {
00239       destructorSafeDestroyNSSReference();
00240     }
00241     
00242     void destructorSafeDestroyNSSReference()
00243     {
00244       if (isAlreadyShutDown())
00245         return;
00246       
00247       // clean up all NSS resources here
00248     }
00249 
00250     virtual ~derivedClass()
00251     {
00252       destructorSafeDestroyNSSReference();
00253       shutdown(calledFromObject);
00254     }
00255     
00256     NS_IMETHODIMP doSomething()
00257     {
00258       if (isAlreadyShutDown())
00259         return NS_ERROR_NOT_AVAILABLE;
00260       
00261       // use the NSS resources and do something
00262     }
00263   };
00264 */
00265 
00266 class nsNSSShutDownObject
00267 {
00268 public:
00269 
00270   enum CalledFromType {calledFromList, calledFromObject};
00271 
00272   nsNSSShutDownObject()
00273   {
00274     mAlreadyShutDown = PR_FALSE;
00275     nsNSSShutDownList::remember(this);
00276   }
00277   
00278   virtual ~nsNSSShutDownObject()
00279   {
00280     // the derived class must call 
00281     //   shutdown(calledFromObject);
00282     // in its destructor
00283   }
00284   
00285   void shutdown(CalledFromType calledFrom)
00286   {
00287     if (!mAlreadyShutDown) {
00288       if (calledFromObject == calledFrom) {
00289         nsNSSShutDownList::forget(this);
00290       }
00291       if (calledFromList == calledFrom) {
00292         virtualDestroyNSSReference();
00293       }
00294       mAlreadyShutDown = PR_TRUE;
00295     }
00296   }
00297   
00298   PRBool isAlreadyShutDown() { return mAlreadyShutDown; }
00299 
00300 protected:
00301   virtual void virtualDestroyNSSReference() = 0;
00302 private:
00303   volatile PRBool mAlreadyShutDown;
00304 };
00305 
00306 class nsOnPK11LogoutCancelObject
00307 {
00308 public:
00309   nsOnPK11LogoutCancelObject()
00310   :mIsLoggedOut(PR_FALSE)
00311   {
00312     nsNSSShutDownList::remember(this);
00313   }
00314   
00315   virtual ~nsOnPK11LogoutCancelObject()
00316   {
00317     nsNSSShutDownList::forget(this);
00318   }
00319   
00320   void logout()
00321   {
00322     // We do not care for a race condition.
00323     // Once the bool arrived at false,
00324     // later calls to isPK11LoggedOut() will see it.
00325     // This is a one-time change from 0 to 1.
00326     
00327     mIsLoggedOut = PR_TRUE;
00328   }
00329   
00330   PRBool isPK11LoggedOut()
00331   {
00332     return mIsLoggedOut;
00333   }
00334 
00335 private:
00336   volatile PRBool mIsLoggedOut;
00337 };
00338 
00339 #endif