зеркало из https://github.com/mozilla/pjs.git
Bug 326491 - cleanup observers on shutdown even if the observer service is leaked, r=darin
This commit is contained in:
Родитель
eac373d533
Коммит
05825942c6
|
@ -93,7 +93,6 @@
|
|||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefBranch2.h"
|
||||
#include "nsIWritablePropertyBag2.h"
|
||||
#include "nsObserverService.h"
|
||||
|
||||
// we want to explore making the document own the load group
|
||||
// so we can associate the document URI with the load group.
|
||||
|
|
|
@ -84,6 +84,13 @@
|
|||
*/
|
||||
#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1"
|
||||
|
||||
/**
|
||||
* Observer Service ContractID
|
||||
* The observer service implements the global nsIObserverService object.
|
||||
* It should be used from the main thread only.
|
||||
*/
|
||||
#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1"
|
||||
|
||||
/**
|
||||
* The following are the CIDs and Contract IDs of the nsISupports wrappers for
|
||||
* primative types.
|
||||
|
|
|
@ -681,8 +681,9 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
|
|||
nsCOMPtr <nsIEventQueue> currentQ;
|
||||
NS_GetCurrentEventQ(getter_AddRefs(currentQ), eqs);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
do_GetService("@mozilla.org/observer-service;1");
|
||||
nsRefPtr<nsObserverService> observerService;
|
||||
CallGetService("@mozilla.org/observer-service;1",
|
||||
(nsObserverService**) getter_AddRefs(observerService));
|
||||
|
||||
if (observerService)
|
||||
{
|
||||
|
@ -721,10 +722,13 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
|
|||
|
||||
// We save the "xpcom-shutdown-loaders" observers to notify after
|
||||
// the observerservice is gone.
|
||||
if (observerService)
|
||||
if (observerService) {
|
||||
observerService->
|
||||
EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID,
|
||||
getter_AddRefs(moduleLoaders));
|
||||
|
||||
observerService->Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
// XPCOM is officially in shutdown mode NOW
|
||||
|
|
|
@ -99,7 +99,6 @@ EXPORTS = \
|
|||
nsIByteBuffer.h \
|
||||
nsIUnicharBuffer.h \
|
||||
nsInt64.h \
|
||||
nsObserverService.h \
|
||||
nsRecyclingAllocator.h \
|
||||
nsStaticNameTable.h \
|
||||
nsStaticAtom.h \
|
||||
|
|
|
@ -37,53 +37,29 @@
|
|||
|
||||
#include "nsObserverList.h"
|
||||
|
||||
#include "pratom.h"
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
#include "nsIWeakReference.h"
|
||||
|
||||
nsObserverList::nsObserverList(nsresult &rv)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsObserverList);
|
||||
mLock = PR_NewLock();
|
||||
if (!mLock)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsObserverList::~nsObserverList(void)
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsObserverList);
|
||||
if (mLock)
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
|
||||
{
|
||||
NS_ENSURE_ARG(anObserver);
|
||||
NS_ASSERTION(anObserver, "Null input");
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
if (!ownsWeak) {
|
||||
ObserverRef* o = mObservers.AppendElement(anObserver);
|
||||
if (!o)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
nsCOMPtr<nsISupports> observerRef;
|
||||
if (ownsWeak) {
|
||||
nsCOMPtr<nsISupportsWeakReference>
|
||||
weakRefFactory(do_QueryInterface(anObserver));
|
||||
NS_ASSERTION(weakRefFactory,
|
||||
"Doesn't implement nsISupportsWeakReference");
|
||||
if (weakRefFactory)
|
||||
weakRefFactory->
|
||||
GetWeakReference((nsIWeakReference**)(nsISupports**)
|
||||
getter_AddRefs(observerRef));
|
||||
} else {
|
||||
observerRef = anObserver;
|
||||
return NS_OK;
|
||||
}
|
||||
if (!observerRef)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(anObserver);
|
||||
if (!weak)
|
||||
return NS_NOINTERFACE;
|
||||
|
||||
if (!mObservers.AppendObject(observerRef))
|
||||
ObserverRef *o = mObservers.AppendElement(weak);
|
||||
if (!o)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return NS_OK;
|
||||
|
@ -92,51 +68,25 @@ nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
|
|||
nsresult
|
||||
nsObserverList::RemoveObserver(nsIObserver* anObserver)
|
||||
{
|
||||
NS_ENSURE_ARG(anObserver);
|
||||
NS_ASSERTION(anObserver, "Null input");
|
||||
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
if (mObservers.RemoveObject(anObserver))
|
||||
if (mObservers.RemoveElement(NS_STATIC_CAST(nsISupports*, anObserver)))
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsISupportsWeakReference>
|
||||
weakRefFactory(do_QueryInterface(anObserver));
|
||||
if (!weakRefFactory)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr<nsIWeakReference> observerRef;
|
||||
weakRefFactory->GetWeakReference(getter_AddRefs(observerRef));
|
||||
|
||||
nsCOMPtr<nsIWeakReference> observerRef = do_GetWeakReference(anObserver);
|
||||
if (!observerRef)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (!mObservers.RemoveObject(observerRef))
|
||||
if (!mObservers.RemoveElement(observerRef))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsObserverEnumerator : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsObserverEnumerator(nsCOMArray<nsISupports> &aObservers);
|
||||
|
||||
private:
|
||||
~nsObserverEnumerator() { }
|
||||
|
||||
PRUint32 mIndex; // Counts down, ends at 0
|
||||
nsCOMArray<nsISupports> mObservers;
|
||||
};
|
||||
|
||||
nsresult
|
||||
nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator)
|
||||
{
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
nsRefPtr<nsObserverEnumerator> e(new nsObserverEnumerator(mObservers));
|
||||
nsRefPtr<nsObserverEnumerator> e(new nsObserverEnumerator(this));
|
||||
if (!e)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
|
@ -144,41 +94,82 @@ nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsObserverEnumerator::nsObserverEnumerator(nsCOMArray<nsISupports> &aObservers)
|
||||
void
|
||||
nsObserverList::EnumerateObservers(EnumObserversFunc aFunc, void *aClosure)
|
||||
{
|
||||
for (PRInt32 i = 0; i < aObservers.Count(); ++i) {
|
||||
nsCOMPtr<nsIWeakReference> weak(do_QueryInterface(aObservers[i]));
|
||||
if (weak) {
|
||||
nsCOMPtr<nsISupports> strong(do_QueryReferent(weak));
|
||||
if (strong)
|
||||
mObservers.AppendObject(strong);
|
||||
for (PRInt32 i = mObservers.Length() - 1; i >= 0; --i) {
|
||||
if (mObservers[i].isWeakRef) {
|
||||
nsCOMPtr<nsIObserver> o(do_QueryReferent(mObservers[i].asWeak()));
|
||||
if (o) {
|
||||
aFunc(o, aClosure);
|
||||
}
|
||||
else {
|
||||
// the object has gone away, remove the weakref
|
||||
mObservers.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mObservers.AppendObject(aObservers[i]);
|
||||
aFunc(mObservers[i].asObserver(), aClosure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mIndex = mObservers.Count();
|
||||
struct NotifyData
|
||||
{
|
||||
nsISupports* aSubject;
|
||||
const char *aTopic;
|
||||
const PRUnichar *someData;
|
||||
};
|
||||
|
||||
void
|
||||
nsObserverList::NotifyObservers(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const PRUnichar *someData)
|
||||
{
|
||||
NotifyData nd = { aSubject, aTopic, someData };
|
||||
EnumerateObservers(Notify, &nd);
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverList::Notify(nsIObserver* aObserver, void *aClosure)
|
||||
{
|
||||
NotifyData *nd = NS_REINTERPRET_CAST(NotifyData*, aClosure);
|
||||
aObserver->Observe(nd->aSubject, nd->aTopic, nd->someData);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsObserverEnumerator, nsISimpleEnumerator)
|
||||
|
||||
void
|
||||
nsObserverEnumerator::Fill(nsIObserver* aObserver, void *aClosure)
|
||||
{
|
||||
nsObserverEnumerator* e =
|
||||
NS_REINTERPRET_CAST(nsObserverEnumerator*, aClosure);
|
||||
e->mObservers.AppendObject(aObserver);
|
||||
}
|
||||
|
||||
nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList)
|
||||
: mIndex(0)
|
||||
{
|
||||
mObservers.SetCapacity(aObserverList->mObservers.Length());
|
||||
aObserverList->EnumerateObservers(Fill, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverEnumerator::HasMoreElements(PRBool *aResult)
|
||||
{
|
||||
*aResult = (mIndex > 0);
|
||||
*aResult = (mIndex < mObservers.Count());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverEnumerator::GetNext(nsISupports* *aResult)
|
||||
{
|
||||
if (!mIndex) {
|
||||
if (mIndex == mObservers.Count()) {
|
||||
NS_ERROR("Enumerating after HasMoreElements returned false.");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
--mIndex;
|
||||
NS_ADDREF(*aResult = mObservers[mIndex]);
|
||||
++mIndex;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -39,25 +39,88 @@
|
|||
#define nsObserverList_h___
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCOMArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
class nsISimpleEnumerator;
|
||||
class nsIObserver;
|
||||
struct ObserverRef
|
||||
{
|
||||
ObserverRef(const ObserverRef& o) :
|
||||
isWeakRef(o.isWeakRef), ref(o.ref) { }
|
||||
|
||||
ObserverRef(nsIObserver* aObserver) : isWeakRef(PR_FALSE), ref(aObserver) { }
|
||||
ObserverRef(nsIWeakReference* aWeak) : isWeakRef(PR_TRUE), ref(aWeak) { }
|
||||
|
||||
class nsObserverList
|
||||
PRBool isWeakRef;
|
||||
nsCOMPtr<nsISupports> ref;
|
||||
|
||||
nsIObserver* asObserver() {
|
||||
NS_ASSERTION(!isWeakRef, "Isn't a strong ref.");
|
||||
return NS_STATIC_CAST(nsIObserver*, (nsISupports*) ref);
|
||||
}
|
||||
|
||||
nsIWeakReference* asWeak() {
|
||||
NS_ASSERTION(isWeakRef, "Isn't a weak ref.");
|
||||
return NS_STATIC_CAST(nsIWeakReference*, (nsISupports*) ref);
|
||||
}
|
||||
|
||||
PRBool operator==(nsISupports* b) const { return ref == b; }
|
||||
};
|
||||
|
||||
class nsObserverList : public nsCharPtrHashKey
|
||||
{
|
||||
public:
|
||||
nsObserverList(nsresult &rv);
|
||||
~nsObserverList();
|
||||
nsObserverList(const char *key) : nsCharPtrHashKey(key)
|
||||
{ MOZ_COUNT_CTOR(nsObserverList); }
|
||||
|
||||
~nsObserverList() { MOZ_COUNT_DTOR(nsObserverList); }
|
||||
|
||||
nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak);
|
||||
nsresult RemoveObserver(nsIObserver* anObserver);
|
||||
|
||||
void NotifyObservers(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const PRUnichar *someData);
|
||||
nsresult GetObserverList(nsISimpleEnumerator** anEnumerator);
|
||||
|
||||
protected:
|
||||
PRLock* mLock;
|
||||
nsCOMArray<nsISupports> mObservers;
|
||||
|
||||
private:
|
||||
friend class nsObserverEnumerator;
|
||||
|
||||
typedef void (*EnumObserversFunc)(nsIObserver* aObserver, void *aClosure);
|
||||
|
||||
// EnumerateObservers passes all the registered observers to aFunc
|
||||
// in LIFO order. If there are any stale weak references they are
|
||||
// removed during enumeration. aFunc must not modify the observerlist
|
||||
// during enumeration.
|
||||
void EnumerateObservers(EnumObserversFunc aFunc, void *aClosure);
|
||||
|
||||
// Static helper function for NotifyObservers
|
||||
static void Notify(nsIObserver* aObserver, void *aClosure);
|
||||
|
||||
nsTArray<ObserverRef> mObservers;
|
||||
|
||||
};
|
||||
|
||||
class nsObserverEnumerator : public nsISimpleEnumerator
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISIMPLEENUMERATOR
|
||||
|
||||
nsObserverEnumerator(nsObserverList* aObserverList);
|
||||
|
||||
private:
|
||||
~nsObserverEnumerator() { }
|
||||
|
||||
// Static helper function for the constructor
|
||||
static void Fill(nsIObserver* aObserver, void *aClosure);
|
||||
|
||||
PRInt32 mIndex; // Counts up from 0
|
||||
nsCOMArray<nsIObserver> mObservers;
|
||||
};
|
||||
|
||||
#endif /* nsObserverList_h___ */
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "prlog.h"
|
||||
#include "prlock.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIComponentManager.h"
|
||||
|
@ -48,6 +48,8 @@
|
|||
#include "nsObserverList.h"
|
||||
#include "nsHashtable.h"
|
||||
#include "nsIWeakReference.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsIEnumerator.h"
|
||||
|
||||
#define NOTIFY_GLOBAL_OBSERVERS
|
||||
|
||||
|
@ -68,17 +70,26 @@ PRLogModuleInfo* observerServiceLog = nsnull;
|
|||
// nsObserverService Implementation
|
||||
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsObserverService, nsIObserverService)
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS2(nsObserverService, nsIObserverService, nsObserverService)
|
||||
|
||||
nsObserverService::nsObserverService()
|
||||
: mObserverTopicTable(nsnull)
|
||||
nsObserverService::nsObserverService() :
|
||||
mShuttingDown(PR_FALSE)
|
||||
{
|
||||
mObserverTopicTable.Init();
|
||||
}
|
||||
|
||||
nsObserverService::~nsObserverService(void)
|
||||
{
|
||||
if(mObserverTopicTable)
|
||||
delete mObserverTopicTable;
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
nsObserverService::Shutdown()
|
||||
{
|
||||
mShuttingDown = PR_TRUE;
|
||||
|
||||
if (mObserverTopicTable.IsInitialized())
|
||||
mObserverTopicTable.Clear();
|
||||
}
|
||||
|
||||
NS_METHOD
|
||||
|
@ -89,158 +100,85 @@ nsObserverService::Create(nsISupports* outer, const nsIID& aIID, void* *aInstanc
|
|||
observerServiceLog = PR_NewLogModule("ObserverService");
|
||||
#endif
|
||||
|
||||
nsresult rv;
|
||||
nsObserverService* os = new nsObserverService();
|
||||
if (os == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(os);
|
||||
rv = os->QueryInterface(aIID, aInstancePtr);
|
||||
NS_RELEASE(os);
|
||||
return rv;
|
||||
}
|
||||
nsRefPtr<nsObserverService> os = new nsObserverService();
|
||||
|
||||
static PRBool PR_CALLBACK
|
||||
ReleaseObserverList(nsHashKey *aKey, void *aData, void* closure)
|
||||
{
|
||||
nsObserverList* observerList = NS_STATIC_CAST(nsObserverList*, aData);
|
||||
delete(observerList);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
nsresult nsObserverService::GetObserverList(const char* aTopic, nsObserverList** anObserverList)
|
||||
{
|
||||
if (anObserverList == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
if(mObserverTopicTable == nsnull)
|
||||
{
|
||||
mObserverTopicTable = new nsObjectHashtable(nsnull,
|
||||
nsnull, // should never be cloned
|
||||
ReleaseObserverList,
|
||||
nsnull,
|
||||
256,
|
||||
PR_TRUE);
|
||||
if (mObserverTopicTable == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
|
||||
nsCStringKey key(aTopic);
|
||||
|
||||
nsObserverList *topicObservers;
|
||||
topicObservers = (nsObserverList *) mObserverTopicTable->Get(&key);
|
||||
|
||||
if (topicObservers)
|
||||
{
|
||||
*anObserverList = topicObservers;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
topicObservers = new nsObserverList(rv);
|
||||
if (!topicObservers)
|
||||
// The cast is required for MSVC6, otherwise it complains about calling
|
||||
// a private function.
|
||||
if (!os || !((nsObserverService*) os)->mObserverTopicTable.IsInitialized())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
delete topicObservers;
|
||||
return rv;
|
||||
return os->QueryInterface(aIID, aInstancePtr);
|
||||
}
|
||||
|
||||
#define NS_ENSURE_VALIDCALL \
|
||||
if (!nsIThread::IsMainThread()) { \
|
||||
NS_ERROR("Using observer service off the main thread!"); \
|
||||
return NS_ERROR_UNEXPECTED; \
|
||||
} \
|
||||
if (mShuttingDown) { \
|
||||
NS_ERROR("Using observer service after XPCOM shutdown!"); \
|
||||
return NS_ERROR_ILLEGAL_DURING_SHUTDOWN; \
|
||||
}
|
||||
|
||||
*anObserverList = topicObservers;
|
||||
mObserverTopicTable->Put(&key, topicObservers);
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic,
|
||||
PRBool ownsWeak)
|
||||
{
|
||||
NS_ENSURE_VALIDCALL
|
||||
NS_ENSURE_ARG(anObserver && aTopic);
|
||||
|
||||
nsObserverList *observerList = mObserverTopicTable.PutEntry(aTopic);
|
||||
if (!observerList)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
return observerList->AddObserver(anObserver, ownsWeak);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsObserverService::AddObserver(nsIObserver* anObserver, const char* aTopic, PRBool ownsWeak)
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic)
|
||||
{
|
||||
nsObserverList* anObserverList;
|
||||
nsresult rv;
|
||||
NS_ENSURE_VALIDCALL
|
||||
NS_ENSURE_ARG(anObserver && aTopic);
|
||||
|
||||
if (anObserver == nsnull || aTopic == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (!observerList)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = GetObserverList(aTopic, &anObserverList);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return anObserverList->AddObserver(anObserver, ownsWeak);
|
||||
return observerList->RemoveObserver(anObserver);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsObserverService::RemoveObserver(nsIObserver* anObserver, const char* aTopic)
|
||||
NS_IMETHODIMP
|
||||
nsObserverService::EnumerateObservers(const char* aTopic,
|
||||
nsISimpleEnumerator** anEnumerator)
|
||||
{
|
||||
nsObserverList* anObserverList;
|
||||
nsresult rv;
|
||||
NS_ENSURE_VALIDCALL
|
||||
NS_ENSURE_ARG(aTopic && anEnumerator);
|
||||
|
||||
if (anObserver == nsnull || aTopic == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (!observerList)
|
||||
return NS_NewEmptyEnumerator(anEnumerator);
|
||||
|
||||
rv = GetObserverList(aTopic, &anObserverList);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return anObserverList->RemoveObserver(anObserver);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsObserverService::EnumerateObservers(const char* aTopic, nsISimpleEnumerator** anEnumerator)
|
||||
{
|
||||
nsObserverList* anObserverList;
|
||||
nsresult rv;
|
||||
|
||||
if (anEnumerator == nsnull || aTopic == nsnull)
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
|
||||
rv = GetObserverList(aTopic, &anObserverList);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return anObserverList->GetObserverList(anEnumerator);
|
||||
return observerList->GetObserverList(anEnumerator);
|
||||
}
|
||||
|
||||
// Enumerate observers of aTopic and call Observe on each.
|
||||
NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const PRUnichar *someData) {
|
||||
nsresult rv = NS_OK;
|
||||
#ifdef NOTIFY_GLOBAL_OBSERVERS
|
||||
nsCOMPtr<nsISimpleEnumerator> globalObservers;
|
||||
#endif
|
||||
nsCOMPtr<nsISimpleEnumerator> observers;
|
||||
nsCOMPtr<nsISupports> observerRef;
|
||||
const PRUnichar *someData)
|
||||
{
|
||||
NS_ENSURE_VALIDCALL
|
||||
NS_ENSURE_ARG(aTopic);
|
||||
|
||||
nsObserverList *observerList = mObserverTopicTable.GetEntry(aTopic);
|
||||
if (observerList)
|
||||
observerList->NotifyObservers(aSubject, aTopic, someData);
|
||||
|
||||
#ifdef NOTIFY_GLOBAL_OBSERVERS
|
||||
EnumerateObservers("*", getter_AddRefs(globalObservers));
|
||||
#endif
|
||||
rv = EnumerateObservers(aTopic, getter_AddRefs(observers));
|
||||
#ifdef NOTIFY_GLOBAL_OBSERVERS
|
||||
/* If there are no global observers and we failed to get normal observers
|
||||
* then we return the error indicating failure to get normal observers.
|
||||
*/
|
||||
if (!globalObservers && NS_FAILED(rv))
|
||||
return rv;
|
||||
observerList = mObserverTopicTable.GetEntry("*");
|
||||
if (observerList)
|
||||
observerList->NotifyObservers(aSubject, aTopic, someData);
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
PRBool more = PR_FALSE;
|
||||
/* If observers is non null then null it out unless it really
|
||||
* has more elements (i.e. that call doesn't fail).
|
||||
*/
|
||||
if (observers && NS_FAILED(observers->HasMoreElements(&more)) || !more)
|
||||
{
|
||||
#ifdef NOTIFY_GLOBAL_OBSERVERS
|
||||
if (observers = globalObservers)
|
||||
globalObservers = nsnull;
|
||||
#else
|
||||
observers = nsnull;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
observers->GetNext(getter_AddRefs(observerRef));
|
||||
nsCOMPtr<nsIObserver> observer = do_QueryInterface(observerRef);
|
||||
if (observer)
|
||||
observer->Observe(aSubject, aTopic, someData);
|
||||
}
|
||||
} while (observers);
|
||||
return NS_OK;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
@ -39,37 +39,37 @@
|
|||
#define nsObserverService_h___
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsObserverList.h"
|
||||
#include "nsTHashtable.h"
|
||||
|
||||
#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1"
|
||||
#define NS_OBSERVERSERVICE_CLASSNAME "Observer Service"
|
||||
|
||||
class nsObserverList;
|
||||
class nsObjectHashtable;
|
||||
|
||||
// {D07F5195-E3D1-11d2-8ACD-00105A1B8860}
|
||||
#define NS_OBSERVERSERVICE_CID \
|
||||
{ 0xd07f5195, 0xe3d1, 0x11d2, { 0x8a, 0xcd, 0x0, 0x10, 0x5a, 0x1b, 0x88, 0x60 } }
|
||||
|
||||
class nsObserverService : public nsIObserverService {
|
||||
public:
|
||||
NS_DEFINE_STATIC_CID_ACCESSOR( NS_OBSERVERSERVICE_CID )
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_OBSERVERSERVICE_CID)
|
||||
|
||||
nsObserverService();
|
||||
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVERSERVICE
|
||||
|
||||
void Shutdown();
|
||||
|
||||
static NS_METHOD
|
||||
Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
|
||||
private:
|
||||
~nsObserverService(void);
|
||||
|
||||
nsObjectHashtable* mObserverTopicTable;
|
||||
|
||||
nsresult GetObserverList(const char* aTopic, nsObserverList** anObserverList);
|
||||
|
||||
|
||||
PRBool mShuttingDown;
|
||||
nsTHashtable<nsObserverList> mObserverTopicTable;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsObserverService, NS_OBSERVERSERVICE_CID)
|
||||
|
||||
#endif /* nsObserverService_h___ */
|
||||
|
|
|
@ -482,18 +482,22 @@ class nsTArray : public nsTArray_base {
|
|||
// and destroy" the first element that is equal to the given element.
|
||||
// @param item The item to search for.
|
||||
// @param comp The Comparator used to determine element equality.
|
||||
// @return PR_TRUE if the element was found
|
||||
template<class Item, class Comparator>
|
||||
void RemoveElement(const Item& item, const Comparator& comp) {
|
||||
PRBool RemoveElement(const Item& item, const Comparator& comp) {
|
||||
index_type i = IndexOf(item, 0, comp);
|
||||
if (i != NoIndex)
|
||||
RemoveElementAt(i);
|
||||
if (i == NoIndex)
|
||||
return PR_FALSE;
|
||||
|
||||
RemoveElementAt(i);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
// A variation on the RemoveElement method defined above that assumes
|
||||
// that 'operator==' is defined for elem_type.
|
||||
template<class Item>
|
||||
void RemoveElement(const Item& item) {
|
||||
RemoveElement(item, nsDefaultComparator<elem_type, Item>());
|
||||
PRBool RemoveElement(const Item& item) {
|
||||
return RemoveElement(item, nsDefaultComparator<elem_type, Item>());
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -41,8 +41,9 @@
|
|||
#include "nsIRDFContainerUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsObserverService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIWindowMediator.h"
|
||||
#include "nsXPCOMCID.h"
|
||||
|
||||
// just to do the reverse-lookup! sheesh.
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче