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

Side by Side Diff: content/child/shared_memory_data_consumer_handle.cc

Issue 1186053004: Cancel loading when body stream reader is detached. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@error-ipc-data-consumer
Patch Set: Created 5 years, 6 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "content/child/shared_memory_data_consumer_handle.h" 5 #include "content/child/shared_memory_data_consumer_handle.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <deque> 8 #include <deque>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 DISALLOW_COPY_AND_ASSIGN(DelegateThreadSafeReceivedData); 42 DISALLOW_COPY_AND_ASSIGN(DelegateThreadSafeReceivedData);
43 }; 43 };
44 44
45 } // namespace 45 } // namespace
46 46
47 using Result = blink::WebDataConsumerHandle::Result; 47 using Result = blink::WebDataConsumerHandle::Result;
48 48
49 class SharedMemoryDataConsumerHandle::Context final 49 class SharedMemoryDataConsumerHandle::Context final
50 : public base::RefCountedThreadSafe<Context> { 50 : public base::RefCountedThreadSafe<Context> {
51 public: 51 public:
52 Context() 52 explicit Context(const base::Closure& on_reader_detached)
53 : result_(Ok), 53 : result_(Ok),
54 first_offset_(0), 54 first_offset_(0),
55 client_(nullptr), 55 client_(nullptr),
56 writer_task_runner_(base::MessageLoop::current()->task_runner()),
kinuko 2015/06/23 07:56:10 please use base::ThreadTaskRunnerHandle::Get() ins
yhirano 2015/06/23 08:17:55 Done, and replaced similar ones.
57 on_reader_detached_(on_reader_detached),
58 is_on_reader_detached_valid_(!on_reader_detached_.is_null()),
56 is_handle_active_(true), 59 is_handle_active_(true),
57 is_two_phase_read_in_progress_(false) {} 60 is_two_phase_read_in_progress_(false) {}
58 61
59 bool IsEmpty() const { return queue_.empty(); } 62 bool IsEmpty() const { return queue_.empty(); }
60 void ClearIfNecessary() { 63 void ClearIfNecessary() {
61 if (!is_handle_locked() && !is_handle_active()) { 64 if (!is_handle_locked() && !is_handle_active()) {
62 // No one is interested in the contents. 65 // No one is interested in the contents.
66 if (is_on_reader_detached_valid_) {
67 // We post a task even in the writer thread in order to avoid a
68 // reentrance problem as calling |on_reader_detached_| may manipulate
69 // the context synchronously.
70 writer_task_runner_->PostTask(FROM_HERE, on_reader_detached_);
71 }
63 Clear(); 72 Clear();
64 } 73 }
65 } 74 }
66 void ClearQueue() { 75 void ClearQueue() {
67 for (auto& data : queue_) { 76 for (auto& data : queue_) {
68 delete data; 77 delete data;
69 } 78 }
70 queue_.clear(); 79 queue_.clear();
71 first_offset_ = 0; 80 first_offset_ = 0;
72 } 81 }
(...skipping 25 matching lines...) Expand all
98 auto runner = notification_task_runner_; 107 auto runner = notification_task_runner_;
99 if (!runner) 108 if (!runner)
100 return; 109 return;
101 // We don't re-post the task when the runner changes while waiting for 110 // We don't re-post the task when the runner changes while waiting for
102 // this task because in this case a new reader is obtained and 111 // this task because in this case a new reader is obtained and
103 // notification is already done at the reader creation time if necessary. 112 // notification is already done at the reader creation time if necessary.
104 runner->PostTask(FROM_HERE, 113 runner->PostTask(FROM_HERE,
105 base::Bind(&Context::NotifyInternal, this, false)); 114 base::Bind(&Context::NotifyInternal, this, false));
106 } 115 }
107 void Notify() { NotifyInternal(true); } 116 void Notify() { NotifyInternal(true); }
117 // This function doesn't work in the destructor if |on_reader_detached_| is
118 // not null.
119 void ResetOnReaderDetached() {
120 if (on_reader_detached_.is_null()) {
121 DCHECK(!is_on_reader_detached_valid_);
122 return;
123 }
124 is_on_reader_detached_valid_ = false;
125 if (writer_task_runner_->BelongsToCurrentThread()) {
126 // We can reset the closure immediately.
127 on_reader_detached_.Reset();
128 } else {
129 // We need to reset |on_reader_detached_| on the right thread because it
130 // might lead to the object destruction.
131 writer_task_runner_->PostTask(
132 FROM_HERE,
133 base::Bind(&Context::ResetOnReaderDetachedWithLock, this));
134 }
135 }
108 bool is_handle_locked() const { return notification_task_runner_; } 136 bool is_handle_locked() const { return notification_task_runner_; }
109 bool IsReaderBoundToCurrentThread() const { 137 bool IsReaderBoundToCurrentThread() const {
110 return notification_task_runner_ && 138 return notification_task_runner_ &&
111 notification_task_runner_->BelongsToCurrentThread(); 139 notification_task_runner_->BelongsToCurrentThread();
112 } 140 }
113 bool is_handle_active() const { return is_handle_active_; } 141 bool is_handle_active() const { return is_handle_active_; }
114 void set_is_handle_active(bool b) { is_handle_active_ = b; } 142 void set_is_handle_active(bool b) { is_handle_active_ = b; }
115 void Consume(size_t s) { 143 void Consume(size_t s) {
116 first_offset_ += s; 144 first_offset_ += s;
117 auto top = Top(); 145 auto top = Top();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 base::Bind(&Context::NotifyInternal, this, false)); 180 base::Bind(&Context::NotifyInternal, this, false));
153 } 181 }
154 } 182 }
155 void Clear() { 183 void Clear() {
156 for (auto& data : queue_) { 184 for (auto& data : queue_) {
157 delete data; 185 delete data;
158 } 186 }
159 queue_.clear(); 187 queue_.clear();
160 first_offset_ = 0; 188 first_offset_ = 0;
161 client_ = nullptr; 189 client_ = nullptr;
190 // Note this doesn't work in the destructor if |on_reader_detached_| is not
191 // null. We have an assert in the destructor.
192 ResetOnReaderDetached();
193 }
194 void ResetOnReaderDetachedWithLock() {
195 base::AutoLock lock(lock_);
196 ResetOnReaderDetached();
162 } 197 }
163 198
164 friend class base::RefCountedThreadSafe<Context>; 199 friend class base::RefCountedThreadSafe<Context>;
165 ~Context() { 200 ~Context() {
201 DCHECK(on_reader_detached_.is_null());
202
166 // This is necessary because the queue stores raw pointers. 203 // This is necessary because the queue stores raw pointers.
167 Clear(); 204 Clear();
168 } 205 }
169 206
170 base::Lock lock_; 207 base::Lock lock_;
171 // |result_| stores the ultimate state of this handle if it has. Otherwise, 208 // |result_| stores the ultimate state of this handle if it has. Otherwise,
172 // |Ok| is set. 209 // |Ok| is set.
173 Result result_; 210 Result result_;
174 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>> 211 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>>
175 // once it is allowed. 212 // once it is allowed.
176 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_; 213 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_;
177 size_t first_offset_; 214 size_t first_offset_;
178 Client* client_; 215 Client* client_;
179 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; 216 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_;
217 scoped_refptr<base::SingleThreadTaskRunner> writer_task_runner_;
218 base::Closure on_reader_detached_;
219 // We need this boolean variable to remember if |on_reader_detached_| is
220 // callable because we need to reset |on_reader_detached_| only on the writer
221 // thread and hence |on_reader_detached_.is_null()| is untrustworthy on
222 // other threads.
223 bool is_on_reader_detached_valid_;
180 bool is_handle_active_; 224 bool is_handle_active_;
181 bool is_two_phase_read_in_progress_; 225 bool is_two_phase_read_in_progress_;
182 226
183 DISALLOW_COPY_AND_ASSIGN(Context); 227 DISALLOW_COPY_AND_ASSIGN(Context);
184 }; 228 };
185 229
186 SharedMemoryDataConsumerHandle::Writer::Writer( 230 SharedMemoryDataConsumerHandle::Writer::Writer(
187 const scoped_refptr<Context>& context, 231 const scoped_refptr<Context>& context,
188 BackpressureMode mode) 232 BackpressureMode mode)
189 : context_(context), mode_(mode) { 233 : context_(context), mode_(mode) {
190 } 234 }
191 235
192 SharedMemoryDataConsumerHandle::Writer::~Writer() { 236 SharedMemoryDataConsumerHandle::Writer::~Writer() {
193 Close(); 237 Close();
238 base::AutoLock lock(context_->lock());
239 context_->ResetOnReaderDetached();
194 } 240 }
195 241
196 void SharedMemoryDataConsumerHandle::Writer::AddData( 242 void SharedMemoryDataConsumerHandle::Writer::AddData(
197 scoped_ptr<RequestPeer::ReceivedData> data) { 243 scoped_ptr<RequestPeer::ReceivedData> data) {
198 if (!data->length()) { 244 if (!data->length()) {
199 // We omit empty data. 245 // We omit empty data.
200 return; 246 return;
201 } 247 }
202 248
203 bool needs_notification = false; 249 bool needs_notification = false;
(...skipping 23 matching lines...) Expand all
227 } 273 }
228 } 274 }
229 275
230 void SharedMemoryDataConsumerHandle::Writer::Close() { 276 void SharedMemoryDataConsumerHandle::Writer::Close() {
231 bool needs_notification = false; 277 bool needs_notification = false;
232 278
233 { 279 {
234 base::AutoLock lock(context_->lock()); 280 base::AutoLock lock(context_->lock());
235 if (context_->result() == Ok) { 281 if (context_->result() == Ok) {
236 context_->set_result(Done); 282 context_->set_result(Done);
283 context_->ResetOnReaderDetached();
237 needs_notification = context_->IsEmpty(); 284 needs_notification = context_->IsEmpty();
238 } 285 }
239 } 286 }
240 if (needs_notification) { 287 if (needs_notification) {
241 // We cannot issue the notification synchronously because this function can 288 // We cannot issue the notification synchronously because this function can
242 // be called in the client's callback. 289 // be called in the client's callback.
243 context_->PostNotify(); 290 context_->PostNotify();
244 } 291 }
245 } 292 }
246 293
247 void SharedMemoryDataConsumerHandle::Writer::Fail() { 294 void SharedMemoryDataConsumerHandle::Writer::Fail() {
248 bool needs_notification = false; 295 bool needs_notification = false;
249 { 296 {
250 base::AutoLock lock(context_->lock()); 297 base::AutoLock lock(context_->lock());
251 if (context_->result() == Ok) { 298 if (context_->result() == Ok) {
252 // TODO(yhirano): Use an appropriate error code other than 299 // TODO(yhirano): Use an appropriate error code other than
253 // UnexpectedError. 300 // UnexpectedError.
254 context_->set_result(UnexpectedError); 301 context_->set_result(UnexpectedError);
255 302
256 if (context_->is_two_phase_read_in_progress()) { 303 if (context_->is_two_phase_read_in_progress()) {
257 // If we are in two-phase read session, we cannot discard the data. We 304 // If we are in two-phase read session, we cannot discard the data. We
258 // will clear the queue at the end of the session. 305 // will clear the queue at the end of the session.
259 } else { 306 } else {
260 context_->ClearQueue(); 307 context_->ClearQueue();
261 } 308 }
262 309
310 context_->ResetOnReaderDetached();
263 needs_notification = true; 311 needs_notification = true;
264 } 312 }
265 } 313 }
266 if (needs_notification) { 314 if (needs_notification) {
267 // We cannot issue the notification synchronously because this function can 315 // We cannot issue the notification synchronously because this function can
268 // be called in the client's callback. 316 // be called in the client's callback.
269 context_->PostNotify(); 317 context_->PostNotify();
270 } 318 }
271 } 319 }
272 320
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 } else { 403 } else {
356 context_->Consume(read_size); 404 context_->Consume(read_size);
357 } 405 }
358 406
359 return Ok; 407 return Ok;
360 } 408 }
361 409
362 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( 410 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
363 BackpressureMode mode, 411 BackpressureMode mode,
364 scoped_ptr<Writer>* writer) 412 scoped_ptr<Writer>* writer)
365 : context_(new Context) { 413 : SharedMemoryDataConsumerHandle(mode, base::Closure(), writer) {
414 }
415
416 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
417 BackpressureMode mode,
418 const base::Closure& on_reader_detached,
419 scoped_ptr<Writer>* writer)
420 : context_(new Context(on_reader_detached)) {
366 writer->reset(new Writer(context_, mode)); 421 writer->reset(new Writer(context_, mode));
367 } 422 }
368 423
369 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() { 424 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() {
370 base::AutoLock lock(context_->lock()); 425 base::AutoLock lock(context_->lock());
371 context_->set_is_handle_active(false); 426 context_->set_is_handle_active(false);
372 context_->ClearIfNecessary(); 427 context_->ClearIfNecessary();
373 } 428 }
374 429
375 scoped_ptr<blink::WebDataConsumerHandle::Reader> 430 scoped_ptr<blink::WebDataConsumerHandle::Reader>
376 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) { 431 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) {
377 return make_scoped_ptr(obtainReaderInternal(client)); 432 return make_scoped_ptr(obtainReaderInternal(client));
378 } 433 }
379 434
380 SharedMemoryDataConsumerHandle::ReaderImpl* 435 SharedMemoryDataConsumerHandle::ReaderImpl*
381 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) { 436 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) {
382 return new ReaderImpl(context_, client); 437 return new ReaderImpl(context_, client);
383 } 438 }
384 439
385 const char* SharedMemoryDataConsumerHandle::debugName() const { 440 const char* SharedMemoryDataConsumerHandle::debugName() const {
386 return "SharedMemoryDataConsumerHandle"; 441 return "SharedMemoryDataConsumerHandle";
387 } 442 }
388 443
389 } // namespace content 444 } // namespace content
OLDNEW
« no previous file with comments | « content/child/shared_memory_data_consumer_handle.h ('k') | content/child/shared_memory_data_consumer_handle_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698