Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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_); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 96 void set_is_handle_active(bool b) { is_handle_active_ = b; } | 104 void set_is_handle_active(bool b) { is_handle_active_ = b; } |
| 97 void Consume(size_t s) { | 105 void Consume(size_t s) { |
| 98 first_offset_ += s; | 106 first_offset_ += s; |
| 99 auto top = Top(); | 107 auto top = Top(); |
| 100 if (static_cast<size_t>(top->length()) <= first_offset_) { | 108 if (static_cast<size_t>(top->length()) <= first_offset_) { |
| 101 delete top; | 109 delete top; |
| 102 queue_.pop_front(); | 110 queue_.pop_front(); |
| 103 first_offset_ = 0; | 111 first_offset_ = 0; |
| 104 } | 112 } |
| 105 } | 113 } |
| 114 bool is_two_phase_read_in_progress() const { | |
| 115 return is_two_phase_read_in_progress_; | |
| 116 } | |
| 117 void set_is_two_phase_read_in_progress(bool b) { | |
| 118 is_two_phase_read_in_progress_ = b; | |
| 119 } | |
| 106 base::Lock& lock() { return lock_; } | 120 base::Lock& lock() { return lock_; } |
| 107 | 121 |
| 108 private: | 122 private: |
| 109 void NotifyInternal(bool repost) { | 123 void NotifyInternal(bool repost) { |
| 110 // Note that this function is not protected by |lock_|. | 124 // Note that this function is not protected by |lock_|. |
| 111 | 125 |
| 112 auto runner = notification_task_runner_; | 126 auto runner = notification_task_runner_; |
| 113 if (!runner) | 127 if (!runner) |
| 114 return; | 128 return; |
| 115 | 129 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 // |result_| stores the ultimate state of this handle if it has. Otherwise, | 161 // |result_| stores the ultimate state of this handle if it has. Otherwise, |
| 148 // |Ok| is set. | 162 // |Ok| is set. |
| 149 Result result_; | 163 Result result_; |
| 150 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>> | 164 // TODO(yhirano): Use std::deque<scoped_ptr<ThreadSafeReceivedData>> |
| 151 // once it is allowed. | 165 // once it is allowed. |
| 152 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_; | 166 std::deque<RequestPeer::ThreadSafeReceivedData*> queue_; |
| 153 size_t first_offset_; | 167 size_t first_offset_; |
| 154 Client* client_; | 168 Client* client_; |
| 155 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; | 169 scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; |
| 156 bool is_handle_active_; | 170 bool is_handle_active_; |
| 171 bool is_two_phase_read_in_progress_; | |
| 157 | 172 |
| 158 DISALLOW_COPY_AND_ASSIGN(Context); | 173 DISALLOW_COPY_AND_ASSIGN(Context); |
| 159 }; | 174 }; |
| 160 | 175 |
| 161 SharedMemoryDataConsumerHandle::Writer::Writer( | 176 SharedMemoryDataConsumerHandle::Writer::Writer( |
| 162 const scoped_refptr<Context>& context, | 177 const scoped_refptr<Context>& context, |
| 163 BackpressureMode mode) | 178 BackpressureMode mode) |
| 164 : context_(context), mode_(mode) { | 179 : context_(context), mode_(mode) { |
| 165 } | 180 } |
| 166 | 181 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 205 base::AutoLock lock(context_->lock()); | 220 base::AutoLock lock(context_->lock()); |
| 206 if (context_->result() == Ok) { | 221 if (context_->result() == Ok) { |
| 207 context_->set_result(Done); | 222 context_->set_result(Done); |
| 208 needs_notification = context_->IsEmpty(); | 223 needs_notification = context_->IsEmpty(); |
| 209 } | 224 } |
| 210 } | 225 } |
| 211 if (needs_notification) | 226 if (needs_notification) |
| 212 context_->Notify(); | 227 context_->Notify(); |
| 213 } | 228 } |
| 214 | 229 |
| 230 void SharedMemoryDataConsumerHandle::Writer::Error() { | |
| 231 bool needs_notification = false; | |
| 232 | |
| 233 { | |
| 234 base::AutoLock lock(context_->lock()); | |
| 235 if (context_->result() == Ok) { | |
| 236 // TODO(yhirano): Use an appropriate error code other than | |
| 237 // UnexpectedError. | |
| 238 context_->set_result(UnexpectedError); | |
| 239 | |
| 240 if (!context_->is_two_phase_read_in_progress()) { | |
| 241 // If we are in two-phase read session, we cannot discard the data. | |
| 242 // Otherwise, clear the data. | |
|
hiroshige
2015/06/18 07:01:20
Please mention in the comment when/how ClearQueue(
yhirano
2015/06/18 08:13:33
Done.
| |
| 243 context_->ClearQueue(); | |
| 244 } | |
| 245 | |
| 246 needs_notification = true; | |
| 247 } | |
| 248 } | |
| 249 if (needs_notification) | |
| 250 context_->Notify(); | |
| 251 } | |
| 252 | |
| 215 SharedMemoryDataConsumerHandle::ReaderImpl::ReaderImpl( | 253 SharedMemoryDataConsumerHandle::ReaderImpl::ReaderImpl( |
| 216 scoped_refptr<Context> context, | 254 scoped_refptr<Context> context, |
| 217 Client* client) | 255 Client* client) |
| 218 : context_(context) { | 256 : context_(context) { |
| 219 base::AutoLock lock(context_->lock()); | 257 base::AutoLock lock(context_->lock()); |
| 220 DCHECK(!context_->is_handle_locked()); | 258 DCHECK(!context_->is_handle_locked()); |
| 221 context_->AcquireReaderLock(client); | 259 context_->AcquireReaderLock(client); |
| 222 } | 260 } |
| 223 | 261 |
| 224 SharedMemoryDataConsumerHandle::ReaderImpl::~ReaderImpl() { | 262 SharedMemoryDataConsumerHandle::ReaderImpl::~ReaderImpl() { |
| 225 base::AutoLock lock(context_->lock()); | 263 base::AutoLock lock(context_->lock()); |
| 226 context_->ReleaseReaderLock(); | 264 context_->ReleaseReaderLock(); |
| 227 context_->ClearIfNecessary(); | 265 context_->ClearIfNecessary(); |
| 228 } | 266 } |
| 229 | 267 |
| 230 Result SharedMemoryDataConsumerHandle::ReaderImpl::read( | 268 Result SharedMemoryDataConsumerHandle::ReaderImpl::read( |
| 231 void* data, | 269 void* data, |
| 232 size_t size, | 270 size_t size, |
| 233 Flags flags, | 271 Flags flags, |
| 234 size_t* read_size_to_return) { | 272 size_t* read_size_to_return) { |
| 235 base::AutoLock lock(context_->lock()); | 273 base::AutoLock lock(context_->lock()); |
| 236 | 274 |
| 237 size_t total_read_size = 0; | 275 size_t total_read_size = 0; |
| 238 *read_size_to_return = 0; | 276 *read_size_to_return = 0; |
| 277 | |
| 278 if (context_->is_two_phase_read_in_progress()) | |
| 279 context_->set_result(UnexpectedError); | |
|
hiroshige
2015/06/18 07:01:21
Is this change for setting errors on read()/beginR
yhirano
2015/06/18 08:13:33
Done. By the way, I added a condition to stabilize
| |
| 280 | |
| 239 if (context_->result() != Ok && context_->result() != Done) | 281 if (context_->result() != Ok && context_->result() != Done) |
| 240 return context_->result(); | 282 return context_->result(); |
| 241 | 283 |
| 242 while (!context_->IsEmpty() && total_read_size < size) { | 284 while (!context_->IsEmpty() && total_read_size < size) { |
| 243 const auto& top = context_->Top(); | 285 const auto& top = context_->Top(); |
| 244 size_t readable = top->length() - context_->first_offset(); | 286 size_t readable = top->length() - context_->first_offset(); |
| 245 size_t writable = size - total_read_size; | 287 size_t writable = size - total_read_size; |
| 246 size_t read_size = std::min(readable, writable); | 288 size_t read_size = std::min(readable, writable); |
| 247 const char* begin = top->payload() + context_->first_offset(); | 289 const char* begin = top->payload() + context_->first_offset(); |
| 248 std::copy(begin, begin + read_size, | 290 std::copy(begin, begin + read_size, |
| 249 static_cast<char*>(data) + total_read_size); | 291 static_cast<char*>(data) + total_read_size); |
| 250 total_read_size += read_size; | 292 total_read_size += read_size; |
| 251 context_->Consume(read_size); | 293 context_->Consume(read_size); |
| 252 } | 294 } |
| 253 *read_size_to_return = total_read_size; | 295 *read_size_to_return = total_read_size; |
| 254 return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait; | 296 return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait; |
| 255 } | 297 } |
| 256 | 298 |
| 257 Result SharedMemoryDataConsumerHandle::ReaderImpl::beginRead( | 299 Result SharedMemoryDataConsumerHandle::ReaderImpl::beginRead( |
| 258 const void** buffer, | 300 const void** buffer, |
| 259 Flags flags, | 301 Flags flags, |
| 260 size_t* available) { | 302 size_t* available) { |
| 261 *buffer = nullptr; | 303 *buffer = nullptr; |
| 262 *available = 0; | 304 *available = 0; |
| 263 | 305 |
| 264 base::AutoLock lock(context_->lock()); | 306 base::AutoLock lock(context_->lock()); |
| 265 | 307 |
| 308 if (context_->is_two_phase_read_in_progress()) | |
| 309 context_->set_result(UnexpectedError); | |
|
hiroshige
2015/06/18 07:01:21
ditto.
yhirano
2015/06/18 08:13:33
Done.
| |
| 310 | |
| 266 if (context_->result() != Ok && context_->result() != Done) | 311 if (context_->result() != Ok && context_->result() != Done) |
| 267 return context_->result(); | 312 return context_->result(); |
| 268 | 313 |
| 269 if (context_->IsEmpty()) | 314 if (context_->IsEmpty()) |
| 270 return context_->result() == Done ? Done : ShouldWait; | 315 return context_->result() == Done ? Done : ShouldWait; |
| 271 | 316 |
| 317 context_->set_is_two_phase_read_in_progress(true); | |
| 272 const auto& top = context_->Top(); | 318 const auto& top = context_->Top(); |
| 273 *buffer = top->payload() + context_->first_offset(); | 319 *buffer = top->payload() + context_->first_offset(); |
| 274 *available = top->length() - context_->first_offset(); | 320 *available = top->length() - context_->first_offset(); |
| 275 | 321 |
| 276 return Ok; | 322 return Ok; |
| 277 } | 323 } |
| 278 | 324 |
| 279 Result SharedMemoryDataConsumerHandle::ReaderImpl::endRead(size_t read_size) { | 325 Result SharedMemoryDataConsumerHandle::ReaderImpl::endRead(size_t read_size) { |
| 280 base::AutoLock lock(context_->lock()); | 326 base::AutoLock lock(context_->lock()); |
| 281 | 327 |
| 282 if (context_->IsEmpty()) | 328 if (!context_->is_two_phase_read_in_progress()) |
| 283 return UnexpectedError; | 329 return UnexpectedError; |
|
hiroshige
2015/06/18 07:01:20
Can/should we call ClearQueue() in this then claus
yhirano
2015/06/18 08:13:33
I do not want to do so, because it may complicate
yhirano
2015/06/18 08:14:51
Correction: I added early-clear when errored
hiroshige
2015/06/18 08:35:11
OK.
| |
| 284 | 330 |
| 285 context_->Consume(read_size); | 331 context_->set_is_two_phase_read_in_progress(false); |
| 332 if (context_->result() != Ok && context_->result() != Done) { | |
| 333 // We have an error, so we can discard the stored data. | |
| 334 context_->ClearQueue(); | |
| 335 } else { | |
| 336 context_->Consume(read_size); | |
| 337 } | |
| 338 | |
| 286 return Ok; | 339 return Ok; |
| 287 } | 340 } |
| 288 | 341 |
| 289 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( | 342 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( |
| 290 BackpressureMode mode, | 343 BackpressureMode mode, |
| 291 scoped_ptr<Writer>* writer) | 344 scoped_ptr<Writer>* writer) |
| 292 : context_(new Context) { | 345 : context_(new Context) { |
| 293 writer->reset(new Writer(context_, mode)); | 346 writer->reset(new Writer(context_, mode)); |
| 294 } | 347 } |
| 295 | 348 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 359 DCHECK(context_->IsReaderBoundToCurrentThread()); | 412 DCHECK(context_->IsReaderBoundToCurrentThread()); |
| 360 needs_unlock = true; | 413 needs_unlock = true; |
| 361 } | 414 } |
| 362 } | 415 } |
| 363 if (needs_unlock) { | 416 if (needs_unlock) { |
| 364 reader_.reset(); | 417 reader_.reset(); |
| 365 } | 418 } |
| 366 } | 419 } |
| 367 | 420 |
| 368 } // namespace content | 421 } // namespace content |
| OLD | NEW |