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.
5 #include "chrome/browser/common/cancelable_request.h"
7 CancelableRequestProvider::CancelableRequestProvider()
11 CancelableRequestProvider::Handle
CancelableRequestProvider::AddRequest(
12 CancelableRequestBase
* request
,
13 CancelableRequestConsumerBase
* consumer
) {
16 base::AutoLock
lock(pending_request_lock_
);
18 handle
= next_handle_
;
19 pending_requests_
[next_handle_
] = request
;
22 << "next_handle_ may have wrapped around to invalid state.";
25 consumer
->OnRequestAdded(this, handle
);
27 request
->Init(this, handle
, consumer
);
31 void CancelableRequestProvider::CancelRequest(Handle handle
) {
32 base::AutoLock
lock(pending_request_lock_
);
33 CancelRequestLocked(pending_requests_
.find(handle
));
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());
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";
55 item
->second
->consumer()->OnRequestRemoved(this, item
->first
);
56 item
->second
->set_canceled();
57 pending_requests_
.erase(item
);
60 void CancelableRequestProvider::RequestCompleted(Handle handle
) {
61 CancelableRequestConsumerBase
* consumer
= NULL
;
63 base::AutoLock
lock(pending_request_lock_
);
65 CancelableRequestMap::iterator i
= pending_requests_
.find(handle
);
66 if (i
== pending_requests_
.end()) {
67 NOTREACHED() << "Trying to cancel an unknown request";
70 consumer
= i
->second
->consumer();
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());
76 pending_requests_
.erase(i
);
79 // Notify the consumer that the request is gone
80 consumer
->OnRequestRemoved(this, handle
);
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>;
88 // And the most common subclass of it.
89 template class CancelableRequestConsumerT
<int, 0>;
92 CancelableRequestBase::CancelableRequestBase()
96 callback_thread_
= base::MessageLoop::current();
99 CancelableRequestBase::~CancelableRequestBase() {
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
;
111 void CancelableRequestBase::DoForward(const base::Closure
& forwarded_call
,
113 if (force_async
|| callback_thread_
!= base::MessageLoop::current()) {
114 callback_thread_
->PostTask(
116 base::Bind(&CancelableRequestBase::ExecuteCallback
, this,
119 // We can do synchronous callbacks when we're on the same thread.
120 ExecuteCallback(forwarded_call
);
124 void CancelableRequestBase::ExecuteCallback(
125 const base::Closure
& forwarded_call
) {
126 DCHECK_EQ(callback_thread_
, base::MessageLoop::current());
128 if (!canceled_
.IsSet()) {
131 // Execute the callback.
132 forwarded_call
.Run();
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())