1818
1919#include < list>
2020
21+ #include " app/memory/shared_ptr.h"
2122#include " app/src/log.h"
2223#include " app/src/mutex.h"
2324#include " app/src/semaphore.h"
@@ -32,7 +33,7 @@ namespace callback {
3233
3334class CallbackEntry ;
3435
35- class CallbackQueue : public std ::list<CallbackEntry* > {
36+ class CallbackQueue : public std ::list<SharedPtr< CallbackEntry> > {
3637 public:
3738 CallbackQueue () {}
3839 ~CallbackQueue () {}
@@ -51,7 +52,7 @@ class CallbackEntry {
5152 // callback_mutex_ is used to enforce a critical section for callback
5253 // execution and destruction.
5354 CallbackEntry (Callback* callback, Mutex* callback_mutex)
54- : callback_(callback), mutex_(callback_mutex) {}
55+ : callback_(callback), mutex_(callback_mutex), executing_( false ) {}
5556
5657 // Destroy the callback. This blocks if the callback is currently
5758 // executing.
@@ -61,35 +62,47 @@ class CallbackEntry {
6162 // Returns true if a callback was associated with this entry and was executed,
6263 // false otherwise.
6364 bool Execute () {
64- bool executed = false ;
65- MutexLock lock (*mutex_);
66- if (callback_) {
67- callback_->Run ();
68- // Note: The implementation of BlockingCallback below relies on the
69- // callback being disabled after being run. If that changes, please
70- // make sure to also update BlockingCallback.
71- DisableCallback ();
72- executed = true ;
65+ {
66+ MutexLock lock (*mutex_);
67+ if (!callback_) return false ;
68+ executing_ = true ;
7369 }
74- return executed;
70+
71+ callback_->Run ();
72+
73+ {
74+ MutexLock lock (*mutex_);
75+ executing_ = false ;
76+ }
77+
78+ // Note: The implementation of BlockingCallback below relies on the
79+ // callback being disabled after being run. If that changes, please
80+ // make sure to also update BlockingCallback.
81+ DisableCallback ();
82+
83+ return true ;
7584 }
7685
7786 // Remove the callback method from this entry.
7887 bool DisableCallback () {
79- MutexLock lock (*mutex_);
80- if (callback_) {
81- delete callback_;
88+ Callback* callback_to_delete = nullptr ;
89+ {
90+ MutexLock lock (*mutex_);
91+ if (executing_ || !callback_) return false ;
92+ callback_to_delete = callback_;
8293 callback_ = nullptr ;
83- return true ;
8494 }
85- return false ;
95+ delete callback_to_delete;
96+ return true ;
8697 }
8798
8899 private:
89100 // Callback to call from PollCallbacks().
90101 Callback* callback_;
91- // Mutex that is held when modifying callback_.
102+ // Mutex that is held when modifying callback_ and executing_ .
92103 Mutex* mutex_;
104+ // A flag set to true when callback_ is about to be called.
105+ bool executing_;
93106};
94107
95108// Dispatches a queue of callbacks.
@@ -106,18 +119,18 @@ class CallbackDispatcher {
106119 remaining_callbacks);
107120 }
108121 while (!queue_.empty ()) {
109- delete queue_.back ();
122+ queue_.back (). reset ();
110123 queue_.pop_back ();
111124 }
112125 }
113126
114127 // Add a callback to the dispatch queue returning a reference
115128 // to the entry which can be optionally be removed prior to dispatch.
116129 void * AddCallback (Callback* callback) {
117- CallbackEntry* entry = new CallbackEntry (callback, &execution_mutex_);
130+ auto entry = MakeShared< CallbackEntry> (callback, &execution_mutex_);
118131 MutexLock lock (*queue_.mutex ());
119132 queue_.push_back (entry);
120- return entry;
133+ return entry. get () ;
121134 }
122135
123136 // Remove the callback reference from the specified entry.
@@ -137,16 +150,19 @@ class CallbackDispatcher {
137150 int DispatchCallbacks () {
138151 int dispatched = 0 ;
139152 Mutex* queue_mutex = queue_.mutex ();
140- MutexLock lock (* queue_mutex);
153+ queue_mutex-> Acquire ( );
141154 while (!queue_.empty ()) {
142- CallbackEntry* callback_entry = queue_.front ();
155+ // Make a copy of the SharedPtr in case FlushCallbacks() is called
156+ // currently.
157+ SharedPtr<CallbackEntry> callback_entry = queue_.front ();
143158 queue_.pop_front ();
144159 queue_mutex->Release ();
145160 callback_entry->Execute ();
146161 dispatched++;
147162 queue_mutex->Acquire ();
148- delete callback_entry;
163+ callback_entry. reset () ;
149164 }
165+ queue_mutex->Release ();
150166 return dispatched;
151167 }
152168
@@ -155,7 +171,7 @@ class CallbackDispatcher {
155171 int flushed = 0 ;
156172 MutexLock lock (*queue_.mutex ());
157173 while (!queue_.empty ()) {
158- delete queue_.front ();
174+ queue_.front (). reset ();
159175 queue_.pop_front ();
160176 flushed++;
161177 }
@@ -299,7 +315,7 @@ void RemoveCallback(void* callback_reference) {
299315 // remove the CallbackEntry from the queue so we don't need an additional
300316 // Terminate() here to decrement the reference count that was added by
301317 // AddCallback().
302- static_cast <CallbackEntry*>(callback_reference) ->DisableCallback ();
318+ g_callback_dispatcher ->DisableCallback (callback_reference );
303319 Terminate (false );
304320 }
305321}
0 commit comments