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

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_clear)
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()),
57 on_clear_(on_clear),
58 is_on_clear_valid_(!on_clear_.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_clear_valid_) {
67 // We post a task even in the writer thread in order to keep reentrancy.
hiroshige 2015/06/22 18:23:16 how about adding "because didGetReadable() can des
yhirano 2015/06/23 05:28:37 Done.
68 writer_task_runner_->PostTask(FROM_HERE, on_clear_);
69 }
63 Clear(); 70 Clear();
64 } 71 }
65 } 72 }
66 void ClearQueue() { 73 void ClearQueue() {
67 for (auto& data : queue_) { 74 for (auto& data : queue_) {
68 delete data; 75 delete data;
69 } 76 }
70 queue_.clear(); 77 queue_.clear();
71 first_offset_ = 0; 78 first_offset_ = 0;
72 } 79 }
(...skipping 25 matching lines...) Expand all
98 auto runner = notification_task_runner_; 105 auto runner = notification_task_runner_;
99 if (!runner) 106 if (!runner)
100 return; 107 return;
101 // We don't re-post the task when the runner changes while waiting for 108 // 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 109 // this task because in this case a new reader is obtained and
103 // notification is already done at the reader creation time if necessary. 110 // notification is already done at the reader creation time if necessary.
104 runner->PostTask(FROM_HERE, 111 runner->PostTask(FROM_HERE,
105 base::Bind(&Context::NotifyInternal, this, false)); 112 base::Bind(&Context::NotifyInternal, this, false));
106 } 113 }
107 void Notify() { NotifyInternal(true); } 114 void Notify() { NotifyInternal(true); }
115 void ResetOnClear() {
116 if (on_clear_.is_null()) {
117 DCHECK(!is_on_clear_valid_);
118 return;
119 }
120 is_on_clear_valid_ = false;
121 if (writer_task_runner_->BelongsToCurrentThread()) {
122 // We can reset the closure immediately.
123 on_clear_.Reset();
124 } else {
125 // We need to reset |on_clear_| on the right thread because it might
126 // lead to the object destruction.
127 writer_task_runner_->PostTask(FROM_HERE,
128 base::Bind(&Context::ResetOnClear, this));
129 }
130 }
108 bool is_handle_locked() const { return notification_task_runner_; } 131 bool is_handle_locked() const { return notification_task_runner_; }
109 bool IsReaderBoundToCurrentThread() const { 132 bool IsReaderBoundToCurrentThread() const {
110 return notification_task_runner_ && 133 return notification_task_runner_ &&
111 notification_task_runner_->BelongsToCurrentThread(); 134 notification_task_runner_->BelongsToCurrentThread();
112 } 135 }
113 bool is_handle_active() const { return is_handle_active_; } 136 bool is_handle_active() const { return is_handle_active_; }
114 void set_is_handle_active(bool b) { is_handle_active_ = b; } 137 void set_is_handle_active(bool b) { is_handle_active_ = b; }
115 void Consume(size_t s) { 138 void Consume(size_t s) {
116 first_offset_ += s; 139 first_offset_ += s;
117 auto top = Top(); 140 auto top = Top();
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 base::Bind(&Context::NotifyInternal, this, false)); 175 base::Bind(&Context::NotifyInternal, this, false));
153 } 176 }
154 } 177 }
155 void Clear() { 178 void Clear() {
156 for (auto& data : queue_) { 179 for (auto& data : queue_) {
157 delete data; 180 delete data;
158 } 181 }
159 queue_.clear(); 182 queue_.clear();
160 first_offset_ = 0; 183 first_offset_ = 0;
161 client_ = nullptr; 184 client_ = nullptr;
185 // Note this doesn't work in the destructor if |on_clear_| is not null. We
hiroshige 2015/06/22 18:23:16 This comment might be better to be placed just bef
yhirano 2015/06/23 05:28:37 Done.
186 // have an assert in the destructor.
187 ResetOnClear();
162 } 188 }
163 189
164 friend class base::RefCountedThreadSafe<Context>; 190 friend class base::RefCountedThreadSafe<Context>;
165 ~Context() { 191 ~Context() {
192 DCHECK(on_clear_.is_null());
193
166 // This is necessary because the queue stores raw pointers. 194 // This is necessary because the queue stores raw pointers.
167 Clear(); 195 Clear();
168 } 196 }
169 197
170 base::Lock lock_; 198 base::Lock lock_;
171 // |result_| stores the ultimate state of this handle if it has. Otherwise, 199 // |result_| stores the ultimate state of this handle if it has. Otherwise,
172 // |Ok| is set. 200 // |Ok| is set.
173 Result result_; 201 Result result_;
174 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>> 202 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>>
175 // once it is allowed. 203 // once it is allowed.
176 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_; 204 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_;
177 size_t first_offset_; 205 size_t first_offset_;
178 Client* client_; 206 Client* client_;
179 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; 207 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_;
208 scoped_refptr<base::SingleThreadTaskRunner> writer_task_runner_;
209 base::Closure on_clear_;
210 // We need this boolean variable to remember if |on_clear_| is callable
211 // because we need to set |on_clear_| only on the writer thread and hence
hiroshige 2015/06/22 18:23:16 optional: how about "... because |on_clear_| is re
yhirano 2015/06/23 05:28:38 I think it misleading the callback will be reset s
212 // |on_clear_.is_null()| is untrustworthy.
213 bool is_on_clear_valid_;
hiroshige 2015/06/22 18:23:16 Please add a comment that |on_clear_| and |is_on_c
yhirano 2015/06/23 05:28:37 Other variables are also protected by the lock, so
180 bool is_handle_active_; 214 bool is_handle_active_;
181 bool is_two_phase_read_in_progress_; 215 bool is_two_phase_read_in_progress_;
182 216
183 DISALLOW_COPY_AND_ASSIGN(Context); 217 DISALLOW_COPY_AND_ASSIGN(Context);
184 }; 218 };
185 219
186 SharedMemoryDataConsumerHandle::Writer::Writer( 220 SharedMemoryDataConsumerHandle::Writer::Writer(
187 const scoped_refptr<Context>& context, 221 const scoped_refptr<Context>& context,
188 BackpressureMode mode) 222 BackpressureMode mode)
189 : context_(context), mode_(mode) { 223 : context_(context), mode_(mode) {
190 } 224 }
191 225
192 SharedMemoryDataConsumerHandle::Writer::~Writer() { 226 SharedMemoryDataConsumerHandle::Writer::~Writer() {
193 Close(); 227 Close();
228 base::AutoLock lock(context_->lock());
229 context_->ResetOnClear();
194 } 230 }
195 231
196 void SharedMemoryDataConsumerHandle::Writer::AddData( 232 void SharedMemoryDataConsumerHandle::Writer::AddData(
197 scoped_ptr<RequestPeer::ReceivedData> data) { 233 scoped_ptr<RequestPeer::ReceivedData> data) {
198 if (!data->length()) { 234 if (!data->length()) {
199 // We omit empty data. 235 // We omit empty data.
200 return; 236 return;
201 } 237 }
202 238
203 bool needs_notification = false; 239 bool needs_notification = false;
(...skipping 23 matching lines...) Expand all
227 } 263 }
228 } 264 }
229 265
230 void SharedMemoryDataConsumerHandle::Writer::Close() { 266 void SharedMemoryDataConsumerHandle::Writer::Close() {
231 bool needs_notification = false; 267 bool needs_notification = false;
232 268
233 { 269 {
234 base::AutoLock lock(context_->lock()); 270 base::AutoLock lock(context_->lock());
235 if (context_->result() == Ok) { 271 if (context_->result() == Ok) {
236 context_->set_result(Done); 272 context_->set_result(Done);
273 context_->ResetOnClear();
237 needs_notification = context_->IsEmpty(); 274 needs_notification = context_->IsEmpty();
238 } 275 }
239 } 276 }
240 if (needs_notification) { 277 if (needs_notification) {
241 // We cannot issue the notification synchronously because this function can 278 // We cannot issue the notification synchronously because this function can
242 // be called in the client's callback. 279 // be called in the client's callback.
243 context_->PostNotify(); 280 context_->PostNotify();
244 } 281 }
245 } 282 }
246 283
247 void SharedMemoryDataConsumerHandle::Writer::Fail() { 284 void SharedMemoryDataConsumerHandle::Writer::Fail() {
248 bool needs_notification = false; 285 bool needs_notification = false;
249 { 286 {
250 base::AutoLock lock(context_->lock()); 287 base::AutoLock lock(context_->lock());
251 if (context_->result() == Ok) { 288 if (context_->result() == Ok) {
252 // TODO(yhirano): Use an appropriate error code other than 289 // TODO(yhirano): Use an appropriate error code other than
253 // UnexpectedError. 290 // UnexpectedError.
254 context_->set_result(UnexpectedError); 291 context_->set_result(UnexpectedError);
255 292
256 if (context_->is_two_phase_read_in_progress()) { 293 if (context_->is_two_phase_read_in_progress()) {
257 // If we are in two-phase read session, we cannot discard the data. We 294 // 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. 295 // will clear the queue at the end of the session.
259 } else { 296 } else {
260 context_->ClearQueue(); 297 context_->ClearQueue();
261 } 298 }
262 299
300 context_->ResetOnClear();
263 needs_notification = true; 301 needs_notification = true;
264 } 302 }
265 } 303 }
266 if (needs_notification) { 304 if (needs_notification) {
267 // We cannot issue the notification synchronously because this function can 305 // We cannot issue the notification synchronously because this function can
268 // be called in the client's callback. 306 // be called in the client's callback.
269 context_->PostNotify(); 307 context_->PostNotify();
270 } 308 }
271 } 309 }
272 310
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
355 } else { 393 } else {
356 context_->Consume(read_size); 394 context_->Consume(read_size);
357 } 395 }
358 396
359 return Ok; 397 return Ok;
360 } 398 }
361 399
362 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( 400 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
363 BackpressureMode mode, 401 BackpressureMode mode,
364 scoped_ptr<Writer>* writer) 402 scoped_ptr<Writer>* writer)
365 : context_(new Context) { 403 : SharedMemoryDataConsumerHandle(mode, base::Closure(), writer) {
404 }
405
406 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
407 BackpressureMode mode,
408 const base::Closure& on_clear,
409 scoped_ptr<Writer>* writer)
410 : context_(new Context(on_clear)) {
366 writer->reset(new Writer(context_, mode)); 411 writer->reset(new Writer(context_, mode));
367 } 412 }
368 413
369 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() { 414 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() {
370 base::AutoLock lock(context_->lock()); 415 base::AutoLock lock(context_->lock());
371 context_->set_is_handle_active(false); 416 context_->set_is_handle_active(false);
372 context_->ClearIfNecessary(); 417 context_->ClearIfNecessary();
373 } 418 }
374 419
375 scoped_ptr<blink::WebDataConsumerHandle::Reader> 420 scoped_ptr<blink::WebDataConsumerHandle::Reader>
376 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) { 421 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) {
377 return make_scoped_ptr(obtainReaderInternal(client)); 422 return make_scoped_ptr(obtainReaderInternal(client));
378 } 423 }
379 424
380 SharedMemoryDataConsumerHandle::ReaderImpl* 425 SharedMemoryDataConsumerHandle::ReaderImpl*
381 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) { 426 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) {
382 return new ReaderImpl(context_, client); 427 return new ReaderImpl(context_, client);
383 } 428 }
384 429
385 const char* SharedMemoryDataConsumerHandle::debugName() const { 430 const char* SharedMemoryDataConsumerHandle::debugName() const {
386 return "SharedMemoryDataConsumerHandle"; 431 return "SharedMemoryDataConsumerHandle";
387 } 432 }
388 433
389 } // namespace content 434 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698