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/common/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_ = base::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_ != base::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_, base::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 } 141