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