Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: webrtc/base/asyncinvoker.cc

Issue 2694723004: Making AsyncInvoker destructor thread-safe. (Closed)
Patch Set: Merge with master Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/asyncinvoker.h ('k') | webrtc/base/asyncinvoker-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2014 The WebRTC Project Authors. All rights reserved. 2 * Copyright 2014 The WebRTC Project Authors. All rights reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/base/asyncinvoker.h" 11 #include "webrtc/base/asyncinvoker.h"
12 12
13 #include "webrtc/base/atomicops.h"
13 #include "webrtc/base/checks.h" 14 #include "webrtc/base/checks.h"
14 #include "webrtc/base/logging.h" 15 #include "webrtc/base/logging.h"
15 16
16 namespace rtc { 17 namespace rtc {
17 18
18 AsyncInvoker::AsyncInvoker() : destroying_(false) {} 19 AsyncInvoker::AsyncInvoker() : invocation_complete_(false, false) {}
19 20
20 AsyncInvoker::~AsyncInvoker() { 21 AsyncInvoker::~AsyncInvoker() {
21 destroying_ = true; 22 destroying_ = true;
22 SignalInvokerDestroyed(); 23 SignalInvokerDestroyed();
23 // Messages for this need to be cleared *before* our destructor is complete. 24 // Messages for this need to be cleared *before* our destructor is complete.
24 MessageQueueManager::Clear(this); 25 MessageQueueManager::Clear(this);
26 // And we need to wait for any invocations that are still in progress on
27 // other threads.
28 while (AtomicOps::AcquireLoad(&pending_invocations_)) {
29 // If the destructor was called while AsyncInvoke was being called by
30 // another thread, WITHIN an AsyncInvoked functor, it may do another
31 // Thread::Post even after we called MessageQueueManager::Clear(this). So
32 // we need to keep calling Clear to discard these posts.
33 MessageQueueManager::Clear(this);
34 invocation_complete_.Wait(Event::kForever);
35 }
25 } 36 }
26 37
27 void AsyncInvoker::OnMessage(Message* msg) { 38 void AsyncInvoker::OnMessage(Message* msg) {
28 // Get the AsyncClosure shared ptr from this message's data. 39 // Get the AsyncClosure shared ptr from this message's data.
29 ScopedMessageData<AsyncClosure>* data = 40 ScopedMessageData<AsyncClosure>* data =
30 static_cast<ScopedMessageData<AsyncClosure>*>(msg->pdata); 41 static_cast<ScopedMessageData<AsyncClosure>*>(msg->pdata);
31 // Execute the closure and trigger the return message if needed. 42 // Execute the closure and trigger the return message if needed.
32 data->inner_data().Execute(); 43 data->inner_data().Execute();
33 delete data; 44 delete data;
34 } 45 }
(...skipping 17 matching lines...) Expand all
52 } 63 }
53 64
54 void AsyncInvoker::DoInvoke(const Location& posted_from, 65 void AsyncInvoker::DoInvoke(const Location& posted_from,
55 Thread* thread, 66 Thread* thread,
56 std::unique_ptr<AsyncClosure> closure, 67 std::unique_ptr<AsyncClosure> closure,
57 uint32_t id) { 68 uint32_t id) {
58 if (destroying_) { 69 if (destroying_) {
59 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker."; 70 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
60 return; 71 return;
61 } 72 }
73 AtomicOps::Increment(&pending_invocations_);
62 thread->Post(posted_from, this, id, 74 thread->Post(posted_from, this, id,
63 new ScopedMessageData<AsyncClosure>(std::move(closure))); 75 new ScopedMessageData<AsyncClosure>(std::move(closure)));
64 } 76 }
65 77
66 void AsyncInvoker::DoInvokeDelayed(const Location& posted_from, 78 void AsyncInvoker::DoInvokeDelayed(const Location& posted_from,
67 Thread* thread, 79 Thread* thread,
68 std::unique_ptr<AsyncClosure> closure, 80 std::unique_ptr<AsyncClosure> closure,
69 uint32_t delay_ms, 81 uint32_t delay_ms,
70 uint32_t id) { 82 uint32_t id) {
71 if (destroying_) { 83 if (destroying_) {
72 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker."; 84 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
73 return; 85 return;
74 } 86 }
87 AtomicOps::Increment(&pending_invocations_);
75 thread->PostDelayed(posted_from, delay_ms, this, id, 88 thread->PostDelayed(posted_from, delay_ms, this, id,
76 new ScopedMessageData<AsyncClosure>(std::move(closure))); 89 new ScopedMessageData<AsyncClosure>(std::move(closure)));
77 } 90 }
78 91
79 GuardedAsyncInvoker::GuardedAsyncInvoker() : thread_(Thread::Current()) { 92 GuardedAsyncInvoker::GuardedAsyncInvoker() : thread_(Thread::Current()) {
80 thread_->SignalQueueDestroyed.connect(this, 93 thread_->SignalQueueDestroyed.connect(this,
81 &GuardedAsyncInvoker::ThreadDestroyed); 94 &GuardedAsyncInvoker::ThreadDestroyed);
82 } 95 }
83 96
84 GuardedAsyncInvoker::~GuardedAsyncInvoker() { 97 GuardedAsyncInvoker::~GuardedAsyncInvoker() {
85 } 98 }
86 99
87 bool GuardedAsyncInvoker::Flush(uint32_t id) { 100 bool GuardedAsyncInvoker::Flush(uint32_t id) {
88 rtc::CritScope cs(&crit_); 101 rtc::CritScope cs(&crit_);
89 if (thread_ == nullptr) 102 if (thread_ == nullptr)
90 return false; 103 return false;
91 invoker_.Flush(thread_, id); 104 invoker_.Flush(thread_, id);
92 return true; 105 return true;
93 } 106 }
94 107
95 void GuardedAsyncInvoker::ThreadDestroyed() { 108 void GuardedAsyncInvoker::ThreadDestroyed() {
96 rtc::CritScope cs(&crit_); 109 rtc::CritScope cs(&crit_);
97 // We should never get more than one notification about the thread dying. 110 // We should never get more than one notification about the thread dying.
98 RTC_DCHECK(thread_ != nullptr); 111 RTC_DCHECK(thread_ != nullptr);
99 thread_ = nullptr; 112 thread_ = nullptr;
100 } 113 }
101 114
115 AsyncClosure::~AsyncClosure() {
116 AtomicOps::Decrement(&invoker_->pending_invocations_);
117 invoker_->invocation_complete_.Set();
118 }
119
102 NotifyingAsyncClosureBase::NotifyingAsyncClosureBase( 120 NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(
103 AsyncInvoker* invoker, 121 AsyncInvoker* invoker,
104 const Location& callback_posted_from, 122 const Location& callback_posted_from,
105 Thread* calling_thread) 123 Thread* calling_thread)
106 : invoker_(invoker), 124 : AsyncClosure(invoker),
107 callback_posted_from_(callback_posted_from), 125 callback_posted_from_(callback_posted_from),
108 calling_thread_(calling_thread) { 126 calling_thread_(calling_thread) {
109 calling_thread->SignalQueueDestroyed.connect( 127 calling_thread->SignalQueueDestroyed.connect(
110 this, &NotifyingAsyncClosureBase::CancelCallback); 128 this, &NotifyingAsyncClosureBase::CancelCallback);
111 invoker->SignalInvokerDestroyed.connect( 129 invoker->SignalInvokerDestroyed.connect(
112 this, &NotifyingAsyncClosureBase::CancelCallback); 130 this, &NotifyingAsyncClosureBase::CancelCallback);
113 } 131 }
114 132
115 NotifyingAsyncClosureBase::~NotifyingAsyncClosureBase() { 133 NotifyingAsyncClosureBase::~NotifyingAsyncClosureBase() {
116 disconnect_all(); 134 disconnect_all();
(...skipping 10 matching lines...) Expand all
127 void NotifyingAsyncClosureBase::CancelCallback() { 145 void NotifyingAsyncClosureBase::CancelCallback() {
128 // If the callback is triggering when this is called, block the 146 // If the callback is triggering when this is called, block the
129 // destructor of the dying object here by waiting until the callback 147 // destructor of the dying object here by waiting until the callback
130 // is done triggering. 148 // is done triggering.
131 CritScope cs(&crit_); 149 CritScope cs(&crit_);
132 // calling_thread_ == NULL means do not trigger the callback. 150 // calling_thread_ == NULL means do not trigger the callback.
133 calling_thread_ = NULL; 151 calling_thread_ = NULL;
134 } 152 }
135 153
136 } // namespace rtc 154 } // namespace rtc
OLDNEW
« no previous file with comments | « webrtc/base/asyncinvoker.h ('k') | webrtc/base/asyncinvoker-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698