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

--HG--
extra : rebase_source : 87dc3560125bbb6c77215777753c9fbc2a34e7f6
This commit is contained in:
Randell Jesup 2018-05-18 11:15:30 -04:00
Родитель 53c7c73179
Коммит ceedbeadd3
1 изменённых файлов: 22 добавлений и 4 удалений

Просмотреть файл

@ -57,7 +57,15 @@ public:
*/ */
bool RemoveObserver(Observer<T>* aObserver) bool RemoveObserver(Observer<T>* aObserver)
{ {
return mObservers.RemoveElement(aObserver); if (mObservers.RemoveElement(aObserver)) {
// 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 != NoIndex);
mBroadcastCopy[i] = nullptr;
return true;
}
return false;
} }
uint32_t Length() uint32_t Length()
@ -65,17 +73,27 @@ public:
return mObservers.Length(); return mObservers.Length();
} }
/**
* Call Notify() on each item in the list.
* Handles the case of Notify() calling RemoveObserver()
*/
void Broadcast(const T& aParam) void Broadcast(const T& aParam)
{ {
nsTArray<Observer<T>*> observersCopy(mObservers); MOZ_ASSERT(mBroadcastCopy.Empty());
uint32_t size = observersCopy.Length(); mBroadcastCopy = mObservers;
uint32_t size = mBroadcastCopy.Length();
for (uint32_t i = 0; i < size; ++i) { 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: protected:
nsTArray<Observer<T>*> mObservers; nsTArray<Observer<T>*> mObservers;
nsTArray<Observer<T>*> mBroadcastCopy;
}; };
} // namespace mozilla } // namespace mozilla