1 /*
2 * libjingle
3 * Copyright 2014 Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "talk/base/asyncinvoker.h"
29
30 namespace talk_base {
31
AsyncInvoker()32 AsyncInvoker::AsyncInvoker() : destroying_(false) {}
33
~AsyncInvoker()34 AsyncInvoker::~AsyncInvoker() {
35 destroying_ = true;
36 SignalInvokerDestroyed();
37 // Messages for this need to be cleared *before* our destructor is complete.
38 MessageQueueManager::Clear(this);
39 }
40
OnMessage(Message * msg)41 void AsyncInvoker::OnMessage(Message* msg) {
42 // Get the AsyncClosure shared ptr from this message's data.
43 ScopedRefMessageData<AsyncClosure>* data =
44 static_cast<ScopedRefMessageData<AsyncClosure>*>(msg->pdata);
45 scoped_refptr<AsyncClosure> closure = data->data();
46 delete msg->pdata;
47 msg->pdata = NULL;
48
49 // Execute the closure and trigger the return message if needed.
50 closure->Execute();
51 }
52
Flush(Thread * thread,uint32 id)53 void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
54 if (destroying_) return;
55
56 // Run this on |thread| to reduce the number of context switches.
57 if (Thread::Current() != thread) {
58 thread->Invoke<void>(Bind(&AsyncInvoker::Flush, this, thread, id));
59 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.
66 thread->Send(it->phandler,
67 it->message_id,
68 it->pdata);
69 }
70 }
71
DoInvoke(Thread * thread,AsyncClosure * closure,uint32 id)72 void AsyncInvoker::DoInvoke(Thread* thread, AsyncClosure* closure,
73 uint32 id) {
74 if (destroying_) {
75 LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
76 // Since this call transwers ownership of |closure|, we clean it up here.
77 delete closure;
78 return;
79 }
80 thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
81 }
82
NotifyingAsyncClosureBase(AsyncInvoker * invoker,Thread * calling_thread)83 NotifyingAsyncClosureBase::NotifyingAsyncClosureBase(AsyncInvoker* invoker,
84 Thread* calling_thread)
85 : invoker_(invoker), calling_thread_(calling_thread) {
86 calling_thread->SignalQueueDestroyed.connect(
87 this, &NotifyingAsyncClosureBase::CancelCallback);
88 invoker->SignalInvokerDestroyed.connect(
89 this, &NotifyingAsyncClosureBase::CancelCallback);
90 }
91
TriggerCallback()92 void NotifyingAsyncClosureBase::TriggerCallback() {
93 CritScope cs(&crit_);
94 if (!CallbackCanceled() && !callback_.empty()) {
95 invoker_->AsyncInvoke<void>(calling_thread_, callback_);
96 }
97 }
98
CancelCallback()99 void NotifyingAsyncClosureBase::CancelCallback() {
100 // If the callback is triggering when this is called, block the
101 // destructor of the dying object here by waiting until the callback
102 // is done triggering.
103 CritScope cs(&crit_);
104 // calling_thread_ == NULL means do not trigger the callback.
105 calling_thread_ = NULL;
106 }
107
108 } // namespace talk_base
109