| Index: webrtc/rtc_base/asyncinvoker.h
|
| diff --git a/webrtc/rtc_base/asyncinvoker.h b/webrtc/rtc_base/asyncinvoker.h
|
| index 17d702a37bdce677636475f7f09cd52c5ffe9f1d..455ded24dda81802b708c4c20402b0820a2284d0 100644
|
| --- a/webrtc/rtc_base/asyncinvoker.h
|
| +++ b/webrtc/rtc_base/asyncinvoker.h
|
| @@ -11,6 +11,7 @@
|
| #ifndef WEBRTC_RTC_BASE_ASYNCINVOKER_H_
|
| #define WEBRTC_RTC_BASE_ASYNCINVOKER_H_
|
|
|
| +#include <atomic>
|
| #include <memory>
|
| #include <utility>
|
|
|
| @@ -18,6 +19,8 @@
|
| #include "webrtc/rtc_base/bind.h"
|
| #include "webrtc/rtc_base/constructormagic.h"
|
| #include "webrtc/rtc_base/event.h"
|
| +#include "webrtc/rtc_base/refcountedobject.h"
|
| +#include "webrtc/rtc_base/scoped_ref_ptr.h"
|
| #include "webrtc/rtc_base/sigslot.h"
|
| #include "webrtc/rtc_base/thread.h"
|
|
|
| @@ -70,6 +73,20 @@ namespace rtc {
|
| // AsyncInvoker invoker_;
|
| // int result_;
|
| // };
|
| +//
|
| +// More details about threading:
|
| +// - It's safe to construct/destruct AsyncInvoker on different threads.
|
| +// - It's safe to call AsyncInvoke from different threads.
|
| +// - It's safe to call AsyncInvoke recursively from *within* a functor that's
|
| +// being AsyncInvoked.
|
| +// - However, it's *not* safe to call AsyncInvoke from *outside* a functor
|
| +// that's being AsyncInvoked while the AsyncInvoker is being destroyed on
|
| +// another thread. This is just inherently unsafe and there's no way to
|
| +// prevent that. So, the user of this class should ensure that the start of
|
| +// each "chain" of invocations is synchronized somehow with the AsyncInvoker's
|
| +// destruction. This can be done by starting each chain of invocations on the
|
| +// same thread on which it will be destroyed, or by using some other
|
| +// synchronization method.
|
| class AsyncInvoker : public MessageHandler {
|
| public:
|
| AsyncInvoker();
|
| @@ -118,9 +135,28 @@ class AsyncInvoker : public MessageHandler {
|
| std::unique_ptr<AsyncClosure> closure,
|
| uint32_t delay_ms,
|
| uint32_t id);
|
| - volatile int pending_invocations_ = 0;
|
| - Event invocation_complete_;
|
| - bool destroying_ = false;
|
| +
|
| + // Used to keep track of how many invocations (AsyncClosures) are still
|
| + // alive, so that the destructor can wait for them to finish, as described in
|
| + // the class documentation.
|
| + //
|
| + // TODO(deadbeef): Using a raw std::atomic like this is prone to error and
|
| + // difficult to maintain. We should try to wrap this functionality in a
|
| + // separate class to reduce the chance of errors being introduced in the
|
| + // future.
|
| + std::atomic<int> pending_invocations_;
|
| +
|
| + // Reference counted so that if the AsyncInvoker destructor finishes before
|
| + // an AsyncClosure's destructor that's about to call
|
| + // "invocation_complete_->Set()", it's not dereferenced after being
|
| + // destroyed.
|
| + scoped_refptr<RefCountedObject<Event>> invocation_complete_;
|
| +
|
| + // This flag is used to ensure that if an application AsyncInvokes tasks that
|
| + // recursively AsyncInvoke other tasks ad infinitum, the cycle eventually
|
| + // terminates.
|
| + std::atomic<bool> destroying_;
|
| +
|
| friend class AsyncClosure;
|
|
|
| RTC_DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
|
| @@ -149,7 +185,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> {
|
| bool AsyncInvoke(const Location& posted_from,
|
| const FunctorT& functor,
|
| uint32_t id = 0) {
|
| - rtc::CritScope cs(&crit_);
|
| + CritScope cs(&crit_);
|
| if (thread_ == nullptr)
|
| return false;
|
| invoker_.AsyncInvoke<ReturnT, FunctorT>(posted_from, thread_, functor, id);
|
| @@ -163,7 +199,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> {
|
| const FunctorT& functor,
|
| uint32_t delay_ms,
|
| uint32_t id = 0) {
|
| - rtc::CritScope cs(&crit_);
|
| + CritScope cs(&crit_);
|
| if (thread_ == nullptr)
|
| return false;
|
| invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(posted_from, thread_,
|
| @@ -180,7 +216,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> {
|
| void (HostT::*callback)(ReturnT),
|
| HostT* callback_host,
|
| uint32_t id = 0) {
|
| - rtc::CritScope cs(&crit_);
|
| + CritScope cs(&crit_);
|
| if (thread_ == nullptr)
|
| return false;
|
| invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
|
| @@ -198,7 +234,7 @@ class GuardedAsyncInvoker : public sigslot::has_slots<> {
|
| void (HostT::*callback)(),
|
| HostT* callback_host,
|
| uint32_t id = 0) {
|
| - rtc::CritScope cs(&crit_);
|
| + CritScope cs(&crit_);
|
| if (thread_ == nullptr)
|
| return false;
|
| invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(
|
|
|