Home | History | Annotate | Download | only in base
      1 /*
      2  *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
      3  *
      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
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #ifndef WEBRTC_BASE_ASYNCINVOKER_H_
     12 #define WEBRTC_BASE_ASYNCINVOKER_H_
     13 
     14 #include "webrtc/base/asyncinvoker-inl.h"
     15 #include "webrtc/base/bind.h"
     16 #include "webrtc/base/sigslot.h"
     17 #include "webrtc/base/scopedptrcollection.h"
     18 #include "webrtc/base/thread.h"
     19 
     20 namespace rtc {
     21 
     22 // Invokes function objects (aka functors) asynchronously on a Thread, and
     23 // owns the lifetime of calls (ie, when this object is destroyed, calls in
     24 // flight are cancelled). AsyncInvoker can optionally execute a user-specified
     25 // function when the asynchronous call is complete, or operates in
     26 // fire-and-forget mode otherwise.
     27 //
     28 // AsyncInvoker does not own the thread it calls functors on.
     29 //
     30 // A note about async calls and object lifetimes: users should
     31 // be mindful of object lifetimes when calling functions asynchronously and
     32 // ensure objects used by the function _cannot_ be deleted between the
     33 // invocation and execution of the functor. AsyncInvoker is designed to
     34 // help: any calls in flight will be cancelled when the AsyncInvoker used to
     35 // make the call is destructed, and any calls executing will be allowed to
     36 // complete before AsyncInvoker destructs.
     37 //
     38 // The easiest way to ensure lifetimes are handled correctly is to create a
     39 // class that owns the Thread and AsyncInvoker objects, and then call its
     40 // methods asynchronously as needed.
     41 //
     42 // Example:
     43 //   class MyClass {
     44 //    public:
     45 //     void FireAsyncTaskWithResult(Thread* thread, int x) {
     46 //       // Specify a callback to get the result upon completion.
     47 //       invoker_.AsyncInvoke<int>(
     48 //           thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
     49 //           &MyClass::OnTaskComplete, this);
     50 //     }
     51 //     void FireAnotherAsyncTask(Thread* thread) {
     52 //       // No callback specified means fire-and-forget.
     53 //       invoker_.AsyncInvoke<void>(
     54 //           thread, Bind(&MyClass::AnotherAsyncTask, this));
     55 //
     56 //    private:
     57 //     int AsyncTaskWithResult(int x) {
     58 //       // Some long running process...
     59 //       return x * x;
     60 //     }
     61 //     void AnotherAsyncTask() {
     62 //       // Some other long running process...
     63 //     }
     64 //     void OnTaskComplete(int result) { result_ = result; }
     65 //
     66 //     AsyncInvoker invoker_;
     67 //     int result_;
     68 //   };
     69 class AsyncInvoker : public MessageHandler {
     70  public:
     71   AsyncInvoker();
     72   ~AsyncInvoker() override;
     73 
     74   // Call |functor| asynchronously on |thread|, with no callback upon
     75   // completion. Returns immediately.
     76   template <class ReturnT, class FunctorT>
     77   void AsyncInvoke(Thread* thread, const FunctorT& functor, uint32_t id = 0) {
     78     scoped_refptr<AsyncClosure> closure(
     79         new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor));
     80     DoInvoke(thread, closure, id);
     81   }
     82 
     83   // Call |functor| asynchronously on |thread| with |delay_ms|, with no callback
     84   // upon completion. Returns immediately.
     85   template <class ReturnT, class FunctorT>
     86   void AsyncInvokeDelayed(Thread* thread,
     87                           const FunctorT& functor,
     88                           uint32_t delay_ms,
     89                           uint32_t id = 0) {
     90     scoped_refptr<AsyncClosure> closure(
     91         new RefCountedObject<FireAndForgetAsyncClosure<FunctorT> >(functor));
     92     DoInvokeDelayed(thread, closure, delay_ms, id);
     93   }
     94 
     95   // Call |functor| asynchronously on |thread|, calling |callback| when done.
     96   template <class ReturnT, class FunctorT, class HostT>
     97   void AsyncInvoke(Thread* thread,
     98                    const FunctorT& functor,
     99                    void (HostT::*callback)(ReturnT),
    100                    HostT* callback_host,
    101                    uint32_t id = 0) {
    102     scoped_refptr<AsyncClosure> closure(
    103         new RefCountedObject<NotifyingAsyncClosure<ReturnT, FunctorT, HostT> >(
    104             this, Thread::Current(), functor, callback, callback_host));
    105     DoInvoke(thread, closure, id);
    106   }
    107 
    108   // Call |functor| asynchronously on |thread|, calling |callback| when done.
    109   // Overloaded for void return.
    110   template <class ReturnT, class FunctorT, class HostT>
    111   void AsyncInvoke(Thread* thread,
    112                    const FunctorT& functor,
    113                    void (HostT::*callback)(),
    114                    HostT* callback_host,
    115                    uint32_t id = 0) {
    116     scoped_refptr<AsyncClosure> closure(
    117         new RefCountedObject<NotifyingAsyncClosure<void, FunctorT, HostT> >(
    118             this, Thread::Current(), functor, callback, callback_host));
    119     DoInvoke(thread, closure, id);
    120   }
    121 
    122   // Synchronously execute on |thread| all outstanding calls we own
    123   // that are pending on |thread|, and wait for calls to complete
    124   // before returning. Optionally filter by message id.
    125   // The destructor will not wait for outstanding calls, so if that
    126   // behavior is desired, call Flush() before destroying this object.
    127   void Flush(Thread* thread, uint32_t id = MQID_ANY);
    128 
    129   // Signaled when this object is destructed.
    130   sigslot::signal0<> SignalInvokerDestroyed;
    131 
    132  private:
    133   void OnMessage(Message* msg) override;
    134   void DoInvoke(Thread* thread,
    135                 const scoped_refptr<AsyncClosure>& closure,
    136                 uint32_t id);
    137   void DoInvokeDelayed(Thread* thread,
    138                        const scoped_refptr<AsyncClosure>& closure,
    139                        uint32_t delay_ms,
    140                        uint32_t id);
    141   bool destroying_;
    142 
    143   RTC_DISALLOW_COPY_AND_ASSIGN(AsyncInvoker);
    144 };
    145 
    146 // Similar to AsyncInvoker, but guards against the Thread being destroyed while
    147 // there are outstanding dangling pointers to it. It will connect to the current
    148 // thread in the constructor, and will get notified when that thread is
    149 // destroyed. After GuardedAsyncInvoker is constructed, it can be used from
    150 // other threads to post functors to the thread it was constructed on. If that
    151 // thread dies, any further calls to AsyncInvoke() will be safely ignored.
    152 class GuardedAsyncInvoker : public sigslot::has_slots<> {
    153  public:
    154   GuardedAsyncInvoker();
    155   ~GuardedAsyncInvoker() override;
    156 
    157   // Synchronously execute all outstanding calls we own, and wait for calls to
    158   // complete before returning. Optionally filter by message id. The destructor
    159   // will not wait for outstanding calls, so if that behavior is desired, call
    160   // Flush() first. Returns false if the thread has died.
    161   bool Flush(uint32_t id = MQID_ANY);
    162 
    163   // Call |functor| asynchronously with no callback upon completion. Returns
    164   // immediately. Returns false if the thread has died.
    165   template <class ReturnT, class FunctorT>
    166   bool AsyncInvoke(const FunctorT& functor, uint32_t id = 0) {
    167     rtc::CritScope cs(&crit_);
    168     if (thread_ == nullptr)
    169       return false;
    170     invoker_.AsyncInvoke<ReturnT, FunctorT>(thread_, functor, id);
    171     return true;
    172   }
    173 
    174   // Call |functor| asynchronously with |delay_ms|, with no callback upon
    175   // completion. Returns immediately. Returns false if the thread has died.
    176   template <class ReturnT, class FunctorT>
    177   bool AsyncInvokeDelayed(const FunctorT& functor,
    178                           uint32_t delay_ms,
    179                           uint32_t id = 0) {
    180     rtc::CritScope cs(&crit_);
    181     if (thread_ == nullptr)
    182       return false;
    183     invoker_.AsyncInvokeDelayed<ReturnT, FunctorT>(thread_, functor, delay_ms,
    184                                                    id);
    185     return true;
    186   }
    187 
    188   // Call |functor| asynchronously, calling |callback| when done. Returns false
    189   // if the thread has died.
    190   template <class ReturnT, class FunctorT, class HostT>
    191   bool AsyncInvoke(const FunctorT& functor,
    192                    void (HostT::*callback)(ReturnT),
    193                    HostT* callback_host,
    194                    uint32_t id = 0) {
    195     rtc::CritScope cs(&crit_);
    196     if (thread_ == nullptr)
    197       return false;
    198     invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(thread_, functor, callback,
    199                                                    callback_host, id);
    200     return true;
    201   }
    202 
    203   // Call |functor| asynchronously calling |callback| when done. Overloaded for
    204   // void return. Returns false if the thread has died.
    205   template <class ReturnT, class FunctorT, class HostT>
    206   bool AsyncInvoke(const FunctorT& functor,
    207                    void (HostT::*callback)(),
    208                    HostT* callback_host,
    209                    uint32_t id = 0) {
    210     rtc::CritScope cs(&crit_);
    211     if (thread_ == nullptr)
    212       return false;
    213     invoker_.AsyncInvoke<ReturnT, FunctorT, HostT>(thread_, functor, callback,
    214                                                    callback_host, id);
    215     return true;
    216   }
    217 
    218  private:
    219   // Callback when |thread_| is destroyed.
    220   void ThreadDestroyed();
    221 
    222   CriticalSection crit_;
    223   Thread* thread_ GUARDED_BY(crit_);
    224   AsyncInvoker invoker_ GUARDED_BY(crit_);
    225 };
    226 
    227 }  // namespace rtc
    228 
    229 #endif  // WEBRTC_BASE_ASYNCINVOKER_H_
    230