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

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

Issue 2845753002: Remove data race in WebDataRequest::CancelRequest. (Closed)
Patch Set: use atomic ops Created 3 years, 7 months 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() { 21 WebDataRequest::~WebDataRequest() {
22 if (IsActive()) { 22 WebDataRequestManager* manager = GetManager();
23 manager_->CancelRequest(handle_); 23 if (manager)
24 } 24 manager->CancelRequest(handle_);
25 } 25 }
26 26
27 WebDataServiceBase::Handle WebDataRequest::GetHandle() const { 27 WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
28 return handle_; 28 return handle_;
29 } 29 }
30 30
31 bool WebDataRequest::IsActive() const { 31 bool WebDataRequest::IsActive() const {
32 return manager_ != nullptr; 32 return GetManager() != nullptr;
33 } 33 }
34 34
35 WebDataRequest::WebDataRequest(WebDataRequestManager* manager, 35 WebDataRequest::WebDataRequest(WebDataRequestManager* manager,
36 WebDataServiceConsumer* consumer) 36 WebDataServiceConsumer* consumer,
37 WebDataServiceBase::Handle handle)
37 : task_runner_(base::ThreadTaskRunnerHandle::Get()), 38 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
38 manager_(manager), 39 atomic_manager_(reinterpret_cast<base::subtle::AtomicWord>(manager)),
39 consumer_(consumer), 40 consumer_(consumer),
40 handle_(0) { 41 handle_(handle) {
42 DCHECK(task_runner_);
41 DCHECK(IsActive()); 43 DCHECK(IsActive());
42 } 44 }
43 45
44 void WebDataRequest::AssertThreadSafe() const { 46 WebDataRequestManager* WebDataRequest::GetManager() const {
45 // Manipulations of the request state should only happen when the request is 47 return reinterpret_cast<WebDataRequestManager*>(
46 // active and the manager's lock is held (i.e., during request cancellation 48 base::subtle::Acquire_Load(&atomic_manager_));
47 // or completion).
48 DCHECK(IsActive());
49 manager_->AssertLockedByCurrentThread();
50 } 49 }
51 50
52 WebDataServiceConsumer* WebDataRequest::GetConsumer() const { 51 WebDataServiceConsumer* WebDataRequest::GetConsumer() const {
53 AssertThreadSafe();
54 return consumer_; 52 return consumer_;
55 } 53 }
56 54
57 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() 55 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner()
58 const { 56 const {
59 return task_runner_; 57 return task_runner_;
60 } 58 }
61 59
62 void WebDataRequest::MarkAsInactive() { 60 void WebDataRequest::MarkAsInactive() {
63 AssertThreadSafe(); 61 // Set atomic_manager_ to the equivalent of nullptr;
64 consumer_ = nullptr; 62 base::subtle::Release_Store(&atomic_manager_, 0);
65 manager_ = nullptr;
66 } 63 }
67 64
68 //////////////////////////////////////////////////////////////////////////////// 65 ////////////////////////////////////////////////////////////////////////////////
69 // 66 //
70 // WebDataRequestManager implementation. 67 // WebDataRequestManager implementation.
71 // 68 //
72 //////////////////////////////////////////////////////////////////////////////// 69 ////////////////////////////////////////////////////////////////////////////////
73 70
74 WebDataRequestManager::WebDataRequestManager() 71 WebDataRequestManager::WebDataRequestManager()
75 : next_request_handle_(1) { 72 : next_request_handle_(1) {
76 } 73 }
77 74
78 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest( 75 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
79 WebDataServiceConsumer* consumer) { 76 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_); 77 base::AutoLock l(pending_lock_);
84 request->handle_ = next_request_handle_++; 78 std::unique_ptr<WebDataRequest> request(
85 pending_requests_[request->handle_] = request.get(); 79 new WebDataRequest(this, consumer, next_request_handle_));
Peter Kasting 2017/04/28 06:36:41 Nit: Prefer = MakeUnique to bare new
Roger McFarlane (Chromium) 2017/04/28 15:06:13 That doesn't play nicely with non-public construct
Peter Kasting 2017/05/04 18:32:25 Mmm. I didn't think through the constructor being
Roger McFarlane (Chromium) 2017/05/05 18:58:49 Acknowledged.
86 80 bool inserted =
81 pending_requests_.emplace(next_request_handle_, request.get()).second;
82 DCHECK(inserted);
83 ++next_request_handle_;
87 return request; 84 return request;
88 } 85 }
89 86
90 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) { 87 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
91 base::AutoLock l(pending_lock_); 88 base::AutoLock l(pending_lock_);
92 // If the request was already cancelled, or has already completed, it won't 89 // If the request was already cancelled, or has already completed, it won't
93 // be in the pending_requests_ collection any more. 90 // be in the pending_requests_ collection any more.
94 auto i = pending_requests_.find(h); 91 auto i = pending_requests_.find(h);
95 if (i == pending_requests_.end()) 92 if (i == pending_requests_.end())
96 return; 93 return;
97 i->second->MarkAsInactive(); 94 i->second->MarkAsInactive();
98 pending_requests_.erase(i); 95 pending_requests_.erase(i);
99 } 96 }
100 97
101 void WebDataRequestManager::RequestCompleted( 98 void WebDataRequestManager::RequestCompleted(
102 std::unique_ptr<WebDataRequest> request, 99 std::unique_ptr<WebDataRequest> request,
103 std::unique_ptr<WDTypedResult> result) { 100 std::unique_ptr<WDTypedResult> result) {
104 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 101 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
105 request->GetTaskRunner(); 102 request->GetTaskRunner();
106 task_runner->PostTask( 103 task_runner->PostTask(
107 FROM_HERE, 104 FROM_HERE,
108 base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this, 105 base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread, this,
109 base::Passed(&request), base::Passed(&result))); 106 base::Passed(&request), base::Passed(&result)));
110 }
111
112 void WebDataRequestManager::AssertLockedByCurrentThread() const {
113 pending_lock_.AssertAcquired();
114 } 107 }
115 108
116 WebDataRequestManager::~WebDataRequestManager() { 109 WebDataRequestManager::~WebDataRequestManager() {
117 base::AutoLock l(pending_lock_); 110 base::AutoLock l(pending_lock_);
118 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) 111 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
119 i->second->MarkAsInactive(); 112 i->second->MarkAsInactive();
120 pending_requests_.clear(); 113 pending_requests_.clear();
121 } 114 }
122 115
123 void WebDataRequestManager::RequestCompletedOnThread( 116 void WebDataRequestManager::RequestCompletedOnThread(
124 std::unique_ptr<WebDataRequest> request, 117 std::unique_ptr<WebDataRequest> request,
125 std::unique_ptr<WDTypedResult> result) { 118 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())
129 return;
130
131 // Used to export the consumer from the locked region below so that the
132 // consumer can be notified outside of the lock and after the request has
133 // been marked as inactive.
134 WebDataServiceConsumer* consumer;
135
136 // Manipulate the pending_requests_ collection while holding the lock. 119 // Manipulate the pending_requests_ collection while holding the lock.
137 { 120 {
138 base::AutoLock l(pending_lock_); 121 base::AutoLock l(pending_lock_);
139 122
140 // Re-check whether the request is active. It might have been cancelled in 123 // Re-check whether the request is active. It might have been cancelled in
141 // another thread before the lock was acquired. 124 // another thread before the lock was acquired.
Peter Kasting 2017/04/28 06:36:41 This comment seems misleading (we're no longer "re
Roger McFarlane (Chromium) 2017/04/28 15:06:13 Done.
142 if (!request->IsActive()) 125 if (!request->IsActive())
143 return; 126 return;
144 127
145 // Remember the consumer for notification below.
146 consumer = request->GetConsumer();
Peter Kasting 2017/04/28 06:36:41 This isn't safe to remove. MarkAsInactive() nukes
Roger McFarlane (Chromium) 2017/04/28 15:06:13 consumer_ doesn't gets nuked anymore (I made it co
147
148 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 128 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
149 // is fixed. 129 // is fixed.
150 tracked_objects::ScopedTracker tracking_profile( 130 tracked_objects::ScopedTracker tracking_profile(
151 FROM_HERE_WITH_EXPLICIT_FUNCTION( 131 FROM_HERE_WITH_EXPLICIT_FUNCTION(
152 "422460 " 132 "422460 "
153 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap")); 133 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
154 134
135 // Remove the request object from the pending_requests_ map. Note that this
136 // method has ownership of the object (it was passed by unique_ptr).
155 auto i = pending_requests_.find(request->GetHandle()); 137 auto i = pending_requests_.find(request->GetHandle());
156 DCHECK(i != pending_requests_.end()); 138 DCHECK(i != pending_requests_.end());
Roger McFarlane (Chromium) 2017/04/27 20:51:44 The code in this block is just CancelRequest() + a
Peter Kasting 2017/04/28 06:36:41 Doing this will require some refactoring given the
Roger McFarlane (Chromium) 2017/04/28 15:06:13 consumer_ no longer gets set to nullptr, only the
Peter Kasting 2017/05/04 18:32:25 In that case, the change you suggest seems like a
Roger McFarlane (Chromium) 2017/05/05 18:58:49 i'll send another CL.
157
158 // Take ownership of the request object and remove it from the map.
159 pending_requests_.erase(i); 139 pending_requests_.erase(i);
160 140
161 // The request is no longer active. 141 // The request is no longer active.
162 request->MarkAsInactive(); 142 request->MarkAsInactive();
163 } 143 }
164 144
165 // Notify the consumer if needed. 145 // Notify the consumer if needed.
166 // 146 //
167 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to 147 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
168 // be appropriately thread safe. 148 // be appropriately thread safe.
149 WebDataServiceConsumer* const consumer = request->GetConsumer();
169 if (consumer) { 150 if (consumer) {
170 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 151 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
171 // is fixed. 152 // is fixed.
172 tracked_objects::ScopedTracker tracking_profile( 153 tracked_objects::ScopedTracker tracking_profile(
173 FROM_HERE_WITH_EXPLICIT_FUNCTION( 154 FROM_HERE_WITH_EXPLICIT_FUNCTION(
174 "422460 " 155 "422460 "
175 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer")); 156 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
176 157
177 consumer->OnWebDataServiceRequestDone(request->GetHandle(), 158 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
178 std::move(result)); 159 std::move(result));
179 } 160 }
180 } 161 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698