@@ -66,6 +66,24 @@ class ListenerSet{
6666
6767 mutable SpinLock m_lock;
6868
69+ // The data structure here is an intrusive map where the nodes form a
70+ // linked-list. The map provides a fast way to add/remove listeners while
71+ // the linked-list is the main method of iterating the listeners.
72+ //
73+ // Iterating listeners to fire callbacks is completely thread-safe as they
74+ // do not modify the structure of the container. OTOH, adding/removing does
75+ // modify the data structure.
76+ //
77+ // "m_lock" protects the structure of container. You cannot change the
78+ // map or the linked list without holding this lock. When iterating the
79+ // nodes to fire callbacks, you must hold this lock when moving from one
80+ // node to the next to prevent the points from changing from under you.
81+ //
82+ // To prevent a listener from being removed while its callback is running,
83+ // there is a lock on each node. The contract for removing is a listener is
84+ // that when "remove_listener()" returns, this class holds no more
85+ // references to it and thus is the listener is safe to destroy.
86+ //
6987 struct Node {
7088 SpinLock lock;
7189 ListenerType& listener;
@@ -112,7 +130,7 @@ void ListenerSet<ListenerType>::add(ListenerType& listener){
112130 std::piecewise_construct,
113131 std::forward_as_tuple (&listener),
114132 std::forward_as_tuple (*this , listener)
115- );
133+ );
116134 if (!ret.second ){
117135 return ;
118136 }
@@ -132,6 +150,9 @@ void ListenerSet<ListenerType>::remove(ListenerType& listener) noexcept{
132150#ifdef PA_DEBUG_ListenerSet
133151 auto scope = m_sanitizer.check_scope ();
134152#endif
153+
154+ bool printed = false ;
155+
135156 while (true ){
136157 WriteSpinLock lg (m_lock);
137158 auto iter = m_listeners.find (&listener);
@@ -146,9 +167,12 @@ void ListenerSet<ListenerType>::remove(ListenerType& listener) noexcept{
146167#endif
147168
148169 if (!node.lock .try_acquire_write ()){
149- try {
150- std::cout << " ListenerSet::remove(): Retry inner." << std::endl;
151- }catch (...){}
170+ if (!printed){
171+ try {
172+ std::cout << " ListenerSet::remove(): Retry inner." << std::endl;
173+ }catch (...){}
174+ printed = true ;
175+ }
152176 continue ;
153177 }
154178
0 commit comments