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

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

Issue 1181573003: Set error on WebDataConsumerHandle while loading body. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@use-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 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 Context()
53 : result_(Ok), 53 : result_(Ok),
54 first_offset_(0), 54 first_offset_(0),
55 client_(nullptr), 55 client_(nullptr),
56 is_handle_active_(true) {} 56 is_handle_active_(true),
57 is_two_phase_read_in_progress_(false) {}
57 58
58 bool IsEmpty() const { return queue_.empty(); } 59 bool IsEmpty() const { return queue_.empty(); }
59 void ClearIfNecessary() { 60 void ClearIfNecessary() {
60 if (!is_handle_locked() && !is_handle_active()) { 61 if (!is_handle_locked() && !is_handle_active()) {
61 // No one is interested in the contents. 62 // No one is interested in the contents.
62 Clear(); 63 Clear();
63 } 64 }
64 } 65 }
66 void ClearQueue() {
67 for (auto& data : queue_) {
68 delete data;
69 }
70 queue_.clear();
71 first_offset_ = 0;
72 }
65 RequestPeer::ThreadSafeReceivedData* Top() { return queue_.front(); } 73 RequestPeer::ThreadSafeReceivedData* Top() { return queue_.front(); }
66 void Push(scoped_ptr<RequestPeer::ThreadSafeReceivedData> data) { 74 void Push(scoped_ptr<RequestPeer::ThreadSafeReceivedData> data) {
67 queue_.push_back(data.release()); 75 queue_.push_back(data.release());
68 } 76 }
69 size_t first_offset() const { return first_offset_; } 77 size_t first_offset() const { return first_offset_; }
70 Result result() const { return result_; } 78 Result result() const { return result_; }
71 void set_result(Result r) { result_ = r; } 79 void set_result(Result r) { result_ = r; }
72 void AcquireReaderLock(Client* client) { 80 void AcquireReaderLock(Client* client) {
73 DCHECK(!notification_task_runner_); 81 DCHECK(!notification_task_runner_);
74 DCHECK(!client_); 82 DCHECK(!client_);
75 notification_task_runner_ = base::MessageLoop::current()->task_runner(); 83 notification_task_runner_ = base::MessageLoop::current()->task_runner();
76 client_ = client; 84 client_ = client;
77 if (client && !(IsEmpty() && result() == Ok)) { 85 if (client && !(IsEmpty() && result() == Ok)) {
78 // We cannot notify synchronously because the user doesn't have the reader 86 // We cannot notify synchronously because the user doesn't have the reader
79 // yet. 87 // yet.
80 notification_task_runner_->PostTask( 88 notification_task_runner_->PostTask(
81 FROM_HERE, base::Bind(&Context::NotifyInternal, this, false)); 89 FROM_HERE, base::Bind(&Context::NotifyInternal, this, false));
82 } 90 }
83 } 91 }
84 void ReleaseReaderLock() { 92 void ReleaseReaderLock() {
85 DCHECK(notification_task_runner_); 93 DCHECK(notification_task_runner_);
86 notification_task_runner_ = nullptr; 94 notification_task_runner_ = nullptr;
87 client_ = nullptr; 95 client_ = nullptr;
88 } 96 }
97 void PostNotify() {
98 auto runner = notification_task_runner_;
99 if (!runner)
100 return;
101 // 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
103 // notification is already done at the reader creation time if necessary.
104 runner->PostTask(FROM_HERE,
105 base::Bind(&Context::NotifyInternal, this, false));
106 }
89 void Notify() { NotifyInternal(true); } 107 void Notify() { NotifyInternal(true); }
90 bool is_handle_locked() const { return notification_task_runner_; } 108 bool is_handle_locked() const { return notification_task_runner_; }
91 bool IsReaderBoundToCurrentThread() const { 109 bool IsReaderBoundToCurrentThread() const {
92 return notification_task_runner_ && 110 return notification_task_runner_ &&
93 notification_task_runner_->BelongsToCurrentThread(); 111 notification_task_runner_->BelongsToCurrentThread();
94 } 112 }
95 bool is_handle_active() const { return is_handle_active_; } 113 bool is_handle_active() const { return is_handle_active_; }
96 void set_is_handle_active(bool b) { is_handle_active_ = b; } 114 void set_is_handle_active(bool b) { is_handle_active_ = b; }
97 void Consume(size_t s) { 115 void Consume(size_t s) {
98 first_offset_ += s; 116 first_offset_ += s;
99 auto top = Top(); 117 auto top = Top();
100 if (static_cast<size_t>(top->length()) <= first_offset_) { 118 if (static_cast<size_t>(top->length()) <= first_offset_) {
101 delete top; 119 delete top;
102 queue_.pop_front(); 120 queue_.pop_front();
103 first_offset_ = 0; 121 first_offset_ = 0;
104 } 122 }
105 } 123 }
124 bool is_two_phase_read_in_progress() const {
125 return is_two_phase_read_in_progress_;
126 }
127 void set_is_two_phase_read_in_progress(bool b) {
128 is_two_phase_read_in_progress_ = b;
129 }
106 base::Lock& lock() { return lock_; } 130 base::Lock& lock() { return lock_; }
107 131
108 private: 132 private:
109 void NotifyInternal(bool repost) { 133 void NotifyInternal(bool repost) {
110 // Note that this function is not protected by |lock_|. 134 // Note that this function is not protected by |lock_|.
111 135
112 auto runner = notification_task_runner_; 136 auto runner = notification_task_runner_;
113 if (!runner) 137 if (!runner)
114 return; 138 return;
115 139
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 // |result_| stores the ultimate state of this handle if it has. Otherwise, 171 // |result_| stores the ultimate state of this handle if it has. Otherwise,
148 // |Ok| is set. 172 // |Ok| is set.
149 Result result_; 173 Result result_;
150 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>> 174 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>>
151 // once it is allowed. 175 // once it is allowed.
152 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_; 176 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_;
153 size_t first_offset_; 177 size_t first_offset_;
154 Client* client_; 178 Client* client_;
155 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; 179 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_;
156 bool is_handle_active_; 180 bool is_handle_active_;
181 bool is_two_phase_read_in_progress_;
157 182
158 DISALLOW_COPY_AND_ASSIGN(Context); 183 DISALLOW_COPY_AND_ASSIGN(Context);
159 }; 184 };
160 185
161 SharedMemoryDataConsumerHandle::Writer::Writer( 186 SharedMemoryDataConsumerHandle::Writer::Writer(
162 const scoped_refptr<Context>& context, 187 const scoped_refptr<Context>& context,
163 BackpressureMode mode) 188 BackpressureMode mode)
164 : context_(context), mode_(mode) { 189 : context_(context), mode_(mode) {
165 } 190 }
166 191
(...skipping 20 matching lines...) Expand all
187 scoped_ptr<RequestPeer::ThreadSafeReceivedData> data_to_pass; 212 scoped_ptr<RequestPeer::ThreadSafeReceivedData> data_to_pass;
188 if (mode_ == kApplyBackpressure) { 213 if (mode_ == kApplyBackpressure) {
189 data_to_pass = 214 data_to_pass =
190 make_scoped_ptr(new DelegateThreadSafeReceivedData(data.Pass())); 215 make_scoped_ptr(new DelegateThreadSafeReceivedData(data.Pass()));
191 } else { 216 } else {
192 data_to_pass = make_scoped_ptr(new FixedReceivedData(data.get())); 217 data_to_pass = make_scoped_ptr(new FixedReceivedData(data.get()));
193 } 218 }
194 context_->Push(data_to_pass.Pass()); 219 context_->Push(data_to_pass.Pass());
195 } 220 }
196 221
197 if (needs_notification) 222 if (needs_notification) {
223 // We CAN issue the notification synchronously if the associated reader
224 // lives in this thread, because this function cannot be called in the
225 // client's callback.
198 context_->Notify(); 226 context_->Notify();
227 }
199 } 228 }
200 229
201 void SharedMemoryDataConsumerHandle::Writer::Close() { 230 void SharedMemoryDataConsumerHandle::Writer::Close() {
202 bool needs_notification = false; 231 bool needs_notification = false;
203 232
204 { 233 {
205 base::AutoLock lock(context_->lock()); 234 base::AutoLock lock(context_->lock());
206 if (context_->result() == Ok) { 235 if (context_->result() == Ok) {
207 context_->set_result(Done); 236 context_->set_result(Done);
208 needs_notification = context_->IsEmpty(); 237 needs_notification = context_->IsEmpty();
209 } 238 }
210 } 239 }
211 if (needs_notification) 240 if (needs_notification) {
212 context_->Notify(); 241 // We cannot issue the notification synchronously because this function can
242 // be called in the client's callback.
243 context_->PostNotify();
244 }
245 }
246
247 void SharedMemoryDataConsumerHandle::Writer::Fail() {
248 bool needs_notification = false;
249 {
250 base::AutoLock lock(context_->lock());
251 if (context_->result() == Ok) {
252 // TODO(yhirano): Use an appropriate error code other than
253 // UnexpectedError.
254 context_->set_result(UnexpectedError);
255
256 if (context_->is_two_phase_read_in_progress()) {
257 // 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.
259 } else {
260 context_->ClearQueue();
261 }
262
263 needs_notification = true;
264 }
265 }
266 if (needs_notification) {
267 // We cannot issue the notification synchronously because this function can
268 // be called in the client's callback.
269 context_->PostNotify();
270 }
213 } 271 }
214 272
215 SharedMemoryDataConsumerHandle::ReaderImpl::ReaderImpl( 273 SharedMemoryDataConsumerHandle::ReaderImpl::ReaderImpl(
216 scoped_refptr<Context> context, 274 scoped_refptr<Context> context,
217 Client* client) 275 Client* client)
218 : context_(context) { 276 : context_(context) {
219 base::AutoLock lock(context_->lock()); 277 base::AutoLock lock(context_->lock());
220 DCHECK(!context_->is_handle_locked()); 278 DCHECK(!context_->is_handle_locked());
221 context_->AcquireReaderLock(client); 279 context_->AcquireReaderLock(client);
222 } 280 }
223 281
224 SharedMemoryDataConsumerHandle::ReaderImpl::~ReaderImpl() { 282 SharedMemoryDataConsumerHandle::ReaderImpl::~ReaderImpl() {
225 base::AutoLock lock(context_->lock()); 283 base::AutoLock lock(context_->lock());
226 context_->ReleaseReaderLock(); 284 context_->ReleaseReaderLock();
227 context_->ClearIfNecessary(); 285 context_->ClearIfNecessary();
228 } 286 }
229 287
230 Result SharedMemoryDataConsumerHandle::ReaderImpl::read( 288 Result SharedMemoryDataConsumerHandle::ReaderImpl::read(
231 void* data, 289 void* data,
232 size_t size, 290 size_t size,
233 Flags flags, 291 Flags flags,
234 size_t* read_size_to_return) { 292 size_t* read_size_to_return) {
235 base::AutoLock lock(context_->lock()); 293 base::AutoLock lock(context_->lock());
236 294
237 size_t total_read_size = 0; 295 size_t total_read_size = 0;
238 *read_size_to_return = 0; 296 *read_size_to_return = 0;
297
298 if (context_->result() == Ok && context_->is_two_phase_read_in_progress())
299 context_->set_result(UnexpectedError);
300
239 if (context_->result() != Ok && context_->result() != Done) 301 if (context_->result() != Ok && context_->result() != Done)
240 return context_->result(); 302 return context_->result();
241 303
242 while (!context_->IsEmpty() && total_read_size < size) { 304 while (!context_->IsEmpty() && total_read_size < size) {
243 const auto& top = context_->Top(); 305 const auto& top = context_->Top();
244 size_t readable = top->length() - context_->first_offset(); 306 size_t readable = top->length() - context_->first_offset();
245 size_t writable = size - total_read_size; 307 size_t writable = size - total_read_size;
246 size_t read_size = std::min(readable, writable); 308 size_t read_size = std::min(readable, writable);
247 const char* begin = top->payload() + context_->first_offset(); 309 const char* begin = top->payload() + context_->first_offset();
248 std::copy(begin, begin + read_size, 310 std::copy(begin, begin + read_size,
249 static_cast<char*>(data) + total_read_size); 311 static_cast<char*>(data) + total_read_size);
250 total_read_size += read_size; 312 total_read_size += read_size;
251 context_->Consume(read_size); 313 context_->Consume(read_size);
252 } 314 }
253 *read_size_to_return = total_read_size; 315 *read_size_to_return = total_read_size;
254 return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait; 316 return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait;
255 } 317 }
256 318
257 Result SharedMemoryDataConsumerHandle::ReaderImpl::beginRead( 319 Result SharedMemoryDataConsumerHandle::ReaderImpl::beginRead(
258 const void** buffer, 320 const void** buffer,
259 Flags flags, 321 Flags flags,
260 size_t* available) { 322 size_t* available) {
261 *buffer = nullptr; 323 *buffer = nullptr;
262 *available = 0; 324 *available = 0;
263 325
264 base::AutoLock lock(context_->lock()); 326 base::AutoLock lock(context_->lock());
265 327
328 if (context_->result() == Ok && context_->is_two_phase_read_in_progress())
329 context_->set_result(UnexpectedError);
330
266 if (context_->result() != Ok && context_->result() != Done) 331 if (context_->result() != Ok && context_->result() != Done)
267 return context_->result(); 332 return context_->result();
268 333
269 if (context_->IsEmpty()) 334 if (context_->IsEmpty())
270 return context_->result() == Done ? Done : ShouldWait; 335 return context_->result() == Done ? Done : ShouldWait;
271 336
337 context_->set_is_two_phase_read_in_progress(true);
272 const auto& top = context_->Top(); 338 const auto& top = context_->Top();
273 *buffer = top->payload() + context_->first_offset(); 339 *buffer = top->payload() + context_->first_offset();
274 *available = top->length() - context_->first_offset(); 340 *available = top->length() - context_->first_offset();
275 341
276 return Ok; 342 return Ok;
277 } 343 }
278 344
279 Result SharedMemoryDataConsumerHandle::ReaderImpl::endRead(size_t read_size) { 345 Result SharedMemoryDataConsumerHandle::ReaderImpl::endRead(size_t read_size) {
280 base::AutoLock lock(context_->lock()); 346 base::AutoLock lock(context_->lock());
281 347
282 if (context_->IsEmpty()) 348 if (!context_->is_two_phase_read_in_progress())
283 return UnexpectedError; 349 return UnexpectedError;
284 350
285 context_->Consume(read_size); 351 context_->set_is_two_phase_read_in_progress(false);
352 if (context_->result() != Ok && context_->result() != Done) {
353 // We have an error, so we can discard the stored data.
354 context_->ClearQueue();
355 } else {
356 context_->Consume(read_size);
357 }
358
286 return Ok; 359 return Ok;
287 } 360 }
288 361
289 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( 362 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle(
290 BackpressureMode mode, 363 BackpressureMode mode,
291 scoped_ptr<Writer>* writer) 364 scoped_ptr<Writer>* writer)
292 : context_(new Context) { 365 : context_(new Context) {
293 writer->reset(new Writer(context_, mode)); 366 writer->reset(new Writer(context_, mode));
294 } 367 }
295 368
296 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() { 369 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() {
297 base::AutoLock lock(context_->lock()); 370 base::AutoLock lock(context_->lock());
298 context_->set_is_handle_active(false); 371 context_->set_is_handle_active(false);
299 context_->ClearIfNecessary(); 372 context_->ClearIfNecessary();
300 } 373 }
301 374
302 scoped_ptr<blink::WebDataConsumerHandle::Reader> 375 scoped_ptr<blink::WebDataConsumerHandle::Reader>
303 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) { 376 SharedMemoryDataConsumerHandle::ObtainReader(Client* client) {
304 return make_scoped_ptr(obtainReaderInternal(client)); 377 return make_scoped_ptr(obtainReaderInternal(client));
305 } 378 }
306 379
307 SharedMemoryDataConsumerHandle::ReaderImpl* 380 SharedMemoryDataConsumerHandle::ReaderImpl*
308 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) { 381 SharedMemoryDataConsumerHandle::obtainReaderInternal(Client* client) {
309 return new ReaderImpl(context_, client); 382 return new ReaderImpl(context_, client);
310 } 383 }
311 384
312 Result SharedMemoryDataConsumerHandle::read(void* data,
313 size_t size,
314 Flags flags,
315 size_t* read_size_to_return) {
316 // Note this (and below similar functions) is a bit racy. We don't care about
317 // it because this is a deprecated function and will be removed shortly.
318 LockImplicitly();
319 return reader_->read(data, size, flags, read_size_to_return);
320 }
321
322 Result SharedMemoryDataConsumerHandle::beginRead(const void** buffer,
323 Flags flags,
324 size_t* available) {
325 LockImplicitly();
326 return reader_->beginRead(buffer, flags, available);
327 }
328
329 Result SharedMemoryDataConsumerHandle::endRead(size_t read_size) {
330 LockImplicitly();
331 return reader_->endRead(read_size);
332 }
333
334 void SharedMemoryDataConsumerHandle::registerClient(Client* client) {
335 UnlockImplicitly();
336 reader_ = ObtainReader(client);
337 }
338
339 void SharedMemoryDataConsumerHandle::unregisterClient() {
340 reader_.reset();
341 }
342
343 void SharedMemoryDataConsumerHandle::LockImplicitly() {
344 {
345 base::AutoLock lock(context_->lock());
346 if (reader_) {
347 DCHECK(context_->IsReaderBoundToCurrentThread());
348 return;
349 }
350 }
351 reader_ = ObtainReader(nullptr);
352 }
353
354 void SharedMemoryDataConsumerHandle::UnlockImplicitly() {
355 bool needs_unlock = false;
356 {
357 base::AutoLock lock(context_->lock());
358 if (reader_) {
359 DCHECK(context_->IsReaderBoundToCurrentThread());
360 needs_unlock = true;
361 }
362 }
363 if (needs_unlock) {
364 reader_.reset();
365 }
366 }
367
368 const char* SharedMemoryDataConsumerHandle::debugName() const { 385 const char* SharedMemoryDataConsumerHandle::debugName() const {
369 return "SharedMemoryDataConsumerHandle"; 386 return "SharedMemoryDataConsumerHandle";
370 } 387 }
371 388
372 } // namespace content 389 } // 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