Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: third_party/WebKit/Source/platform/LifecycleNotifier.h

Issue 2094143002: Avoid snapshotting ContextLifecycleObservers when iterating. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: msvc compile fix.. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/page/PageLifecycleNotifier.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2013 Google Inc. All Rights Reserved. 3 * Copyright (C) 2013 Google Inc. All Rights Reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
46 // 46 //
47 // When contextDestroyed() is called, the observer's lifecycleContext() 47 // When contextDestroyed() is called, the observer's lifecycleContext()
48 // is still valid and safe to use during the notification. 48 // is still valid and safe to use during the notification.
49 virtual void notifyContextDestroyed(); 49 virtual void notifyContextDestroyed();
50 50
51 DEFINE_INLINE_VIRTUAL_TRACE() 51 DEFINE_INLINE_VIRTUAL_TRACE()
52 { 52 {
53 visitor->trace(m_observers); 53 visitor->trace(m_observers);
54 } 54 }
55 55
56 bool isIteratingOverObservers() const { return m_iterating != IteratingNone; } 56 bool isIteratingOverObservers() const { return m_iterationState != NotIterat ing; }
57 57
58 protected: 58 protected:
59 LifecycleNotifier() 59 LifecycleNotifier()
60 : m_iterating(IteratingNone) 60 : m_iterationState(NotIterating)
61 { 61 {
62 } 62 }
63 63
64 enum IterationType {
65 IteratingNone,
66 IteratingOverAll,
67 };
68
69 IterationType m_iterating;
70
71 protected:
72 using ObserverSet = HeapHashSet<WeakMember<Observer>>;
73
74 ObserverSet m_observers;
75
76 #if DCHECK_IS_ON() 64 #if DCHECK_IS_ON()
77 T* context() { return static_cast<T*>(this); } 65 T* context() { return static_cast<T*>(this); }
78 #endif 66 #endif
67
68 using ObserverSet = HeapHashSet<WeakMember<Observer>>;
69
70 enum IterationState {
71 AllowingNone = 0,
72 AllowingAddition,
73 AllowingRemoval,
74 NotIterating = AllowingAddition | AllowingRemoval,
75 };
76
77 class IterationScope {
78 STACK_ALLOCATED();
79 public:
80 explicit IterationScope(LifecycleNotifier* notifier, IterationState allo wable = AllowingNone)
haraken 2016/06/27 01:06:34 Is the second parameter used somewhere?
sof 2016/06/27 05:14:14 Line 85
81 : m_notifier(notifier)
82 {
83 // Don't support nested iterations.
84 RELEASE_ASSERT(m_notifier->m_iterationState == NotIterating);
85 m_notifier->m_iterationState = allowable;
86
87 // Swap out the notifier's weak collection to this stack allocated
88 // object, ensuring that collection references are strongified acros s
89 // conservative GCs.
90 //
91 // If not done, weak processing could mutate the underlying table
92 // while it is being iterated over.
93 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.
94 }
95 ~IterationScope()
96 {
97 m_notifier->m_iterationState = NotIterating;
98 m_observers.swap(m_notifier->m_observers);
99 }
100
101 const typename LifecycleNotifier::ObserverSet& observers() const { retur n m_observers; }
102
103 private:
104 Member<LifecycleNotifier> m_notifier;
105 typename LifecycleNotifier::ObserverSet m_observers;
106 };
107
108 friend class IterationScope;
109
110 // Iteration state is recorded while iterating the observer set,
111 // optionally barring add or remove mutations while it runs.
112 IterationState m_iterationState;
113 ObserverSet m_observers;
79 }; 114 };
80 115
81 template<typename T, typename Observer> 116 template<typename T, typename Observer>
82 inline LifecycleNotifier<T, Observer>::~LifecycleNotifier() 117 inline LifecycleNotifier<T, Observer>::~LifecycleNotifier()
83 { 118 {
84 // FIXME: Enable the following ASSERT. Also see a FIXME in Document::detach( ). 119 // FIXME: Enable the following ASSERT. Also see a FIXME in Document::detach( ).
85 // ASSERT(!m_observers.size()); 120 // ASSERT(!m_observers.size());
86 } 121 }
87 122
88 template<typename T, typename Observer> 123 template<typename T, typename Observer>
89 inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed() 124 inline void LifecycleNotifier<T, Observer>::notifyContextDestroyed()
90 { 125 {
91 TemporaryChange<IterationType> scope(m_iterating, IteratingOverAll); 126 // Observer unregistration is allowed, but effectively a no-op.
127 TemporaryChange<IterationState> scope(m_iterationState, AllowingRemoval);
92 ObserverSet observers; 128 ObserverSet observers;
93 m_observers.swap(observers); 129 m_observers.swap(observers);
94 for (Observer* observer : observers) { 130 for (Observer* observer : observers) {
95 ASSERT(observer->lifecycleContext() == context()); 131 ASSERT(observer->lifecycleContext() == context());
96 observer->contextDestroyed(); 132 observer->contextDestroyed();
97 } 133 }
98 } 134 }
99 135
100 template<typename T, typename Observer> 136 template<typename T, typename Observer>
101 inline void LifecycleNotifier<T, Observer>::addObserver(Observer* observer) 137 inline void LifecycleNotifier<T, Observer>::addObserver(Observer* observer)
102 { 138 {
103 RELEASE_ASSERT(m_iterating != IteratingOverAll); 139 RELEASE_ASSERT(m_iterationState & AllowingAddition);
104 m_observers.add(observer); 140 m_observers.add(observer);
105 } 141 }
106 142
107 template<typename T, typename Observer> 143 template<typename T, typename Observer>
108 inline void LifecycleNotifier<T, Observer>::removeObserver(Observer* observer) 144 inline void LifecycleNotifier<T, Observer>::removeObserver(Observer* observer)
109 { 145 {
146 RELEASE_ASSERT(m_iterationState & AllowingRemoval);
110 m_observers.remove(observer); 147 m_observers.remove(observer);
111 } 148 }
112 149
113 } // namespace blink 150 } // namespace blink
114 151
115 #endif // LifecycleNotifier_h 152 #endif // LifecycleNotifier_h
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/page/PageLifecycleNotifier.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698