| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "chrome/browser/cancelable_request.h" | |
| 6 | |
| 7 CancelableRequestProvider::CancelableRequestProvider() | |
| 8 : next_handle_(1) { | |
| 9 } | |
| 10 | |
| 11 CancelableRequestProvider::Handle CancelableRequestProvider::AddRequest( | |
| 12 CancelableRequestBase* request, | |
| 13 CancelableRequestConsumerBase* consumer) { | |
| 14 Handle handle; | |
| 15 { | |
| 16 base::AutoLock lock(pending_request_lock_); | |
| 17 | |
| 18 handle = next_handle_; | |
| 19 pending_requests_[next_handle_] = request; | |
| 20 ++next_handle_; | |
| 21 DCHECK(next_handle_) | |
| 22 << "next_handle_ may have wrapped around to invalid state."; | |
| 23 } | |
| 24 | |
| 25 consumer->OnRequestAdded(this, handle); | |
| 26 | |
| 27 request->Init(this, handle, consumer); | |
| 28 return handle; | |
| 29 } | |
| 30 | |
| 31 void CancelableRequestProvider::CancelRequest(Handle handle) { | |
| 32 base::AutoLock lock(pending_request_lock_); | |
| 33 CancelRequestLocked(pending_requests_.find(handle)); | |
| 34 } | |
| 35 | |
| 36 CancelableRequestProvider::~CancelableRequestProvider() { | |
| 37 // There may be requests whose result callback has not been run yet. We need | |
| 38 // to cancel them otherwise they may try and call us back after we've been | |
| 39 // deleted, or do other bad things. This can occur on shutdown (or browser | |
| 40 // context destruction) when a request is scheduled, completed (but not | |
| 41 // dispatched), then the BrowserContext is deleted. | |
| 42 base::AutoLock lock(pending_request_lock_); | |
| 43 while (!pending_requests_.empty()) | |
| 44 CancelRequestLocked(pending_requests_.begin()); | |
| 45 } | |
| 46 | |
| 47 void CancelableRequestProvider::CancelRequestLocked( | |
| 48 const CancelableRequestMap::iterator& item) { | |
| 49 pending_request_lock_.AssertAcquired(); | |
| 50 if (item == pending_requests_.end()) { | |
| 51 NOTREACHED() << "Trying to cancel an unknown request"; | |
| 52 return; | |
| 53 } | |
| 54 | |
| 55 item->second->consumer()->OnRequestRemoved(this, item->first); | |
| 56 item->second->set_canceled(); | |
| 57 pending_requests_.erase(item); | |
| 58 } | |
| 59 | |
| 60 void CancelableRequestProvider::RequestCompleted(Handle handle) { | |
| 61 CancelableRequestConsumerBase* consumer = NULL; | |
| 62 { | |
| 63 base::AutoLock lock(pending_request_lock_); | |
| 64 | |
| 65 CancelableRequestMap::iterator i = pending_requests_.find(handle); | |
| 66 if (i == pending_requests_.end()) { | |
| 67 NOTREACHED() << "Trying to cancel an unknown request"; | |
| 68 return; | |
| 69 } | |
| 70 consumer = i->second->consumer(); | |
| 71 | |
| 72 // This message should only get sent if the class is not cancelled, or | |
| 73 // else the consumer might be gone). | |
| 74 DCHECK(!i->second->canceled()); | |
| 75 | |
| 76 pending_requests_.erase(i); | |
| 77 } | |
| 78 | |
| 79 // Notify the consumer that the request is gone | |
| 80 consumer->OnRequestRemoved(this, handle); | |
| 81 } | |
| 82 | |
| 83 // MSVC doesn't like complex extern templates and DLLs. | |
| 84 #if !defined(COMPILER_MSVC) | |
| 85 // Emit our most common CancelableRequestConsumer. | |
| 86 template class CancelableRequestConsumerTSimple<int>; | |
| 87 | |
| 88 // And the most common subclass of it. | |
| 89 template class CancelableRequestConsumerT<int, 0>; | |
| 90 #endif | |
| 91 | |
| 92 CancelableRequestBase::CancelableRequestBase() | |
| 93 : provider_(NULL), | |
| 94 consumer_(NULL), | |
| 95 handle_(0) { | |
| 96 callback_thread_ = MessageLoop::current(); | |
| 97 } | |
| 98 | |
| 99 CancelableRequestBase::~CancelableRequestBase() { | |
| 100 } | |
| 101 | |
| 102 void CancelableRequestBase::Init(CancelableRequestProvider* provider, | |
| 103 CancelableRequestProvider::Handle handle, | |
| 104 CancelableRequestConsumerBase* consumer) { | |
| 105 DCHECK(handle_ == 0 && provider_ == NULL && consumer_ == NULL); | |
| 106 provider_ = provider; | |
| 107 consumer_ = consumer; | |
| 108 handle_ = handle; | |
| 109 } | |
| 110 | |
| 111 void CancelableRequestBase::DoForward(const base::Closure& forwarded_call, | |
| 112 bool force_async) { | |
| 113 if (force_async || callback_thread_ != MessageLoop::current()) { | |
| 114 callback_thread_->PostTask( | |
| 115 FROM_HERE, | |
| 116 base::Bind(&CancelableRequestBase::ExecuteCallback, this, | |
| 117 forwarded_call)); | |
| 118 } else { | |
| 119 // We can do synchronous callbacks when we're on the same thread. | |
| 120 ExecuteCallback(forwarded_call); | |
| 121 } | |
| 122 } | |
| 123 | |
| 124 void CancelableRequestBase::ExecuteCallback( | |
| 125 const base::Closure& forwarded_call) { | |
| 126 DCHECK_EQ(callback_thread_, MessageLoop::current()); | |
| 127 | |
| 128 if (!canceled_.IsSet()) { | |
| 129 WillExecute(); | |
| 130 | |
| 131 // Execute the callback. | |
| 132 forwarded_call.Run(); | |
| 133 } | |
| 134 | |
| 135 // Notify the provider that the request is complete. The provider will | |
| 136 // notify the consumer for us. Note that it is possible for the callback to | |
| 137 // cancel this request; we must check canceled again. | |
| 138 if (!canceled_.IsSet()) | |
| 139 NotifyCompleted(); | |
| 140 } | |
| OLD | NEW |