Skip to content

Commit 094c06b

Browse files
author
benjamin%smedbergs.us
committed
Bug 326491 - leaked observer service leaks things on shutdown - r=darin
1 parent c2e0194 commit 094c06b

File tree

9 files changed

+218
-241
lines changed

9 files changed

+218
-241
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
@@ -682,8 +682,9 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
682682
nsCOMPtr <nsIEventQueue> currentQ;
683683
NS_GetCurrentEventQ(getter_AddRefs(currentQ), eqs);
684684

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

688689
if (observerService)
689690
{
@@ -722,10 +723,13 @@ NS_ShutdownXPCOM(nsIServiceManager* servMgr)
722723

723724
// We save the "xpcom-shutdown-loaders" observers to notify after
724725
// the observerservice is gone.
725-
if (observerService)
726+
if (observerService) {
726727
observerService->
727728
EnumerateObservers(NS_XPCOM_SHUTDOWN_LOADERS_OBSERVER_ID,
728729
getter_AddRefs(moduleLoaders));
730+
731+
observerService->Shutdown();
732+
}
729733
}
730734

731735
// XPCOM is officially in shutdown mode NOW

xpcom/ds/nsObserverList.cpp

Lines changed: 56 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,91 @@ nsObserverList::AddObserver(nsIObserver* anObserver, PRBool ownsWeak)
9268
nsresult
9369
nsObserverList::RemoveObserver(nsIObserver* anObserver)
9470
{
95-
NS_ENSURE_ARG(anObserver);
71+
NS_ASSERTION(anObserver, "Null input");
9672

97-
nsAutoLock lock(mLock);
98-
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::FillObserverArray(nsCOMArray<nsIObserver> &aArray)
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+
aArray.SetCapacity(mObservers.Length());
101+
102+
for (PRInt32 i = mObservers.Length() - 1; i >= 0; --i) {
103+
if (mObservers[i].isWeakRef) {
104+
nsCOMPtr<nsIObserver> o(do_QueryReferent(mObservers[i].asWeak()));
105+
if (o) {
106+
aArray.AppendObject(o);
107+
}
108+
else {
109+
// the object has gone away, remove the weakref
110+
mObservers.RemoveElementAt(i);
111+
}
155112
}
156113
else {
157-
mObservers.AppendObject(aObservers[i]);
114+
aArray.AppendObject(mObservers[i].asObserver());
158115
}
159116
}
117+
}
118+
119+
void
120+
nsObserverList::NotifyObservers(nsISupports *aSubject,
121+
const char *aTopic,
122+
const PRUnichar *someData)
123+
{
124+
nsCOMArray<nsIObserver> observers;
125+
FillObserverArray(observers);
160126

161-
mIndex = mObservers.Count();
127+
for (PRInt32 i = 0; i < observers.Count(); ++i) {
128+
observers[i]->Observe(aSubject, aTopic, someData);
129+
}
162130
}
163131

164132
NS_IMPL_ISUPPORTS1(nsObserverEnumerator, nsISimpleEnumerator)
165133

134+
nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList)
135+
: mIndex(0)
136+
{
137+
aObserverList->FillObserverArray(mObservers);
138+
}
139+
166140
NS_IMETHODIMP
167141
nsObserverEnumerator::HasMoreElements(PRBool *aResult)
168142
{
169-
*aResult = (mIndex > 0);
143+
*aResult = (mIndex < mObservers.Count());
170144
return NS_OK;
171145
}
172146

173147
NS_IMETHODIMP
174148
nsObserverEnumerator::GetNext(nsISupports* *aResult)
175149
{
176-
if (!mIndex) {
150+
if (mIndex == mObservers.Count()) {
177151
NS_ERROR("Enumerating after HasMoreElements returned false.");
178152
return NS_ERROR_UNEXPECTED;
179153
}
180154

181-
--mIndex;
182155
NS_ADDREF(*aResult = mObservers[mIndex]);
156+
++mIndex;
183157
return NS_OK;
184158
}

xpcom/ds/nsObserverList.h

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,75 @@
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+
}
4670

47-
class nsObserverList
71+
PRBool operator==(nsISupports* b) const { return ref == b; }
72+
};
73+
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+
// Fill an array with the observers of this category.
91+
// The array is filled in last-added-first order.
92+
void FillObserverArray(nsCOMArray<nsIObserver> &aArray);
93+
94+
private:
95+
nsTArray<ObserverRef> mObservers;
6096
};
6197

98+
class nsObserverEnumerator : public nsISimpleEnumerator
99+
{
100+
public:
101+
NS_DECL_ISUPPORTS
102+
NS_DECL_NSISIMPLEENUMERATOR
103+
104+
nsObserverEnumerator(nsObserverList* aObserverList);
105+
106+
private:
107+
~nsObserverEnumerator() { }
108+
109+
PRInt32 mIndex; // Counts up from 0
110+
nsCOMArray<nsIObserver> mObservers;
111+
};
62112

63113
#endif /* nsObserverList_h___ */

0 commit comments

Comments
 (0)