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

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

Issue 2571923002: Fix threading issues in WebDataRequestManager. (Closed)
Patch Set: Simplify handling of result and add request factory func 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(WebDataRequestManager* manager,
Peter Kasting 2016/12/15 01:05:34 Nit: While here, maybe fix function definition ord
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
22 WebDataRequestManager* manager) 22 WebDataServiceConsumer* consumer)
23 : manager_(manager), cancelled_(false), consumer_(consumer) { 23 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
24 handle_ = manager_->GetNextRequestHandle(); 24 manager_(manager),
25 task_runner_ = base::ThreadTaskRunnerHandle::Get(); 25 consumer_(consumer),
26 manager_->RegisterRequest(this); 26 handle_(0) {
27 DCHECK(manager_ != nullptr);
Peter Kasting 2016/12/15 01:05:34 Nit: DCHECK(IsActive())?
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
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::IsActive() const {
41 return manager_ != nullptr;
42 }
43
44 inline void WebDataRequest::AssertThreadSafe() const {
Peter Kasting 2016/12/15 01:05:34 Nit: Remove "inline" (doesn't match class declarat
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
45 // Manipulations of the request state should only happen when the request is
46 // active (i.e., the manager is non-null) and the manager's lock is held
Peter Kasting 2016/12/15 01:05:34 Nit: Remove "(i.e., the manager is non-null)" and
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
47 // (i.e., during request cancellation or completion).
48 DCHECK(manager_ != nullptr);
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
82 WebDataRequestManager::~WebDataRequestManager() { 78 WebDataRequestManager::~WebDataRequestManager() {
83 base::AutoLock l(pending_lock_); 79 base::AutoLock l(pending_lock_);
84 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) 80 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
85 i->second->Cancel(); 81 i->second->MarkAsInactive();
86 pending_requests_.clear(); 82 pending_requests_.clear();
87 } 83 }
88 84
89 void WebDataRequestManager::RegisterRequest(WebDataRequest* request) { 85 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
86 WebDataServiceConsumer* consumer) {
87 std::unique_ptr<WebDataRequest> request(new WebDataRequest(this, consumer));
88
89 // Grab the lock to get the next request handle and register the request.
90 base::AutoLock l(pending_lock_); 90 base::AutoLock l(pending_lock_);
91 pending_requests_[request->GetHandle()] = request; 91 request->handle_ = ++next_request_handle_;
Peter Kasting 2016/12/15 01:05:34 Nit: I think this should be next_request_handle_++
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
92 } 92 pending_requests_[request->handle_] = request.get();
93 93
94 int WebDataRequestManager::GetNextRequestHandle() { 94 return request;
95 base::AutoLock l(pending_lock_);
96 return ++next_request_handle_;
97 } 95 }
98 96
99 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) { 97 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
100 base::AutoLock l(pending_lock_); 98 base::AutoLock l(pending_lock_);
99 // If the request was already cancelled, or has already completed, it won't
100 // be in the pending_requests_ collection any more.
101 auto i = pending_requests_.find(h); 101 auto i = pending_requests_.find(h);
102 DCHECK(i != pending_requests_.end()); 102 if (i == pending_requests_.end())
103 i->second->Cancel(); 103 return;
104 i->second->MarkAsInactive();
104 pending_requests_.erase(i); 105 pending_requests_.erase(i);
105 } 106 }
106 107
107 void WebDataRequestManager::RequestCompleted( 108 void WebDataRequestManager::RequestCompleted(
108 std::unique_ptr<WebDataRequest> request) { 109 std::unique_ptr<WebDataRequest> request,
110 std::unique_ptr<WDTypedResult> result) {
109 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 111 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
110 request->GetTaskRunner(); 112 request->GetTaskRunner();
111 task_runner->PostTask( 113 task_runner->PostTask(
112 FROM_HERE, base::Bind(&WebDataRequestManager::RequestCompletedOnThread, 114 FROM_HERE,
113 this, base::Passed(&request))); 115 base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this,
116 base::Passed(&request), base::Passed(&result)));
114 } 117 }
115 118
116 void WebDataRequestManager::RequestCompletedOnThread( 119 void WebDataRequestManager::RequestCompletedOnThread(
117 std::unique_ptr<WebDataRequest> request) { 120 std::unique_ptr<WebDataRequest> request,
118 if (request->IsCancelled()) 121 std::unique_ptr<WDTypedResult> result) {
122 // If the request is already inactive, early exit to avoid contending for the
123 // lock (aka, the double checked locking pattern).
124 if (!request->IsActive())
119 return; 125 return;
120 126
121 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 127 // Placeholders for the request consumer, handle and result... to be used
Peter Kasting 2016/12/15 01:05:34 Nit: Comment seems inaccurate? I don't see the ot
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Oops, out of date comment. I'd prefer to leave a
122 // fixed. 128 // when notifying the consumer that the request has completed.
123 tracked_objects::ScopedTracker tracking_profile1( 129 WebDataServiceConsumer* consumer = nullptr;
124 FROM_HERE_WITH_EXPLICIT_FUNCTION( 130
125 "422460 WebDataRequestManager::RequestCompletedOnThread::UpdateMap")); 131 // Manipulate the pending_requests_ collection while holding the lock.
126 { 132 {
127 base::AutoLock l(pending_lock_); 133 base::AutoLock l(pending_lock_);
134
135 // Re-check whether the request is active. It might have been cancelled in
136 // another thread before the lock was acquired.
137 if (!request->IsActive())
138 return;
139
140 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
141 // is fixed.
142 tracked_objects::ScopedTracker tracking_profile1(
Peter Kasting 2016/12/15 01:05:34 Nit: Rename this variable and the one below to no
Roger McFarlane (Chromium) 2016/12/15 07:41:45 Done.
143 FROM_HERE_WITH_EXPLICIT_FUNCTION(
144 "422460 "
145 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
146
128 auto i = pending_requests_.find(request->GetHandle()); 147 auto i = pending_requests_.find(request->GetHandle());
129 DCHECK(i != pending_requests_.end()); 148 DCHECK(i != pending_requests_.end());
130 149
131 // Take ownership of the request object and remove it from the map. 150 // Take ownership of the request object and remove it from the map.
132 pending_requests_.erase(i); 151 pending_requests_.erase(i);
152
153 // Remember the consumer and result for notification below.
154 consumer = request->GetConsumer();
155
156 // The request is no longer active.
157 request->MarkAsInactive();
133 } 158 }
134 159
135 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 is 160 // Notify the consumer if needed.
136 // fixed. 161 //
137 tracked_objects::ScopedTracker tracking_profile2( 162 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
138 FROM_HERE_WITH_EXPLICIT_FUNCTION( 163 // be appropriately thread safe.
139 "422460 " 164 if (consumer) {
140 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer")); 165 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
166 // is fixed.
167 tracked_objects::ScopedTracker tracking_profile2(
168 FROM_HERE_WITH_EXPLICIT_FUNCTION(
169 "422460 "
170 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
141 171
142 // Notify the consumer if needed. 172 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
143 if (!request->IsCancelled()) { 173 std::move(result));
144 WebDataServiceConsumer* consumer = request->GetConsumer();
145 request->OnComplete();
146 if (consumer) {
147 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
148 request->GetResult());
149 }
150 } 174 }
151
152 } 175 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698