blob: 8584bdaea2155470dec5e927d0e64c252d3e85b1 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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 09:11:00 -080011#include "rtc_base/async_invoker.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/checks.h"
14#include "rtc_base/logging.h"
Per33544192015-04-02 12:30:51 +020015
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016namespace rtc {
17
deadbeef3af63b02017-08-08 17:59:47 -070018AsyncInvoker::AsyncInvoker()
19 : pending_invocations_(0),
Niels Möllerc572ff32018-11-07 08:43:50 +010020 invocation_complete_(new RefCountedObject<Event>()),
deadbeef3af63b02017-08-08 17:59:47 -070021 destroying_(false) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022
23AsyncInvoker::~AsyncInvoker() {
deadbeef3af63b02017-08-08 17:59:47 -070024 destroying_.store(true, std::memory_order_relaxed);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025 // Messages for this need to be cleared *before* our destructor is complete.
26 MessageQueueManager::Clear(this);
deadbeef162cb532017-02-23 17:10:07 -080027 // And we need to wait for any invocations that are still in progress on
deadbeef3af63b02017-08-08 17:59:47 -070028 // other threads. Using memory_order_acquire for synchronization with
29 // AsyncClosure destructors.
30 while (pending_invocations_.load(std::memory_order_acquire) > 0) {
deadbeef162cb532017-02-23 17:10:07 -080031 // If the destructor was called while AsyncInvoke was being called by
32 // another thread, WITHIN an AsyncInvoked functor, it may do another
33 // Thread::Post even after we called MessageQueueManager::Clear(this). So
34 // we need to keep calling Clear to discard these posts.
deadbeef3af63b02017-08-08 17:59:47 -070035 Thread::Current()->Clear(this);
36 invocation_complete_->Wait(Event::kForever);
deadbeef162cb532017-02-23 17:10:07 -080037 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000038}
39
40void AsyncInvoker::OnMessage(Message* msg) {
41 // Get the AsyncClosure shared ptr from this message's data.
deadbeefa8bc1a12017-02-17 18:06:26 -080042 ScopedMessageData<AsyncClosure>* data =
43 static_cast<ScopedMessageData<AsyncClosure>*>(msg->pdata);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000044 // Execute the closure and trigger the return message if needed.
deadbeefa8bc1a12017-02-17 18:06:26 -080045 data->inner_data().Execute();
46 delete data;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000047}
48
Peter Boström0c4e06b2015-10-07 12:23:21 +020049void AsyncInvoker::Flush(Thread* thread, uint32_t id /*= MQID_ANY*/) {
deadbeef3af63b02017-08-08 17:59:47 -070050 // If the destructor is waiting for invocations to finish, don't start
51 // running even more tasks.
52 if (destroying_.load(std::memory_order_relaxed))
53 return;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000054
55 // Run this on |thread| to reduce the number of context switches.
56 if (Thread::Current() != thread) {
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070057 thread->Invoke<void>(RTC_FROM_HERE,
58 Bind(&AsyncInvoker::Flush, this, thread, id));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 return;
60 }
61
62 MessageList removed;
63 thread->Clear(this, id, &removed);
64 for (MessageList::iterator it = removed.begin(); it != removed.end(); ++it) {
65 // This message was pending on this thread, so run it now.
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070066 thread->Send(it->posted_from, it->phandler, it->message_id, it->pdata);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 }
68}
69
Chris Dziemborowiczc38d3202018-01-31 12:52:24 -080070void AsyncInvoker::Clear() {
71 MessageQueueManager::Clear(this);
72}
73
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070074void AsyncInvoker::DoInvoke(const Location& posted_from,
75 Thread* thread,
deadbeefa8bc1a12017-02-17 18:06:26 -080076 std::unique_ptr<AsyncClosure> closure,
Peter Boström0c4e06b2015-10-07 12:23:21 +020077 uint32_t id) {
deadbeef3af63b02017-08-08 17:59:47 -070078 if (destroying_.load(std::memory_order_relaxed)) {
79 // Note that this may be expected, if the application is AsyncInvoking
80 // tasks that AsyncInvoke other tasks. But otherwise it indicates a race
81 // between a thread destroying the AsyncInvoker and a thread still trying
82 // to use it.
Mirko Bonadei675513b2017-11-09 11:09:25 +010083 RTC_LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000084 return;
85 }
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070086 thread->Post(posted_from, this, id,
deadbeefa8bc1a12017-02-17 18:06:26 -080087 new ScopedMessageData<AsyncClosure>(std::move(closure)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088}
89
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -070090void AsyncInvoker::DoInvokeDelayed(const Location& posted_from,
91 Thread* thread,
deadbeefa8bc1a12017-02-17 18:06:26 -080092 std::unique_ptr<AsyncClosure> closure,
Peter Boström0c4e06b2015-10-07 12:23:21 +020093 uint32_t delay_ms,
94 uint32_t id) {
deadbeef3af63b02017-08-08 17:59:47 -070095 if (destroying_.load(std::memory_order_relaxed)) {
96 // See above comment.
Mirko Bonadei675513b2017-11-09 11:09:25 +010097 RTC_LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -070098 return;
99 }
Taylor Brandstetter5d97a9a2016-06-10 14:17:27 -0700100 thread->PostDelayed(posted_from, delay_ms, this, id,
deadbeefa8bc1a12017-02-17 18:06:26 -0800101 new ScopedMessageData<AsyncClosure>(std::move(closure)));
Guo-wei Shiehdc13abc2015-06-18 14:44:41 -0700102}
103
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200104GuardedAsyncInvoker::GuardedAsyncInvoker() : thread_(Thread::Current()) {
105 thread_->SignalQueueDestroyed.connect(this,
106 &GuardedAsyncInvoker::ThreadDestroyed);
107}
108
Yves Gerey665174f2018-06-19 15:03:05 +0200109GuardedAsyncInvoker::~GuardedAsyncInvoker() {}
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200110
Peter Boström0c4e06b2015-10-07 12:23:21 +0200111bool GuardedAsyncInvoker::Flush(uint32_t id) {
deadbeef3af63b02017-08-08 17:59:47 -0700112 CritScope cs(&crit_);
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200113 if (thread_ == nullptr)
114 return false;
115 invoker_.Flush(thread_, id);
116 return true;
117}
118
119void GuardedAsyncInvoker::ThreadDestroyed() {
deadbeef3af63b02017-08-08 17:59:47 -0700120 CritScope cs(&crit_);
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200121 // We should never get more than one notification about the thread dying.
henrikg91d6ede2015-09-17 00:24:34 -0700122 RTC_DCHECK(thread_ != nullptr);
Magnus Jedverta1f590f2015-08-20 16:42:42 +0200123 thread_ = nullptr;
124}
125
deadbeef3af63b02017-08-08 17:59:47 -0700126AsyncClosure::AsyncClosure(AsyncInvoker* invoker)
127 : invoker_(invoker), invocation_complete_(invoker_->invocation_complete_) {
128 invoker_->pending_invocations_.fetch_add(1, std::memory_order_relaxed);
129}
130
deadbeef162cb532017-02-23 17:10:07 -0800131AsyncClosure::~AsyncClosure() {
deadbeef3af63b02017-08-08 17:59:47 -0700132 // Using memory_order_release for synchronization with the AsyncInvoker
133 // destructor.
134 invoker_->pending_invocations_.fetch_sub(1, std::memory_order_release);
135
136 // After |pending_invocations_| is decremented, we may need to signal
137 // |invocation_complete_| in case the AsyncInvoker is being destroyed and
138 // waiting for pending tasks to complete.
139 //
140 // It's also possible that the destructor finishes before "Set()" is called,
141 // which is safe because the event is reference counted (and in a thread-safe
142 // way).
143 invocation_complete_->Set();
deadbeef162cb532017-02-23 17:10:07 -0800144}
145
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000146} // namespace rtc