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

Side by Side Diff: webrtc/rtc_base/asyncinvoker.h

Issue 2885143005: Fixing race between ~AsyncInvoker and ~AsyncClosure, using ref-counting. (Closed)
Patch Set: Add another TODO. Created 3 years, 4 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 | « no previous file | webrtc/rtc_base/asyncinvoker.cc » ('j') | 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 2014 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source 5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #ifndef WEBRTC_RTC_BASE_ASYNCINVOKER_H_ 11 #ifndef WEBRTC_RTC_BASE_ASYNCINVOKER_H_
12 #define WEBRTC_RTC_BASE_ASYNCINVOKER_H_ 12 #define WEBRTC_RTC_BASE_ASYNCINVOKER_H_
13 13
14 #include <atomic>
14 #include <memory> 15 #include <memory>
15 #include <utility> 16 #include <utility>
16 17
17 #include "webrtc/rtc_base/asyncinvoker-inl.h" 18 #include "webrtc/rtc_base/asyncinvoker-inl.h"
18 #include "webrtc/rtc_base/bind.h" 19 #include "webrtc/rtc_base/bind.h"
19 #include "webrtc/rtc_base/constructormagic.h" 20 #include "webrtc/rtc_base/constructormagic.h"
20 #include "webrtc/rtc_base/event.h" 21 #include "webrtc/rtc_base/event.h"
22 #include "webrtc/rtc_base/refcountedobject.h"
23 #include "webrtc/rtc_base/scoped_ref_ptr.h"
21 #include "webrtc/rtc_base/sigslot.h" 24 #include "webrtc/rtc_base/sigslot.h"
22 #include "webrtc/rtc_base/thread.h" 25 #include "webrtc/rtc_base/thread.h"
23 26
24 namespace rtc { 27 namespace rtc {
25 28
26 // Invokes function objects (aka functors) asynchronously on a Thread, and 29 // Invokes function objects (aka functors) asynchronously on a Thread, and
27 // owns the lifetime of calls (ie, when this object is destroyed, calls in 30 // owns the lifetime of calls (ie, when this object is destroyed, calls in
28 // flight are cancelled). AsyncInvoker can optionally execute a user-specified 31 // flight are cancelled). AsyncInvoker can optionally execute a user-specified
29 // function when the asynchronous call is complete, or operates in 32 // function when the asynchronous call is complete, or operates in
30 // fire-and-forget mode otherwise. 33 // fire-and-forget mode otherwise.
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
63 // return x * x; 66 // return x * x;
64 // } 67 // }
65 // void AnotherAsyncTask() { 68 // void AnotherAsyncTask() {
66 // // Some other long running process... 69 // // Some other long running process...
67 // } 70 // }
68 // void OnTaskComplete(int result) { result_ = result; } 71 // void OnTaskComplete(int result) { result_ = result; }
69 // 72 //
70 // AsyncInvoker invoker_; 73 // AsyncInvoker invoker_;
71 // int result_; 74 // int result_;
72 // }; 75 // };
76 //
77 // More details about threading:
78 // - It's safe to construct/destruct AsyncInvoker on different threads.
79 // - It's safe to call AsyncInvoke from different threads.
80 // - It's safe to call AsyncInvoke recursively from *within* a functor that's
81 // being AsyncInvoked.
82 // - However, it's *not* safe to call AsyncInvoke from *outside* a functor
83 // that's being AsyncInvoked while the AsyncInvoker is being destroyed on
84 // another thread. This is just inherently unsafe and there's no way to
85 // prevent that. So, the user of this class should ensure that the start of
86 // each "chain" of invocations is synchronized somehow with the AsyncInvoker's
87 // destruction. This can be done by starting each chain of invocations on the
88 // same thread on which it will be destroyed, or by using some other
89 // synchronization method.
73 class AsyncInvoker : public MessageHandler { 90 class AsyncInvoker : public MessageHandler {
74 public: 91 public:
75 AsyncInvoker(); 92 AsyncInvoker();
76 ~AsyncInvoker() override; 93 ~AsyncInvoker() override;
77 94
78 // Call |functor| asynchronously on |thread|, with no callback upon 95 // Call |functor| asynchronously on |thread|, with no callback upon
79 // completion. Returns immediately. 96 // completion. Returns immediately.
80 template <class ReturnT, class FunctorT> 97 template <class ReturnT, class FunctorT>
81 void AsyncInvoke(const Location& posted_from, 98 void AsyncInvoke(const Location& posted_from,
82 Thread* thread, 99 Thread* thread,
(...skipping 28 matching lines...) Expand all
111 void OnMessage(Message* msg) override; 128 void OnMessage(Message* msg) override;
112 void DoInvoke(const Location& posted_from, 129 void DoInvoke(const Location& posted_from,
113 Thread* thread, 130 Thread* thread,
114 std::unique_ptr<AsyncClosure> closure, 131 std::unique_ptr<AsyncClosure> closure,
115 uint32_t id); 132 uint32_t id);
116 void DoInvokeDelayed(const Location& posted_from, 133 void DoInvokeDelayed(const Location& posted_from,
117 Thread* thread, 134 Thread* thread,
118 std::unique_ptr<AsyncClosure> closure, 135 std::unique_ptr<AsyncClosure> closure,
119 uint32_t delay_ms, 136 uint32_t delay_ms,
120 uint32_t id); 137 uint32_t id);
121 volatile int pending_invocations_ = 0; 138
122 Event invocation_complete_; 139 // Used to keep track of how many invocations (AsyncClosures) are still
123 bool destroying_ = false; 140 // alive, so that the destructor can wait for them to finish, as described in
141 // the class documentation.
142 //
143 // TODO(deadbeef): Using a raw std::atomic like this is prone to error and
144 // difficult to maintain. We should try to wrap this functionality in a
145 // separate class to reduce the chance of errors being introduced in the
146 // future.
147 std::atomic<int> pending_invocations_;
148
149 // Reference counted so that if the AsyncInvoker destructor finishes before
150 // an AsyncClosure's destructor that's about to call
151 // "invocation_complete_->Set()", it's not dereferenced after being
152 // destroyed.
153 scoped_refptr<RefCountedObject<Event>> invocation_complete_;
154
155 // This flag is used to ensure that if an application AsyncInvokes tasks that
156 // recursively AsyncInvoke other tasks ad infinitum, the cycle eventually
157 // terminates.
158 std::atomic<bool> destroying_;
159
124 friend class AsyncClosure; 160 friend class AsyncClosure;
125 161
126 RTC_DISALLOW_COPY_AND_ASSIGN(AsyncInvoker); 162 RTC_DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
127 }; 163 };
128 164
129 // Similar to AsyncInvoker, but guards against the Thread being destroyed while 165 // Similar to AsyncInvoker, but guards against the Thread being destroyed while
130 // there are outstanding dangling pointers to it. It will connect to the current 166 // there are outstanding dangling pointers to it. It will connect to the current
131 // thread in the constructor, and will get notified when that thread is 167 // thread in the constructor, and will get notified when that thread is
132 // destroyed. After GuardedAsyncInvoker is constructed, it can be used from 168 // destroyed. After GuardedAsyncInvoker is constructed, it can be used from
133 // other threads to post functors to the thread it was constructed on. If that 169 // other threads to post functors to the thread it was constructed on. If that
134 // thread dies, any further calls to AsyncInvoke() will be safely ignored. 170 // thread dies, any further calls to AsyncInvoke() will be safely ignored.
135 class GuardedAsyncInvoker : public sigslot::has_slots<> { 171 class GuardedAsyncInvoker : public sigslot::has_slots<> {
136 public: 172 public:
137 GuardedAsyncInvoker(); 173 GuardedAsyncInvoker();
138 ~GuardedAsyncInvoker() override; 174 ~GuardedAsyncInvoker() override;
139 175
140 // Synchronously execute all outstanding calls we own, and wait for calls to 176 // Synchronously execute all outstanding calls we own, and wait for calls to
141 // complete before returning. Optionally filter by message id. The destructor 177 // complete before returning. Optionally filter by message id. The destructor
142 // will not wait for outstanding calls, so if that behavior is desired, call 178 // will not wait for outstanding calls, so if that behavior is desired, call
143 // Flush() first. Returns false if the thread has died. 179 // Flush() first. Returns false if the thread has died.
144 bool Flush(uint32_t id = MQID_ANY); 180 bool Flush(uint32_t id = MQID_ANY);
145 181
146 // Call |functor| asynchronously with no callback upon completion. Returns 182 // Call |functor| asynchronously with no callback upon completion. Returns
147 // immediately. Returns false if the thread has died. 183 // immediately. Returns false if the thread has died.
148 template <class ReturnT, class FunctorT> 184 template <class ReturnT, class FunctorT>
149 bool AsyncInvoke(const Location& posted_from, 185 bool AsyncInvoke(const Location& posted_from,
150 const FunctorT& functor, 186 const FunctorT& functor,
151 uint32_t id = 0) { 187 uint32_t id = 0) {
152 rtc::CritScope cs(&crit_); 188 CritScope cs(&crit_);
153 if (thread_ == nullptr) 189 if (thread_ == nullptr)
154 return false; 190 return false;
155 invoker_.AsyncInvoke<ReturnT, FunctorT>(posted_from, thread_, functor, id); 191 invoker_.AsyncInvoke<ReturnT, FunctorT>(posted_from, thread_, functor, id);
156 return true; 192 return true;
157 } 193 }
158 194
159 // Call |functor| asynchronously with |delay_ms|, with no callback upon 195 // Call |functor| asynchronously with |delay_ms|, with no callback upon
160 // completion. Returns immediately. Returns false if the thread has died. 196 // completion. Returns immediately. Returns false if the thread has died.
161 template <class ReturnT, class FunctorT> 197 template <class ReturnT, class FunctorT>
162 bool AsyncInvokeDelayed(const Location& posted_from, 198 bool AsyncInvokeDelayed(const Location& posted_from,
163 const FunctorT& functor, 199 const FunctorT& functor,
164 uint32_t delay_ms, 200 uint32_t delay_ms,
165 uint32_t id = 0) { 201 uint32_t id = 0) {
166 rtc::CritScope cs(&crit_); 202 CritScope cs(&crit_);
167 if (thread_ == nullptr) 203 if (thread_ == nullptr)
168 return false; 204 return false;
169 invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(posted_from, thread_, 205 invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(posted_from, thread_,
170 functor, delay_ms, id); 206 functor, delay_ms, id);
171 return true; 207 return true;
172 } 208 }
173 209
174 // Call |functor| asynchronously, calling |callback| when done. Returns false 210 // Call |functor| asynchronously, calling |callback| when done. Returns false
175 // if the thread has died. 211 // if the thread has died.
176 template <class ReturnT, class FunctorT, class HostT> 212 template <class ReturnT, class FunctorT, class HostT>
177 bool AsyncInvoke(const Location& posted_from, 213 bool AsyncInvoke(const Location& posted_from,
178 const Location& callback_posted_from, 214 const Location& callback_posted_from,
179 const FunctorT& functor, 215 const FunctorT& functor,
180 void (HostT::*callback)(ReturnT), 216 void (HostT::*callback)(ReturnT),
181 HostT* callback_host, 217 HostT* callback_host,
182 uint32_t id = 0) { 218 uint32_t id = 0) {
183 rtc::CritScope cs(&crit_); 219 CritScope cs(&crit_);
184 if (thread_ == nullptr) 220 if (thread_ == nullptr)
185 return false; 221 return false;
186 invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>( 222 invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
187 posted_from, callback_posted_from, thread_, functor, callback, 223 posted_from, callback_posted_from, thread_, functor, callback,
188 callback_host, id); 224 callback_host, id);
189 return true; 225 return true;
190 } 226 }
191 227
192 // Call |functor| asynchronously calling |callback| when done. Overloaded for 228 // Call |functor| asynchronously calling |callback| when done. Overloaded for
193 // void return. Returns false if the thread has died. 229 // void return. Returns false if the thread has died.
194 template <class ReturnT, class FunctorT, class HostT> 230 template <class ReturnT, class FunctorT, class HostT>
195 bool AsyncInvoke(const Location& posted_from, 231 bool AsyncInvoke(const Location& posted_from,
196 const Location& callback_posted_from, 232 const Location& callback_posted_from,
197 const FunctorT& functor, 233 const FunctorT& functor,
198 void (HostT::*callback)(), 234 void (HostT::*callback)(),
199 HostT* callback_host, 235 HostT* callback_host,
200 uint32_t id = 0) { 236 uint32_t id = 0) {
201 rtc::CritScope cs(&crit_); 237 CritScope cs(&crit_);
202 if (thread_ == nullptr) 238 if (thread_ == nullptr)
203 return false; 239 return false;
204 invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>( 240 invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
205 posted_from, callback_posted_from, thread_, functor, callback, 241 posted_from, callback_posted_from, thread_, functor, callback,
206 callback_host, id); 242 callback_host, id);
207 return true; 243 return true;
208 } 244 }
209 245
210 private: 246 private:
211 // Callback when |thread_| is destroyed. 247 // Callback when |thread_| is destroyed.
212 void ThreadDestroyed(); 248 void ThreadDestroyed();
213 249
214 CriticalSection crit_; 250 CriticalSection crit_;
215 Thread* thread_ GUARDED_BY(crit_); 251 Thread* thread_ GUARDED_BY(crit_);
216 AsyncInvoker invoker_ GUARDED_BY(crit_); 252 AsyncInvoker invoker_ GUARDED_BY(crit_);
217 }; 253 };
218 254
219 } // namespace rtc 255 } // namespace rtc
220 256
221 #endif // WEBRTC_RTC_BASE_ASYNCINVOKER_H_ 257 #endif // WEBRTC_RTC_BASE_ASYNCINVOKER_H_
OLDNEW
« no previous file with comments | « no previous file | webrtc/rtc_base/asyncinvoker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698