blob: 83a873811e7258a16a982c39609598114ca78055 [file] [log] [blame]
henrike@webrtc.org47be73b2014-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
11#include "webrtc/base/asyncinvoker.h"
12
Magnus Jedvert26960172015-08-20 14:42:4213#include "webrtc/base/checks.h"
Perf92c6f82015-04-02 10:30:5114#include "webrtc/base/logging.h"
15
henrike@webrtc.org47be73b2014-05-13 18:00:2616namespace rtc {
17
18AsyncInvoker::AsyncInvoker() : destroying_(false) {}
19
20AsyncInvoker::~AsyncInvoker() {
21 destroying_ = true;
22 SignalInvokerDestroyed();
23 // Messages for this need to be cleared *before* our destructor is complete.
24 MessageQueueManager::Clear(this);
25}
26
27void AsyncInvoker::OnMessage(Message* msg) {
28 // Get the AsyncClosure shared ptr from this message's data.
29 ScopedRefMessageData<AsyncClosure>* data =
30 static_cast<ScopedRefMessageData<AsyncClosure>*>(msg->pdata);
31 scoped_refptr<AsyncClosure> closure = data->data();
32 delete msg->pdata;
33 msg->pdata = NULL;
34
35 // Execute the closure and trigger the return message if needed.
36 closure->Execute();
37}
38
Peter Boström07e22e62015-10-07 10:23:2139void AsyncInvoker::Flush(Thread* thread, uint32_t id /*= MQID_ANY*/) {
henrike@webrtc.org47be73b2014-05-13 18:00:2640 if (destroying_) return;
41
42 // Run this on |thread| to reduce the number of context switches.
43 if (Thread::Current() != thread) {
Taylor Brandstetterc0bec8f2016-06-10 21:17:2744 thread->Invoke<void>(RTC_FROM_HERE,
45 Bind(&AsyncInvoker::Flush, this, thread, id));
henrike@webrtc.org47be73b2014-05-13 18:00:2646 return;
47 }
48
49 MessageList removed;
50 thread->Clear(this, id, &removed);
51 for (MessageList::iterator it = removed.begin(); it != removed.end(); ++it) {
52 // This message was pending on this thread, so run it now.
Taylor Brandstetterc0bec8f2016-06-10 21:17:2753 thread->Send(it->posted_from, it->phandler, it->message_id, it->pdata);
henrike@webrtc.org47be73b2014-05-13 18:00:2654 }
55}
56
Taylor Brandstetterc0bec8f2016-06-10 21:17:2757void AsyncInvoker::DoInvoke(const Location& posted_from,
58 Thread* thread,
perkj@webrtc.org3cb7a632015-01-29 08:53:4559 const scoped_refptr<AsyncClosure>& closure,
Peter Boström07e22e62015-10-07 10:23:2160 uint32_t id) {
henrike@webrtc.org47be73b2014-05-13 18:00:2661 if (destroying_) {
62 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
henrike@webrtc.org47be73b2014-05-13 18:00:2663 return;
64 }
Taylor Brandstetterc0bec8f2016-06-10 21:17:2765 thread->Post(posted_from, this, id,
66 new ScopedRefMessageData<AsyncClosure>(closure));
henrike@webrtc.org47be73b2014-05-13 18:00:2667}
68
Taylor Brandstetterc0bec8f2016-06-10 21:17:2769void AsyncInvoker::DoInvokeDelayed(const Location& posted_from,
70 Thread* thread,
Guo-wei Shieh5aca27b2015-06-18 21:44:4171 const scoped_refptr<AsyncClosure>& closure,
Peter Boström07e22e62015-10-07 10:23:2172 uint32_t delay_ms,
73 uint32_t id) {
Guo-wei Shieh5aca27b2015-06-18 21:44:4174 if (destroying_) {
75 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
76 return;
77 }
Taylor Brandstetterc0bec8f2016-06-10 21:17:2778 thread->PostDelayed(posted_from, delay_ms, this, id,
Guo-wei Shieh5aca27b2015-06-18 21:44:4179 new ScopedRefMessageData<AsyncClosure>(closure));
80}
81
Magnus Jedvert26960172015-08-20 14:42:4282GuardedAsyncInvoker::GuardedAsyncInvoker() : thread_(Thread::Current()) {
83 thread_->SignalQueueDestroyed.connect(this,
84 &GuardedAsyncInvoker::ThreadDestroyed);
85}
86
87GuardedAsyncInvoker::~GuardedAsyncInvoker() {
88}
89
Peter Boström07e22e62015-10-07 10:23:2190bool GuardedAsyncInvoker::Flush(uint32_t id) {
Magnus Jedvert26960172015-08-20 14:42:4291 rtc::CritScope cs(&crit_);
92 if (thread_ == nullptr)
93 return false;
94 invoker_.Flush(thread_, id);
95 return true;
96}
97
98void GuardedAsyncInvoker::ThreadDestroyed() {
99 rtc::CritScope cs(&crit_);
100 // We should never get more than one notification about the thread dying.
henrikg5c075c82015-09-17 07:24:34101 RTC_DCHECK(thread_ != nullptr);
Magnus Jedvert26960172015-08-20 14:42:42102 thread_ = nullptr;
103}
104
Taylor Brandstetterc0bec8f2016-06-10 21:17:27105NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(
106 AsyncInvoker* invoker,
107 const Location& callback_posted_from,
108 Thread* calling_thread)
109 : invoker_(invoker),
110 callback_posted_from_(callback_posted_from),
111 calling_thread_(calling_thread) {
henrike@webrtc.org47be73b2014-05-13 18:00:26112 calling_thread->SignalQueueDestroyed.connect(
113 this, &NotifyingAsyncClosureBase::CancelCallback);
114 invoker->SignalInvokerDestroyed.connect(
115 this, &NotifyingAsyncClosureBase::CancelCallback);
116}
117
kwiberg@webrtc.org786b6342015-03-09 22:21:53118NotifyingAsyncClosureBase::~NotifyingAsyncClosureBase() {
119 disconnect_all();
120}
121
henrike@webrtc.org47be73b2014-05-13 18:00:26122void NotifyingAsyncClosureBase::TriggerCallback() {
123 CritScope cs(&crit_);
124 if (!CallbackCanceled() && !callback_.empty()) {
Taylor Brandstetterc0bec8f2016-06-10 21:17:27125 invoker_->AsyncInvoke<void>(callback_posted_from_, calling_thread_,
126 callback_);
henrike@webrtc.org47be73b2014-05-13 18:00:26127 }
128}
129
130void NotifyingAsyncClosureBase::CancelCallback() {
131 // If the callback is triggering when this is called, block the
132 // destructor of the dying object here by waiting until the callback
133 // is done triggering.
134 CritScope cs(&crit_);
135 // calling_thread_ == NULL means do not trigger the callback.
136 calling_thread_ = NULL;
137}
138
139} // namespace rtc