Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: components/webdata/common/web_data_request_manager.cc

Issue 2571923002: Fix threading issues in WebDataRequestManager. (Closed)
Patch Set: address pkasting's comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/webdata/common/web_data_request_manager.h" 5 #include "components/webdata/common/web_data_request_manager.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/profiler/scoped_tracker.h" 11 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h" 12 #include "base/stl_util.h"
13 #include "base/threading/thread_task_runner_handle.h" 13 #include "base/threading/thread_task_runner_handle.h"
14 14
15 //////////////////////////////////////////////////////////////////////////////// 15 ////////////////////////////////////////////////////////////////////////////////
16 // 16 //
17 // WebDataRequest implementation. 17 // WebDataRequest implementation.
18 // 18 //
19 //////////////////////////////////////////////////////////////////////////////// 19 ////////////////////////////////////////////////////////////////////////////////
20 20
21 WebDataRequest::WebDataRequest(WebDataServiceConsumer* consumer,
22 WebDataRequestManager* manager)
23 : manager_(manager), cancelled_(false), consumer_(consumer) {
24 handle_ = manager_->GetNextRequestHandle();
25 task_runner_ = base::ThreadTaskRunnerHandle::Get();
26 manager_->RegisterRequest(this);
27 }
28
29 WebDataRequest::~WebDataRequest() { 21 WebDataRequest::~WebDataRequest() {
30 if (manager_) { 22 if (IsActive()) {
31 manager_->CancelRequest(handle_); 23 manager_->CancelRequest(handle_);
32 } 24 }
33 } 25 }
34 26
35 WebDataServiceBase::Handle WebDataRequest::GetHandle() const { 27 WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
36 return handle_; 28 return handle_;
37 } 29 }
38 30
31 bool WebDataRequest::IsActive() const {
32 return manager_ != nullptr;
33 }
34
35 WebDataRequest::WebDataRequest(WebDataRequestManager* manager,
36 WebDataServiceConsumer* consumer)
37 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
38 manager_(manager),
39 consumer_(consumer),
40 handle_(0) {
41 DCHECK(IsActive());
42 }
43
44 void WebDataRequest::AssertThreadSafe() const {
45 // Manipulations of the request state should only happen when the request is
46 // active and the manager's lock is held (i.e., during request cancellation
47 // or completion).
48 DCHECK(IsActive());
49 manager_->AssertLockedByCurrentThread();
50 }
51
39 WebDataServiceConsumer* WebDataRequest::GetConsumer() const { 52 WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
53 AssertThreadSafe();
40 return consumer_; 54 return consumer_;
41 } 55 }
42 56
43 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() 57 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
44 const { 58 const {
45 return task_runner_; 59 return task_runner_;
46 } 60 }
47 61
48 bool WebDataRequest::IsCancelled() const { 62 void WebDataRequest::MarkAsInactive() {
49 base::AutoLock l(cancel_lock_); 63 AssertThreadSafe();
50 return cancelled_; 64 consumer_ = nullptr;
51 } 65 manager_ = nullptr;
52
53 void WebDataRequest::Cancel() {
54 base::AutoLock l(cancel_lock_);
55 cancelled_ = true;
56 consumer_ = NULL;
57 manager_ = NULL;
58 }
59
60 void WebDataRequest::OnComplete() {
61 manager_= NULL;
62 }
63
64 void WebDataRequest::SetResult(std::unique_ptr<WDTypedResult> r) {
65 result_ = std::move(r);
66 }
67
68 std::unique_ptr<WDTypedResult> WebDataRequest::GetResult() {
69 return std::move(result_);
70 } 66 }
71 67
72 //////////////////////////////////////////////////////////////////////////////// 68 ////////////////////////////////////////////////////////////////////////////////
73 // 69 //
74 // WebDataRequestManager implementation. 70 // WebDataRequestManager implementation.
75 // 71 //
76 //////////////////////////////////////////////////////////////////////////////// 72 ////////////////////////////////////////////////////////////////////////////////
77 73
78 WebDataRequestManager::WebDataRequestManager() 74 WebDataRequestManager::WebDataRequestManager()
79 : next_request_handle_(1) { 75 : next_request_handle_(1) {
80 } 76 }
81 77
78 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
79 WebDataServiceConsumer* consumer) {
80 std::unique_ptr<WebDataRequest> request(new WebDataRequest(this, consumer));
81
82 // Grab the lock to get the next request handle and register the request.
83 base::AutoLock l(pending_lock_);
84 request->handle_ = next_request_handle_++;
85 pending_requests_[request->handle_] = request.get();
86
87 return request;
88 }
89
90 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
91 base::AutoLock l(pending_lock_);
92 // If the request was already cancelled, or has already completed, it won't
93 // be in the pending_requests_ collection any more.
94 auto i = pending_requests_.find(h);
95 if (i == pending_requests_.end())
96 return;
97 i->second->MarkAsInactive();
98 pending_requests_.erase(i);
99 }
100
101 void WebDataRequestManager::RequestCompleted(
102 std::unique_ptr<WebDataRequest> request,
103 std::unique_ptr<WDTypedResult> result) {
104 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
105 request->GetTaskRunner();
106 task_runner->PostTask(
107 FROM_HERE,
108 base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this,
109 base::Passed(&request), base::Passed(&result)));
110 }
111
112 void WebDataRequestManager::AssertLockedByCurrentThread() const {
113 pending_lock_.AssertAcquired();
114 }
115
82 WebDataRequestManager::~WebDataRequestManager() { 116 WebDataRequestManager::~WebDataRequestManager() {
83 base::AutoLock l(pending_lock_); 117 base::AutoLock l(pending_lock_);
84 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) 118 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
85 i->second->Cancel(); 119 i->second->MarkAsInactive();
86 pending_requests_.clear(); 120 pending_requests_.clear();
87 } 121 }
88 122
89 void WebDataRequestManager::RegisterRequest(WebDataRequest* request) {
90 base::AutoLock l(pending_lock_);
91 pending_requests_[request->GetHandle()] = request;
92 }
93
94 int WebDataRequestManager::GetNextRequestHandle() {
95 base::AutoLock l(pending_lock_);
96 return ++next_request_handle_;
97 }
98
99 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
100 base::AutoLock l(pending_lock_);
101 auto i = pending_requests_.find(h);
102 DCHECK(i != pending_requests_.end());
103 i->second->Cancel();
104 pending_requests_.erase(i);
105 }
106
107 void WebDataRequestManager::RequestCompleted(
108 std::unique_ptr<WebDataRequest> request) {
109 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
110 request->GetTaskRunner();
111 task_runner->PostTask(
112 FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread,
113 this, base::Passed(&request)));
114 }
115
116 void WebDataRequestManager::RequestCompletedOnThread( 123 void WebDataRequestManager::RequestCompletedOnThread(
117 std::unique_ptr<WebDataRequest> request) { 124 std::unique_ptr<WebDataRequest> request,
118 if (request->IsCancelled()) 125 std::unique_ptr<WDTypedResult> result) {
126 // If the request is already inactive, early exit to avoid contending for the
127 // lock (aka, the double checked locking pattern).
128 if (!request->IsActive())
119 return; 129 return;
120 130
121 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 131 // Used to export the consumer from the locked region below so that consumer
Peter Kasting 2016/12/15 07:50:17 Yeah, this comment seems fine. Nit: I'd say "so t
Roger McFarlane (Chromium) 2016/12/15 16:30:47 Done.
122 // fixed. 132 // can be notified outside of the lock and after the request has been marked
123 tracked_objects::ScopedTracker tracking_profile1( 133 // as inactive.
124 FROM_HERE_WITH_EXPLICIT_FUNCTION( 134 WebDataServiceConsumer* consumer;
125 "422460 WebDataRequestManager::RequestCompletedOnThread::UpdateMap")); 135
136 // Manipulate the pending_requests_ collection while holding the lock.
126 { 137 {
127 base::AutoLock l(pending_lock_); 138 base::AutoLock l(pending_lock_);
139
140 // Re-check whether the request is active. It might have been cancelled in
141 // another thread before the lock was acquired.
142 if (!request->IsActive())
143 return;
144
145 // Remember the consumer for notification below.
146 consumer = request->GetConsumer();
147
148 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
149 // is fixed.
150 tracked_objects::ScopedTracker tracking_profile(
151 FROM_HERE_WITH_EXPLICIT_FUNCTION(
152 "422460 "
153 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
154
128 auto i = pending_requests_.find(request->GetHandle()); 155 auto i = pending_requests_.find(request->GetHandle());
129 DCHECK(i != pending_requests_.end()); 156 DCHECK(i != pending_requests_.end());
130 157
131 // Take ownership of the request object and remove it from the map. 158 // Take ownership of the request object and remove it from the map.
132 pending_requests_.erase(i); 159 pending_requests_.erase(i);
160
161 // The request is no longer active.
162 request->MarkAsInactive();
133 } 163 }
134 164
135 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 165 // Notify the consumer if needed.
136 // fixed. 166 //
137 tracked_objects::ScopedTracker tracking_profile2( 167 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
138 FROM_HERE_WITH_EXPLICIT_FUNCTION( 168 // be appropriately thread safe.
139 "422460 " 169 if (consumer) {
140 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer")); 170 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
171 // is fixed.
172 tracked_objects::ScopedTracker tracking_profile(
173 FROM_HERE_WITH_EXPLICIT_FUNCTION(
174 "422460 "
175 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
141 176
142 // Notify the consumer if needed. 177 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
143 if (!request->IsCancelled()) { 178 std::move(result));
144 WebDataServiceConsumer* consumer = request->GetConsumer();
145 request->OnComplete();
146 if (consumer) {
147 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
148 request->GetResult());
149 }
150 } 179 }
151
152 } 180 }
OLDNEW
« no previous file with comments | « components/webdata/common/web_data_request_manager.h ('k') | components/webdata/common/web_database_backend.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698