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
20namespace 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//   };
69class 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.
152class 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