blob: 621375ccd212364aafb64dfd92d91e49de71792d [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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
Steve Anton10542f22019-01-11 17:11:0011#ifndef RTC_BASE_ASYNC_INVOKER_H_
12#define RTC_BASE_ASYNC_INVOKER_H_
henrike@webrtc.orgf0488722014-05-13 18:00:2613
deadbeef3af63b02017-08-09 00:59:4714#include <atomic>
Henrik Kjellanderec78f1c2017-06-29 05:52:5015#include <memory>
16#include <utility>
deadbeefa8bc1a12017-02-18 02:06:2617
Niels Möller0694ce72021-05-03 14:03:2218#include "absl/base/attributes.h"
Mirko Bonadeid9708072019-01-25 19:26:4819#include "api/scoped_refptr.h"
Steve Anton10542f22019-01-11 17:11:0020#include "rtc_base/async_invoker_inl.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3121#include "rtc_base/event.h"
Artem Titove41c4332018-07-25 13:04:2822#include "rtc_base/third_party/sigslot/sigslot.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3123#include "rtc_base/thread.h"
Henrik Kjellanderec78f1c2017-06-29 05:52:5024
25namespace rtc {
26
Tommi9ebe6d72021-11-16 15:07:3427// DEPRECATED - do not use.
28//
Henrik Kjellanderec78f1c2017-06-29 05:52:5029// Invokes function objects (aka functors) asynchronously on a Thread, and
30// owns the lifetime of calls (ie, when this object is destroyed, calls in
31// flight are cancelled). AsyncInvoker can optionally execute a user-specified
32// function when the asynchronous call is complete, or operates in
33// fire-and-forget mode otherwise.
34//
35// AsyncInvoker does not own the thread it calls functors on.
36//
37// A note about async calls and object lifetimes: users should
38// be mindful of object lifetimes when calling functions asynchronously and
39// ensure objects used by the function _cannot_ be deleted between the
40// invocation and execution of the functor. AsyncInvoker is designed to
41// help: any calls in flight will be cancelled when the AsyncInvoker used to
42// make the call is destructed, and any calls executing will be allowed to
43// complete before AsyncInvoker destructs.
44//
45// The easiest way to ensure lifetimes are handled correctly is to create a
46// class that owns the Thread and AsyncInvoker objects, and then call its
47// methods asynchronously as needed.
48//
49// Example:
50// class MyClass {
51// public:
52// void FireAsyncTaskWithResult(Thread* thread, int x) {
53// // Specify a callback to get the result upon completion.
54// invoker_.AsyncInvoke<int>(RTC_FROM_HERE,
55// thread, Bind(&MyClass::AsyncTaskWithResult, this, x),
56// &MyClass::OnTaskComplete, this);
57// }
58// void FireAnotherAsyncTask(Thread* thread) {
59// // No callback specified means fire-and-forget.
60// invoker_.AsyncInvoke<void>(RTC_FROM_HERE,
61// thread, Bind(&MyClass::AnotherAsyncTask, this));
62//
63// private:
64// int AsyncTaskWithResult(int x) {
65// // Some long running process...
66// return x * x;
67// }
68// void AnotherAsyncTask() {
69// // Some other long running process...
70// }
71// void OnTaskComplete(int result) { result_ = result; }
72//
73// AsyncInvoker invoker_;
74// int result_;
75// };
deadbeef3af63b02017-08-09 00:59:4776//
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.
Niels Möller0694ce72021-05-03 14:03:2290class DEPRECATED_AsyncInvoker : public MessageHandlerAutoCleanup {
Henrik Kjellanderec78f1c2017-06-29 05:52:5091 public:
Niels Möller0694ce72021-05-03 14:03:2292 DEPRECATED_AsyncInvoker();
93 ~DEPRECATED_AsyncInvoker() override;
Henrik Kjellanderec78f1c2017-06-29 05:52:5094
Byoungchan Lee14af7622022-01-11 20:24:5895 DEPRECATED_AsyncInvoker(const DEPRECATED_AsyncInvoker&) = delete;
96 DEPRECATED_AsyncInvoker& operator=(const DEPRECATED_AsyncInvoker&) = delete;
97
Artem Titov96e3b992021-07-26 14:03:1498 // Call `functor` asynchronously on `thread`, with no callback upon
Henrik Kjellanderec78f1c2017-06-29 05:52:5099 // completion. Returns immediately.
100 template <class ReturnT, class FunctorT>
101 void AsyncInvoke(const Location& posted_from,
102 Thread* thread,
Cameron Pickettd132ce12018-03-12 23:07:37103 FunctorT&& functor,
Henrik Kjellanderec78f1c2017-06-29 05:52:50104 uint32_t id = 0) {
105 std::unique_ptr<AsyncClosure> closure(
Cameron Pickettd132ce12018-03-12 23:07:37106 new FireAndForgetAsyncClosure<FunctorT>(
107 this, std::forward<FunctorT>(functor)));
Henrik Kjellanderec78f1c2017-06-29 05:52:50108 DoInvoke(posted_from, thread, std::move(closure), id);
109 }
110
Artem Titov96e3b992021-07-26 14:03:14111 // Call `functor` asynchronously on `thread` with `delay_ms`, with no callback
Henrik Kjellanderec78f1c2017-06-29 05:52:50112 // upon completion. Returns immediately.
113 template <class ReturnT, class FunctorT>
114 void AsyncInvokeDelayed(const Location& posted_from,
115 Thread* thread,
Cameron Pickettd132ce12018-03-12 23:07:37116 FunctorT&& functor,
Henrik Kjellanderec78f1c2017-06-29 05:52:50117 uint32_t delay_ms,
118 uint32_t id = 0) {
119 std::unique_ptr<AsyncClosure> closure(
Cameron Pickettd132ce12018-03-12 23:07:37120 new FireAndForgetAsyncClosure<FunctorT>(
121 this, std::forward<FunctorT>(functor)));
Henrik Kjellanderec78f1c2017-06-29 05:52:50122 DoInvokeDelayed(posted_from, thread, std::move(closure), delay_ms, id);
123 }
124
Chris Dziemborowiczc38d3202018-01-31 20:52:24125 // Cancels any outstanding calls we own that are pending on any thread, and
126 // which have not yet started to execute. This does not wait for any calls
127 // that have already started executing to complete.
128 void Clear();
129
Henrik Kjellanderec78f1c2017-06-29 05:52:50130 private:
131 void OnMessage(Message* msg) override;
132 void DoInvoke(const Location& posted_from,
133 Thread* thread,
134 std::unique_ptr<AsyncClosure> closure,
135 uint32_t id);
136 void DoInvokeDelayed(const Location& posted_from,
137 Thread* thread,
138 std::unique_ptr<AsyncClosure> closure,
139 uint32_t delay_ms,
140 uint32_t id);
deadbeef3af63b02017-08-09 00:59:47141
142 // Used to keep track of how many invocations (AsyncClosures) are still
143 // alive, so that the destructor can wait for them to finish, as described in
144 // the class documentation.
145 //
146 // TODO(deadbeef): Using a raw std::atomic like this is prone to error and
147 // difficult to maintain. We should try to wrap this functionality in a
148 // separate class to reduce the chance of errors being introduced in the
149 // future.
150 std::atomic<int> pending_invocations_;
151
Tommi9ebe6d72021-11-16 15:07:34152 // Reference counted so that if the destructor finishes before an
153 // AsyncClosure's destructor that's about to call
154 // "invocation_complete_->Set()", it's not dereferenced after being destroyed.
Niels Möllerbed85072022-06-14 10:30:16155 rtc::scoped_refptr<FinalRefCountedObject<Event>> invocation_complete_;
deadbeef3af63b02017-08-09 00:59:47156
157 // This flag is used to ensure that if an application AsyncInvokes tasks that
158 // recursively AsyncInvoke other tasks ad infinitum, the cycle eventually
159 // terminates.
160 std::atomic<bool> destroying_;
161
Henrik Kjellanderec78f1c2017-06-29 05:52:50162 friend class AsyncClosure;
Henrik Kjellanderec78f1c2017-06-29 05:52:50163};
164
Henrik Kjellanderec78f1c2017-06-29 05:52:50165} // namespace rtc
henrike@webrtc.orgf0488722014-05-13 18:00:26166
Steve Anton10542f22019-01-11 17:11:00167#endif // RTC_BASE_ASYNC_INVOKER_H_