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

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

Issue 2845753002: Remove data race in WebDataRequest::CancelRequest. (Closed)
Patch Set: move static_assert 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
« no previous file with comments | « components/webdata/common/web_data_request_manager.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/memory/ptr_util.h"
11 #include "base/profiler/scoped_tracker.h" 12 #include "base/profiler/scoped_tracker.h"
12 #include "base/stl_util.h" 13 #include "base/stl_util.h"
13 #include "base/threading/thread_task_runner_handle.h" 14 #include "base/threading/thread_task_runner_handle.h"
14 15
15 //////////////////////////////////////////////////////////////////////////////// 16 ////////////////////////////////////////////////////////////////////////////////
16 // 17 //
17 // WebDataRequest implementation. 18 // WebDataRequest implementation.
18 // 19 //
19 //////////////////////////////////////////////////////////////////////////////// 20 ////////////////////////////////////////////////////////////////////////////////
20 21
21 WebDataRequest::~WebDataRequest() { 22 WebDataRequest::~WebDataRequest() {
22 if (IsActive()) { 23 WebDataRequestManager* manager = GetManager();
23 manager_->CancelRequest(handle_); 24 if (manager)
24 } 25 manager->CancelRequest(handle_);
25 } 26 }
26 27
27 WebDataServiceBase::Handle WebDataRequest::GetHandle() const { 28 WebDataServiceBase::Handle WebDataRequest::GetHandle() const {
28 return handle_; 29 return handle_;
29 } 30 }
30 31
31 bool WebDataRequest::IsActive() const { 32 bool WebDataRequest::IsActive() {
Peter Kasting 2017/05/04 18:32:25 Losing the "const" here seems sad, but inlining th
Roger McFarlane (Chromium) 2017/05/05 18:58:49 Acknowledged.
32 return manager_ != nullptr; 33 return GetManager() != nullptr;
33 } 34 }
34 35
35 WebDataRequest::WebDataRequest(WebDataRequestManager* manager, 36 WebDataRequest::WebDataRequest(WebDataRequestManager* manager,
36 WebDataServiceConsumer* consumer) 37 WebDataServiceConsumer* consumer,
38 WebDataServiceBase::Handle handle)
37 : task_runner_(base::ThreadTaskRunnerHandle::Get()), 39 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
38 manager_(manager), 40 atomic_manager_(reinterpret_cast<base::subtle::AtomicWord>(manager)),
39 consumer_(consumer), 41 consumer_(consumer),
40 handle_(0) { 42 handle_(handle) {
43 DCHECK(task_runner_);
41 DCHECK(IsActive()); 44 DCHECK(IsActive());
45 static_assert(sizeof(atomic_manager_) == sizeof(manager), "size mismatch");
42 } 46 }
43 47
44 void WebDataRequest::AssertThreadSafe() const { 48 WebDataRequestManager* WebDataRequest::GetManager() {
45 // Manipulations of the request state should only happen when the request is 49 return reinterpret_cast<WebDataRequestManager*>(
46 // active and the manager's lock is held (i.e., during request cancellation 50 base::subtle::Acquire_Load(&atomic_manager_));
47 // or completion).
48 DCHECK(IsActive());
49 manager_->AssertLockedByCurrentThread();
50 } 51 }
51 52
52 WebDataServiceConsumer* WebDataRequest::GetConsumer() const { 53 WebDataServiceConsumer* WebDataRequest::GetConsumer() {
53 AssertThreadSafe();
54 return consumer_; 54 return consumer_;
55 } 55 }
56 56
57 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() 57 scoped_refptr<base::SingleThreadTaskRunner> WebDataRequest::GetTaskRunner() {
58 const {
59 return task_runner_; 58 return task_runner_;
60 } 59 }
61 60
62 void WebDataRequest::MarkAsInactive() { 61 void WebDataRequest::MarkAsInactive() {
63 AssertThreadSafe(); 62 // Set atomic_manager_ to the equivalent of nullptr;
64 consumer_ = nullptr; 63 base::subtle::Release_Store(&atomic_manager_, 0);
65 manager_ = nullptr;
66 } 64 }
67 65
68 //////////////////////////////////////////////////////////////////////////////// 66 ////////////////////////////////////////////////////////////////////////////////
69 // 67 //
70 // WebDataRequestManager implementation. 68 // WebDataRequestManager implementation.
71 // 69 //
72 //////////////////////////////////////////////////////////////////////////////// 70 ////////////////////////////////////////////////////////////////////////////////
73 71
74 WebDataRequestManager::WebDataRequestManager() 72 WebDataRequestManager::WebDataRequestManager()
75 : next_request_handle_(1) { 73 : next_request_handle_(1) {
76 } 74 }
77 75
78 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest( 76 std::unique_ptr<WebDataRequest> WebDataRequestManager::NewRequest(
79 WebDataServiceConsumer* consumer) { 77 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_); 78 base::AutoLock l(pending_lock_);
84 request->handle_ = next_request_handle_++; 79 std::unique_ptr<WebDataRequest> request = base::WrapUnique(
85 pending_requests_[request->handle_] = request.get(); 80 new WebDataRequest(this, consumer, next_request_handle_));
86 81 bool inserted =
82 pending_requests_.emplace(next_request_handle_, request.get()).second;
83 DCHECK(inserted);
84 ++next_request_handle_;
87 return request; 85 return request;
88 } 86 }
89 87
90 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) { 88 void WebDataRequestManager::CancelRequest(WebDataServiceBase::Handle h) {
91 base::AutoLock l(pending_lock_); 89 base::AutoLock l(pending_lock_);
92 // If the request was already cancelled, or has already completed, it won't 90 // If the request was already cancelled, or has already completed, it won't
93 // be in the pending_requests_ collection any more. 91 // be in the pending_requests_ collection any more.
94 auto i = pending_requests_.find(h); 92 auto i = pending_requests_.find(h);
95 if (i == pending_requests_.end()) 93 if (i == pending_requests_.end())
96 return; 94 return;
97 i->second->MarkAsInactive(); 95 i->second->MarkAsInactive();
98 pending_requests_.erase(i); 96 pending_requests_.erase(i);
99 } 97 }
100 98
101 void WebDataRequestManager::RequestCompleted( 99 void WebDataRequestManager::RequestCompleted(
102 std::unique_ptr<WebDataRequest> request, 100 std::unique_ptr<WebDataRequest> request,
103 std::unique_ptr<WDTypedResult> result) { 101 std::unique_ptr<WDTypedResult> result) {
104 scoped_refptr<base::SingleThreadTaskRunner> task_runner = 102 scoped_refptr<base::SingleThreadTaskRunner> task_runner =
105 request->GetTaskRunner(); 103 request->GetTaskRunner();
106 task_runner->PostTask( 104 task_runner->PostTask(
107 FROM_HERE, 105 FROM_HERE,
108 base::Bind(&WebDataRequestManager::RequestCompletedOnThread, this, 106 base::BindOnce(&WebDataRequestManager::RequestCompletedOnThread, this,
109 base::Passed(&request), base::Passed(&result))); 107 base::Passed(&request), base::Passed(&result)));
110 }
111
112 void WebDataRequestManager::AssertLockedByCurrentThread() const {
113 pending_lock_.AssertAcquired();
114 } 108 }
115 109
116 WebDataRequestManager::~WebDataRequestManager() { 110 WebDataRequestManager::~WebDataRequestManager() {
117 base::AutoLock l(pending_lock_); 111 base::AutoLock l(pending_lock_);
118 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i) 112 for (auto i = pending_requests_.begin(); i != pending_requests_.end(); ++i)
119 i->second->MarkAsInactive(); 113 i->second->MarkAsInactive();
120 pending_requests_.clear(); 114 pending_requests_.clear();
121 } 115 }
122 116
123 void WebDataRequestManager::RequestCompletedOnThread( 117 void WebDataRequestManager::RequestCompletedOnThread(
124 std::unique_ptr<WebDataRequest> request, 118 std::unique_ptr<WebDataRequest> request,
125 std::unique_ptr<WDTypedResult> result) { 119 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. 120 // Manipulate the pending_requests_ collection while holding the lock.
137 { 121 {
138 base::AutoLock l(pending_lock_); 122 base::AutoLock l(pending_lock_);
139 123
140 // Re-check whether the request is active. It might have been cancelled in 124 // Check whether the request is active. It might have been cancelled in
141 // another thread before the lock was acquired. 125 // another thread before the lock was acquired.
142 if (!request->IsActive()) 126 if (!request->IsActive())
143 return; 127 return;
144 128
145 // Remember the consumer for notification below.
146 consumer = request->GetConsumer();
147
148 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 129 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
149 // is fixed. 130 // is fixed.
150 tracked_objects::ScopedTracker tracking_profile( 131 tracked_objects::ScopedTracker tracking_profile(
151 FROM_HERE_WITH_EXPLICIT_FUNCTION( 132 FROM_HERE_WITH_EXPLICIT_FUNCTION(
152 "422460 " 133 "422460 "
153 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap")); 134 "WebDataRequestManager::RequestCompletedOnThread::UpdateMap"));
154 135
136 // Remove the request object from the pending_requests_ map. Note that this
137 // method has ownership of the object (it was passed by unique_ptr).
155 auto i = pending_requests_.find(request->GetHandle()); 138 auto i = pending_requests_.find(request->GetHandle());
156 DCHECK(i != pending_requests_.end()); 139 DCHECK(i != pending_requests_.end());
157
158 // Take ownership of the request object and remove it from the map.
159 pending_requests_.erase(i); 140 pending_requests_.erase(i);
160 141
161 // The request is no longer active. 142 // The request is no longer active.
162 request->MarkAsInactive(); 143 request->MarkAsInactive();
163 } 144 }
164 145
165 // Notify the consumer if needed. 146 // Notify the consumer if needed.
166 // 147 //
167 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to 148 // NOTE: The pending_lock_ is no longer held here. It's up to the consumer to
168 // be appropriately thread safe. 149 // be appropriately thread safe.
150 WebDataServiceConsumer* const consumer = request->GetConsumer();
169 if (consumer) { 151 if (consumer) {
170 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460 152 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/422460
171 // is fixed. 153 // is fixed.
172 tracked_objects::ScopedTracker tracking_profile( 154 tracked_objects::ScopedTracker tracking_profile(
173 FROM_HERE_WITH_EXPLICIT_FUNCTION( 155 FROM_HERE_WITH_EXPLICIT_FUNCTION(
174 "422460 " 156 "422460 "
175 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer")); 157 "WebDataRequestManager::RequestCompletedOnThread::NotifyConsumer"));
176 158
177 consumer->OnWebDataServiceRequestDone(request->GetHandle(), 159 consumer->OnWebDataServiceRequestDone(request->GetHandle(),
178 std::move(result)); 160 std::move(result));
179 } 161 }
180 } 162 }
OLDNEW
« no previous file with comments | « components/webdata/common/web_data_request_manager.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698