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

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

Issue 2571923002: Fix threading issues in WebDataRequestManager. (Closed)
Patch Set: 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, 21 WebDataRequest::WebDataRequest(WebDataServiceConsumer* consumer,
22 WebDataRequestManager* manager) 22 WebDataRequestManager* manager)
23 : manager_(manager), cancelled_(false), consumer_(consumer) { 23 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
24 handle_ = manager_->GetNextRequestHandle(); 24 handle_(manager->GetNextRequestHandle()),
25 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 25 manager_(manager),
26 consumer_(consumer) {
26 manager_->RegisterRequest(this); 27 manager_->RegisterRequest(this);
27 } 28 }
28 29
29 WebDataRequest::~WebDataRequest() { 30 WebDataRequest::~WebDataRequest() {
30 if (manager_) { 31 if (manager_) {
31 manager_->CancelRequest(handle_); 32 manager_->CancelRequest(handle_);
32 } 33 }
33 } 34 }
34 35
35 WebDataServiceBase::Handle WebDataRequest::GetHandle() const { 36 WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
36 return handle_; 37 return handle_;
37 } 38 }
38 39
40 bool WebDataRequest::IsCancelled() const {
Mathieu 2016/12/14 01:13:46 IsInactive? Could be completed at this point too i
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done. But used IsActive instead, to avoid the doub
41 return manager_ == nullptr;
42 }
43
44 inline void WebDataRequest::AssertThreadSafe() const {
45 // Of manager_ is null then the request has already been cancelled or
Mathieu 2016/12/14 01:13:46 If
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done.
46 // completed, and the asserting context represents and invalid state.
Mathieu 2016/12/14 01:13:46 *an
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Done.
47 DCHECK(manager_);
48
49 // Manipulations of the request state should only happen when the manager's
50 // lock is held (i.e., during request cancellation or completion).
51 manager_->AssertLockedByCurrentThread();
52 }
53
39 WebDataServiceConsumer* WebDataRequest::GetConsumer() const { 54 WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
55 AssertThreadSafe();
40 return consumer_; 56 return consumer_;
41 } 57 }
42 58
43 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() 59 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
44 const { 60 const {
45 return task_runner_; 61 return task_runner_;
46 } 62 }
47 63
48 bool WebDataRequest::IsCancelled() const { 64 void WebDataRequest::MarkAsInactive() {
49 base::AutoLock l(cancel_lock_); 65 AssertThreadSafe();
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this lock isn't useful, it's not protecting agains
50 return cancelled_; 66 consumer_ = nullptr;
51 } 67 manager_ = nullptr;
52
53 void WebDataRequest::Cancel() {
54 base::AutoLock l(cancel_lock_);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this lock isn't useful. This code is called under
55 cancelled_ = true;
56 consumer_ = NULL;
57 manager_ = NULL;
58 }
59
60 void WebDataRequest::OnComplete() {
61 manager_= NULL;
62 } 68 }
63 69
64 void WebDataRequest::SetResult(std::unique_ptr<WDTypedResult> r) { 70 void WebDataRequest::SetResult(std::unique_ptr<WDTypedResult> r) {
71 AssertThreadSafe();
65 result_ = std::move(r); 72 result_ = std::move(r);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this isn't thread safe, could leak r.
66 } 73 }
67 74
68 std::unique_ptr<WDTypedResult> WebDataRequest::GetResult() { 75 std::unique_ptr<WDTypedResult> WebDataRequest::GetResult() {
76 AssertThreadSafe();
69 return std::move(result_); 77 return std::move(result_);
Roger McFarlane (Chromium) 2016/12/13 22:33:55 this isn't thread safe, you could end up with mult
70 } 78 }
71 79
72 //////////////////////////////////////////////////////////////////////////////// 80 ////////////////////////////////////////////////////////////////////////////////
73 // 81 //
74 // WebDataRequestManager implementation. 82 // WebDataRequestManager implementation.
75 // 83 //
76 //////////////////////////////////////////////////////////////////////////////// 84 ////////////////////////////////////////////////////////////////////////////////
77 85
78 WebDataRequestManager::WebDataRequestManager() 86 WebDataRequestManager::WebDataRequestManager()
79 : next_request_handle_(1) { 87 : next_request_handle_(1) {
80 } 88 }
81 89
82 WebDataRequestManager::~WebDataRequestManager() { 90 WebDataRequestManager::~WebDataRequestManager() {
83 base::AutoLock l(pending_lock_); 91 base::AutoLock l(pending_lock_);
84 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) 92 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
85 i->second->Cancel(); 93 i->second->MarkAsInactive();
86 pending_requests_.clear(); 94 pending_requests_.clear();
87 } 95 }
88 96
89 void WebDataRequestManager::RegisterRequest(WebDataRequest* request) { 97 void WebDataRequestManager::RegisterRequest(WebDataRequest* request) {
90 base::AutoLock l(pending_lock_); 98 base::AutoLock l(pending_lock_);
91 pending_requests_[request->GetHandle()] = request; 99 pending_requests_[request->GetHandle()] = request;
92 } 100 }
93 101
94 int WebDataRequestManager::GetNextRequestHandle() { 102 int WebDataRequestManager::GetNextRequestHandle() {
95 base::AutoLock l(pending_lock_); 103 base::AutoLock l(pending_lock_);
96 return ++next_request_handle_; 104 return ++next_request_handle_;
Roger McFarlane (Chromium) 2016/12/13 22:33:55 Maybe make this an atomic type? As is, we take pe
Roger McFarlane (Chromium) 2016/12/14 19:05:53 added factory func.
97 } 105 }
98 106
99 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) { 107 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
100 base::AutoLock l(pending_lock_); 108 base::AutoLock l(pending_lock_);
109 // If the request was already cancelled, or has already completed, it won't
110 // be in the pending_requests_ collection any more.
101 auto i = pending_requests_.find(h); 111 auto i = pending_requests_.find(h);
102 DCHECK(i != pending_requests_.end()); 112 if (i == pending_requests_.end())
Roger McFarlane (Chromium) 2016/12/13 22:33:55 This DCHECK isn't valid. Given concurrent cancell
103 i->second->Cancel(); 113 return;
114 i->second->MarkAsInactive();
104 pending_requests_.erase(i); 115 pending_requests_.erase(i);
105 } 116 }
106 117
107 void WebDataRequestManager::RequestCompleted( 118 void WebDataRequestManager::RequestCompleted(
108 std::unique_ptr<WebDataRequest> request) { 119 std::unique_ptr<WebDataRequest> request,
109 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 120 std::unique_ptr<WDTypedResult> result) {
110 request->GetTaskRunner(); 121 // Transfer ownership of the result to the request.
111 task_runner->PostTask( 122 {
123 base::AutoLock l(pending_lock_);
124 request->SetResult(std::move(result));
Avi (use Gerrit) 2016/12/14 04:40:39 If we no longer have the WebDatabaseBackend call S
Roger McFarlane (Chromium) 2016/12/14 14:02:49 Ah, yes... should have made that private. But pass
125 }
126 request->GetTaskRunner()->PostTask(
112 FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread, 127 FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread,
113 this, base::Passed(&request))); 128 this, base::Passed(&request)));
114 } 129 }
115 130
116 void WebDataRequestManager::RequestCompletedOnThread( 131 void WebDataRequestManager::RequestCompletedOnThread(
117 std::unique_ptr<WebDataRequest> request) { 132 std::unique_ptr<WebDataRequest> request) {
133 // Early exit if the request is cancelled.
118 if (request->IsCancelled()) 134 if (request->IsCancelled())
Roger McFarlane (Chromium) 2016/12/13 22:33:55 An optimization, to attempt to avoid contending fo
Mathieu 2016/12/14 01:13:46 This would be a worthwhile comment for a reader th
Roger McFarlane (Chromium) 2016/12/14 14:02:49 This is the double-checked locking pattern. I'll a
119 return; 135 return;
120 136
121 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 137 // Placeholders for the request consumer, handle and result... to be used
122 // fixed. 138 // when notifying the consumer that the request has completed.
123 tracked_objects::ScopedTracker tracking_profile1( 139 WebDataServiceConsumer* consumer = nullptr;
124 FROM_HERE_WITH_EXPLICIT_FUNCTION( 140 std::unique_ptr<WDTypedResult> result;
125 "422460 WebDataRequestManager::RequestCompletedOnThread::UpdateMap")); 141
142 // Manipulate the pending_requests_ collection while holding the lock.
126 { 143 {
127 base::AutoLock l(pending_lock_); 144 base::AutoLock l(pending_lock_);
145
146 // Re-check if the request was cancelled. It might have been cancelled in
147 // another thread before the lock was acquired.
148 if (request->IsCancelled())
149 return;
150
151 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
152 // is fixed.
153 tracked_objects::ScopedTracker tracking_profile1(
154 FROM_HERE_WITH_EXPLICIT_FUNCTION(
155 "422460 "
156 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
157
128 auto i = pending_requests_.find(request->GetHandle()); 158 auto i = pending_requests_.find(request->GetHandle());
129 DCHECK(i != pending_requests_.end()); 159 DCHECK(i != pending_requests_.end());
Roger McFarlane (Chromium) 2016/12/13 22:33:55 This DCHECK isn't valid. Given concurrent cancell
Mathieu 2016/12/14 01:13:46 It's still in your change, should we remove it?
Roger McFarlane (Chromium) 2016/12/14 14:02:49 It should be valid now, since we re-check while ho
130 160
131 // Take ownership of the request object and remove it from the map. 161 // Take ownership of the request object and remove it from the map.
132 pending_requests_.erase(i); 162 pending_requests_.erase(i);
163
164 // Remember the consumer and result for notification below.
165 consumer = request->GetConsumer();
166 result = request->GetResult();
167
168 // The request is no longer active.
169 request->MarkAsInactive();
133 } 170 }
134 171
135 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 172 // Notify the consumer if needed.
136 // fixed. 173 //
137 tracked_objects::ScopedTracker tracking_profile2( 174 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
138 FROM_HERE_WITH_EXPLICIT_FUNCTION( 175 // be appropriately thread safe.
139 "422460 " 176 if (consumer) {
140 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer")); 177 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
178 // is fixed.
179 tracked_objects::ScopedTracker tracking_profile2(
180 FROM_HERE_WITH_EXPLICIT_FUNCTION(
181 "422460 "
182 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
141 183
142 // Notify the consumer if needed. 184 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
143 if (!request->IsCancelled()) { 185 std::move(result));
144 WebDataServiceConsumer* consumer = request->GetConsumer();
145 request->OnComplete();
146 if (consumer) {
147 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
148 request->GetResult());
149 }
150 } 186 }
151
152 } 187 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698