blob: a57eb7b962d26ac00ab96ecc88a8359ee4b2a114 [file] [log] [blame]
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +00001/*
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
30namespace talk_base {
31
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000032AsyncInvoker::AsyncInvoker() : destroying_(false) {}
33
34AsyncInvoker::~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
41void 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
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000053void AsyncInvoker::Flush(Thread* thread, uint32 id /*= MQID_ANY*/) {
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000054 if (destroying_) return;
55
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000056 // 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
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000062 MessageList removed;
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000063 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);
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000069 }
70}
71
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000072void 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;
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000079 }
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000080 thread->Post(this, id, new ScopedRefMessageData<AsyncClosure>(closure));
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000081}
82
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000083NotifyingAsyncClosureBase::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
92void NotifyingAsyncClosureBase::TriggerCallback() {
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +000093 CritScope cs(&crit_);
henrike@webrtc.org54caffd2014-02-14 23:38:45 +000094 if (!CallbackCanceled() && !callback_.empty()) {
95 invoker_->AsyncInvoke<void>(calling_thread_, callback_);
96 }
97}
98
99void 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;
sergeyu@chromium.org70022fa2014-02-07 19:03:26 +0000106}
107
108} // namespace talk_base