Bug 1425930: Handle Broadcast()->Notify() calling RemoveObserver() r=froyd

This commit is contained in:
Randell Jesup 2018-05-21 15:30:35 -04:00
parent 80358d8b5d
commit 27aae0dbeb

View File

@ -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