Skip to content

Commit ac2cdad

Browse files
author
benjamin%smedbergs.us
committed
Bug 326491 - cleanup observers on shutdown even if the observer service is leaked, r=darin
1 parent d31df1a commit ac2cdad

File tree

10 files changed

+248
-242
lines changed

10 files changed

+248
-242
lines changed

docshell/base/nsDocShell.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@
9393
#include "nsIPrefBranch.h"
9494
#include "nsIPrefBranch2.h"
9595
#include "nsIWritablePropertyBag2.h"
96-
#include "nsObserverService.h"
9796

9897
// we want to explore making the document own the load group
9998
// so we can associate the document URI with the load group.

xpcom/build/nsXPCOMCID.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@
8484
*/
8585
#define NS_ARRAY_CONTRACTID "@mozilla.org/array;1"
8686

87+
/**
88+
* Observer Service ContractID
89+
* The observer service implements the global nsIObserverService object.
90+
* It should be used from the main thread only.
91+
*/
92+
#define NS_OBSERVERSERVICE_CONTRACTID "@mozilla.org/observer-service;1"
93+
8794
/**
8895
* The following are the CIDs and Contract IDs of the nsISupports wrappers for
8996
* primative types.

xpcom/build/nsXPComInit.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,9 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
681681
nsCOMPtr <nsIEventQueue> currentQ;
682682
NS_GetCurrentEventQ(getter_AddRefs(currentQ), eqs);
683683

684-
nsCOMPtr<nsIObserverService> observerService =
685-
do_GetService("@mozilla.org/observer-service;1");
684+
nsRefPtr<nsObserverService> observerService;
685+
CallGetService("@mozilla.org/observer-service;1",
686+
(nsObserverService**) getter_AddRefs(observerService));
686687

687688
if (observerService)
688689
{
@@ -721,10 +722,13 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
721722

722723
// We save the "xpcom-shutdown-loaders" observers to notify after
723724
// the observerservice is gone.
724-
if (observerService)
725+
if (observerService) {
725726
observerService->
726727
EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID,
727728
getter_AddRefs(moduleLoaders));
729+
730+
observerService->Shutdown();
731+
}
728732
}
729733

730734
// XPCOM is officially in shutdown mode NOW

xpcom/ds/Makefile.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ EXPORTS = \
9999
nsIByteBuffer.h \
100100
nsIUnicharBuffer.h \
101101
nsInt64.h \
102-
nsObserverService.h \
103102
nsRecyclingAllocator.h \
104103
nsStaticNameTable.h \
105104
nsStaticAtom.h \

xpcom/ds/nsObserverList.cpp

Lines changed: 73 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -37,53 +37,29 @@
3737

3838
#include "nsObserverList.h"
3939

40-
#include "pratom.h"
41-
#include "nsAutoLock.h"
4240
#include "nsAutoPtr.h"
43-
#include "nsCOMPtr.h"
44-
#include "nsIObserver.h"
41+
#include "nsCOMArray.h"
4542
#include "nsISimpleEnumerator.h"
46-
#include "nsIWeakReference.h"
47-
48-
nsObserverList::nsObserverList(nsresult &rv)
49-
{
50-
MOZ_COUNT_CTOR(nsObserverList);
51-
mLock = PR_NewLock();
52-
if (!mLock)
53-
rv = NS_ERROR_OUT_OF_MEMORY;
54-
}
55-
56-
nsObserverList::~nsObserverList(void)
57-
{
58-
MOZ_COUNT_DTOR(nsObserverList);
59-
if (mLock)
60-
PR_DestroyLock(mLock);
61-
}
6243

6344
nsresult
6445
nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
6546
{
66-
NS_ENSURE_ARG(anObserver);
67-
68-
nsAutoLock lock(mLock);
69-
70-
nsCOMPtr<nsISupports> observerRef;
71-
if (ownsWeak) {
72-
nsCOMPtr<nsISupportsWeakReference>
73-
weakRefFactory(do_QueryInterface(anObserver));
74-
NS_ASSERTION(weakRefFactory,
75-
"Doesn't implement nsISupportsWeakReference");
76-
if (weakRefFactory)
77-
weakRefFactory->
78-
GetWeakReference((nsIWeakReference**)(nsISupports**)
79-
getter_AddRefs(observerRef));
80-
} else {
81-
observerRef = anObserver;
47+
NS_ASSERTION(anObserver, "Null input");
48+
49+
if (!ownsWeak) {
50+
ObserverRef* o = mObservers.AppendElement(anObserver);
51+
if (!o)
52+
return NS_ERROR_OUT_OF_MEMORY;
53+
54+
return NS_OK;
8255
}
83-
if (!observerRef)
84-
return NS_ERROR_FAILURE;
56+
57+
nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(anObserver);
58+
if (!weak)
59+
return NS_NOINTERFACE;
8560

86-
if (!mObservers.AppendObject(observerRef))
61+
ObserverRef *o = mObservers.AppendElement(weak);
62+
if (!o)
8763
return NS_ERROR_OUT_OF_MEMORY;
8864

8965
return NS_OK;
@@ -92,93 +68,108 @@ nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
9268
nsresult
9369
nsObserverList::RemoveObserver(nsIObserver* anObserver)
9470
{
95-
NS_ENSURE_ARG(anObserver);
96-
97-
nsAutoLock lock(mLock);
71+
NS_ASSERTION(anObserver, "Null input");
9872

99-
if (mObservers.RemoveObject(anObserver))
73+
if (mObservers.RemoveElement(NS_STATIC_CAST(nsISupports*, anObserver)))
10074
return NS_OK;
10175

102-
nsCOMPtr<nsISupportsWeakReference>
103-
weakRefFactory(do_QueryInterface(anObserver));
104-
if (!weakRefFactory)
105-
return NS_ERROR_FAILURE;
106-
107-
nsCOMPtr<nsIWeakReference> observerRef;
108-
weakRefFactory->GetWeakReference(getter_AddRefs(observerRef));
109-
76+
nsCOMPtr<nsIWeakReference> observerRef = do_GetWeakReference(anObserver);
11077
if (!observerRef)
11178
return NS_ERROR_FAILURE;
11279

113-
if (!mObservers.RemoveObject(observerRef))
80+
if (!mObservers.RemoveElement(observerRef))
11481
return NS_ERROR_FAILURE;
11582

11683
return NS_OK;
11784
}
11885

119-
class nsObserverEnumerator : public nsISimpleEnumerator
120-
{
121-
public:
122-
NS_DECL_ISUPPORTS
123-
NS_DECL_NSISIMPLEENUMERATOR
124-
125-
nsObserverEnumerator(nsCOMArray<nsISupports> &aObservers);
126-
127-
private:
128-
~nsObserverEnumerator() { }
129-
130-
PRUint32 mIndex; // Counts down, ends at 0
131-
nsCOMArray<nsISupports> mObservers;
132-
};
133-
13486
nsresult
13587
nsObserverList::GetObserverList(nsISimpleEnumerator** anEnumerator)
13688
{
137-
nsAutoLock lock(mLock);
138-
139-
nsRefPtr<nsObserverEnumerator> e(new nsObserverEnumerator(mObservers));
89+
nsRefPtr<nsObserverEnumerator> e(new nsObserverEnumerator(this));
14090
if (!e)
14191
return NS_ERROR_OUT_OF_MEMORY;
14292

14393
NS_ADDREF(*anEnumerator = e);
14494
return NS_OK;
14595
}
14696

147-
nsObserverEnumerator::nsObserverEnumerator(nsCOMArray<nsISupports> &aObservers)
97+
void
98+
nsObserverList::EnumerateObservers(EnumObserversFunc aFunc, void *aClosure)
14899
{
149-
for (PRInt32 i = 0; i < aObservers.Count(); ++i) {
150-
nsCOMPtr<nsIWeakReference> weak(do_QueryInterface(aObservers[i]));
151-
if (weak) {
152-
nsCOMPtr<nsISupports> strong(do_QueryReferent(weak));
153-
if (strong)
154-
mObservers.AppendObject(strong);
100+
for (PRInt32 i = mObservers.Length() - 1; i >= 0; --i) {
101+
if (mObservers[i].isWeakRef) {
102+
nsCOMPtr<nsIObserver> o(do_QueryReferent(mObservers[i].asWeak()));
103+
if (o) {
104+
aFunc(o, aClosure);
105+
}
106+
else {
107+
// the object has gone away, remove the weakref
108+
mObservers.RemoveElementAt(i);
109+
}
155110
}
156111
else {
157-
mObservers.AppendObject(aObservers[i]);
112+
aFunc(mObservers[i].asObserver(), aClosure);
158113
}
159114
}
115+
}
116+
117+
struct NotifyData
118+
{
119+
nsISupports* aSubject;
120+
const char *aTopic;
121+
const PRUnichar *someData;
122+
};
123+
124+
void
125+
nsObserverList::NotifyObservers(nsISupports *aSubject,
126+
const char *aTopic,
127+
const PRUnichar *someData)
128+
{
129+
NotifyData nd = { aSubject, aTopic, someData };
130+
EnumerateObservers(Notify, &nd);
131+
}
160132

161-
mIndex = mObservers.Count();
133+
void
134+
nsObserverList::Notify(nsIObserver* aObserver, void *aClosure)
135+
{
136+
NotifyData *nd = NS_REINTERPRET_CAST(NotifyData*, aClosure);
137+
aObserver->Observe(nd->aSubject, nd->aTopic, nd->someData);
162138
}
163139

164140
NS_IMPL_ISUPPORTS1(nsObserverEnumerator, nsISimpleEnumerator)
165141

142+
void
143+
nsObserverEnumerator::Fill(nsIObserver* aObserver, void *aClosure)
144+
{
145+
nsObserverEnumerator* e =
146+
NS_REINTERPRET_CAST(nsObserverEnumerator*, aClosure);
147+
e->mObservers.AppendObject(aObserver);
148+
}
149+
150+
nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList)
151+
: mIndex(0)
152+
{
153+
mObservers.SetCapacity(aObserverList->mObservers.Length());
154+
aObserverList->EnumerateObservers(Fill, this);
155+
}
156+
166157
NS_IMETHODIMP
167158
nsObserverEnumerator::HasMoreElements(PRBool *aResult)
168159
{
169-
*aResult = (mIndex > 0);
160+
*aResult = (mIndex < mObservers.Count());
170161
return NS_OK;
171162
}
172163

173164
NS_IMETHODIMP
174165
nsObserverEnumerator::GetNext(nsISupports* *aResult)
175166
{
176-
if (!mIndex) {
167+
if (mIndex == mObservers.Count()) {
177168
NS_ERROR("Enumerating after HasMoreElements returned false.");
178169
return NS_ERROR_UNEXPECTED;
179170
}
180171

181-
--mIndex;
182172
NS_ADDREF(*aResult = mObservers[mIndex]);
173+
++mIndex;
183174
return NS_OK;
184175
}

xpcom/ds/nsObserverList.h

Lines changed: 72 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,88 @@
3939
#define nsObserverList_h___
4040

4141
#include "nsISupports.h"
42+
#include "nsTArray.h"
43+
#include "nsCOMPtr.h"
4244
#include "nsCOMArray.h"
45+
#include "nsIObserver.h"
46+
#include "nsIWeakReference.h"
47+
#include "nsHashKeys.h"
48+
#include "nsISimpleEnumerator.h"
4349

44-
class nsISimpleEnumerator;
45-
class nsIObserver;
50+
struct ObserverRef
51+
{
52+
ObserverRef(const ObserverRef& o) :
53+
isWeakRef(o.isWeakRef), ref(o.ref) { }
54+
55+
ObserverRef(nsIObserver* aObserver) : isWeakRef(PR_FALSE), ref(aObserver) { }
56+
ObserverRef(nsIWeakReference* aWeak) : isWeakRef(PR_TRUE), ref(aWeak) { }
57+
58+
PRBool isWeakRef;
59+
nsCOMPtr<nsISupports> ref;
60+
61+
nsIObserver* asObserver() {
62+
NS_ASSERTION(!isWeakRef, "Isn't a strong ref.");
63+
return NS_STATIC_CAST(nsIObserver*, (nsISupports*) ref);
64+
}
65+
66+
nsIWeakReference* asWeak() {
67+
NS_ASSERTION(isWeakRef, "Isn't a weak ref.");
68+
return NS_STATIC_CAST(nsIWeakReference*, (nsISupports*) ref);
69+
}
70+
71+
PRBool operator==(nsISupports* b) const { return ref == b; }
72+
};
4673

47-
class nsObserverList
74+
class nsObserverList : public nsCharPtrHashKey
4875
{
4976
public:
50-
nsObserverList(nsresult &rv);
51-
~nsObserverList();
77+
nsObserverList(const char *key) : nsCharPtrHashKey(key)
78+
{ MOZ_COUNT_CTOR(nsObserverList); }
79+
80+
~nsObserverList() { MOZ_COUNT_DTOR(nsObserverList); }
5281

5382
nsresult AddObserver(nsIObserver* anObserver, PRBool ownsWeak);
5483
nsresult RemoveObserver(nsIObserver* anObserver);
84+
85+
void NotifyObservers(nsISupports *aSubject,
86+
const char *aTopic,
87+
const PRUnichar *someData);
5588
nsresult GetObserverList(nsISimpleEnumerator** anEnumerator);
56-
57-
protected:
58-
PRLock* mLock;
59-
nsCOMArray<nsISupports> mObservers;
89+
90+
private:
91+
friend class nsObserverEnumerator;
92+
93+
typedef void (*EnumObserversFunc)(nsIObserver* aObserver, void *aClosure);
94+
95+
// EnumerateObservers passes all the registered observers to aFunc
96+
// in LIFO order. If there are any stale weak references they are
97+
// removed during enumeration. aFunc must not modify the observerlist
98+
// during enumeration.
99+
void EnumerateObservers(EnumObserversFunc aFunc, void *aClosure);
100+
101+
// Static helper function for NotifyObservers
102+
static void Notify(nsIObserver* aObserver, void *aClosure);
103+
104+
nsTArray<ObserverRef> mObservers;
105+
60106
};
61107

108+
class nsObserverEnumerator : public nsISimpleEnumerator
109+
{
110+
public:
111+
NS_DECL_ISUPPORTS
112+
NS_DECL_NSISIMPLEENUMERATOR
113+
114+
nsObserverEnumerator(nsObserverList* aObserverList);
115+
116+
private:
117+
~nsObserverEnumerator() { }
118+
119+
// Static helper function for the constructor
120+
static void Fill(nsIObserver* aObserver, void *aClosure);
121+
122+
PRInt32 mIndex; // Counts up from 0
123+
nsCOMArray<nsIObserver> mObservers;
124+
};
62125

63126
#endif /* nsObserverList_h___ */

0 commit comments

Comments
 (0)