blob: ca6d6af5e015e73f3493315a9a1eb212428197d0 (
plain) (
blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
commit dc0965023fb7
Author: Randell Jesup <rjesup@jesup.org>
Date: Mon May 21 15:30:35 2018 -0400
Bug 1425930 - Handle Broadcast()->Notify() calling RemoveObserver(). r=froydnj, a=abillings
--HG--
extra : source : a314710b0acd38afc7de74f0306f514b50d84463
---
xpcom/ds/Observer.h | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git xpcom/ds/Observer.h xpcom/ds/Observer.h
index 958e5e4a9694e..83d650a936ccc 100644
--- xpcom/ds/Observer.h
+++ xpcom/ds/Observer.h
@@ -57,7 +57,17 @@ public:
*/
bool RemoveObserver(Observer<T>* aObserver)
{
- return mObservers.RemoveElement(aObserver);
+ if (mObservers.RemoveElement(aObserver)) {
+ if (!mBroadcastCopy.IsEmpty()) {
+ // Annoyingly, someone could RemoveObserver() an item on the list
+ // while we're in a Broadcast()'s Notify() call.
+ auto i = mBroadcastCopy.IndexOf(aObserver);
+ MOZ_ASSERT(i != mBroadcastCopy.NoIndex);
+ mBroadcastCopy[i] = nullptr;
+ }
+ return true;
+ }
+ return false;
}
uint32_t Length()
@@ -65,17 +75,27 @@ public:
return mObservers.Length();
}
+ /**
+ * Call Notify() on each item in the list.
+ * Handles the case of Notify() calling RemoveObserver()
+ */
void Broadcast(const T& aParam)
{
- nsTArray<Observer<T>*> observersCopy(mObservers);
- uint32_t size = observersCopy.Length();
+ MOZ_ASSERT(mBroadcastCopy.IsEmpty());
+ mBroadcastCopy = mObservers;
+ uint32_t size = mBroadcastCopy.Length();
for (uint32_t i = 0; i < size; ++i) {
- observersCopy[i]->Notify(aParam);
+ // nulled if Removed during Broadcast
+ if (mBroadcastCopy[i]) {
+ mBroadcastCopy[i]->Notify(aParam);
+ }
}
+ mBroadcastCopy.Clear();
}
protected:
nsTArray<Observer<T>*> mObservers;
+ nsTArray<Observer<T>*> mBroadcastCopy;
};
} // namespace mozilla
|