Chromium Code Reviews| Index: third_party/WebKit/Source/platform/LifecycleNotifier.h |
| diff --git a/third_party/WebKit/Source/platform/LifecycleNotifier.h b/third_party/WebKit/Source/platform/LifecycleNotifier.h |
| index 27cbdc52b1a7c276c92614f318008bda2dd8de17..568d89160b83852ea802cc5bc556af3a86400bd5 100644 |
| --- a/third_party/WebKit/Source/platform/LifecycleNotifier.h |
| +++ b/third_party/WebKit/Source/platform/LifecycleNotifier.h |
| @@ -53,29 +53,64 @@ public: |
| visitor->trace(m_observers); |
| } |
| - bool isIteratingOverObservers() const { return m_iterating != IteratingNone; } |
| + bool isIteratingOverObservers() const { return m_iterationState != NotIterating; } |
| protected: |
| LifecycleNotifier() |
| - : m_iterating(IteratingNone) |
| + : m_iterationState(NotIterating) |
| { |
| } |
| - enum IterationType { |
| - IteratingNone, |
| - IteratingOverAll, |
| +#if DCHECK_IS_ON() |
| + T* context() { return static_cast<T*>(this); } |
| +#endif |
| + |
| + using ObserverSet = HeapHashSet<WeakMember<Observer>>; |
| + |
| + enum IterationState { |
| + AllowingNone = 0, |
| + AllowingAddition, |
| + AllowingRemoval, |
| + NotIterating = AllowingAddition | AllowingRemoval, |
| }; |
| - IterationType m_iterating; |
| + class IterationScope { |
| + STACK_ALLOCATED(); |
| + public: |
| + explicit IterationScope(LifecycleNotifier* notifier, IterationState allowable = AllowingNone) |
|
haraken
2016/06/27 01:06:34
Is the second parameter used somewhere?
sof
2016/06/27 05:14:14
Line 85
|
| + : m_notifier(notifier) |
| + { |
| + // Don't support nested iterations. |
| + RELEASE_ASSERT(m_notifier->m_iterationState == NotIterating); |
| + m_notifier->m_iterationState = allowable; |
| + |
| + // Swap out the notifier's weak collection to this stack allocated |
| + // object, ensuring that collection references are strongified across |
| + // conservative GCs. |
| + // |
| + // If not done, weak processing could mutate the underlying table |
| + // while it is being iterated over. |
| + m_observers.swap(m_notifier->m_observers); |
|
haraken
2016/06/27 01:06:34
I don't fully understand why we need to explicitly
sof
2016/06/27 05:14:14
I was thinking about that overnight, this being to
sof
2016/06/27 06:36:54
Now done.
|
| + } |
| + ~IterationScope() |
| + { |
| + m_notifier->m_iterationState = NotIterating; |
| + m_observers.swap(m_notifier->m_observers); |
| + } |
| + |
| + const typename LifecycleNotifier::ObserverSet& observers() const { return m_observers; } |
| + |
| + private: |
| + Member<LifecycleNotifier> m_notifier; |
| + typename LifecycleNotifier::ObserverSet m_observers; |
| + }; |
| -protected: |
| - using ObserverSet = HeapHashSet<WeakMember<Observer>>; |
| + friend class IterationScope; |
| + // Iteration state is recorded while iterating the observer set, |
| + // optionally barring add or remove mutations while it runs. |
| + IterationState m_iterationState; |
| ObserverSet m_observers; |
| - |
| -#if DCHECK_IS_ON() |
| - T* context() { return static_cast<T*>(this); } |
| -#endif |
| }; |
| template<typename T, typename Observer> |
| @@ -88,7 +123,8 @@ inline LifecycleNotifier<T, Observer>::~LifecycleNotifier() |
| template<typename T, typename Observer> |
| inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed() |
| { |
| - TemporaryChange<IterationType> scope(m_iterating, IteratingOverAll); |
| + // Observer unregistration is allowed, but effectively a no-op. |
| + TemporaryChange<IterationState> scope(m_iterationState, AllowingRemoval); |
| ObserverSet observers; |
| m_observers.swap(observers); |
| for (Observer* observer : observers) { |
| @@ -100,13 +136,14 @@ inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed() |
| template<typename T, typename Observer> |
| inline void LifecycleNotifier<T, Observer>::addObserver(Observer* observer) |
| { |
| - RELEASE_ASSERT(m_iterating != IteratingOverAll); |
| + RELEASE_ASSERT(m_iterationState & AllowingAddition); |
| m_observers.add(observer); |
| } |
| template<typename T, typename Observer> |
| inline void LifecycleNotifier<T, Observer>::removeObserver(Observer* observer) |
| { |
| + RELEASE_ASSERT(m_iterationState & AllowingRemoval); |
| m_observers.remove(observer); |
| } |