Chromium Code Reviews| Index: content/child/shared_memory_data_consumer_handle.cc |
| diff --git a/content/child/shared_memory_data_consumer_handle.cc b/content/child/shared_memory_data_consumer_handle.cc |
| index beb470d96d31e91d05214d1b13b4e1909ae242cc..01f9d5abd5fa072bcfb04bde17ea123054c37453 100644 |
| --- a/content/child/shared_memory_data_consumer_handle.cc |
| +++ b/content/child/shared_memory_data_consumer_handle.cc |
| @@ -49,10 +49,13 @@ using Result = blink::WebDataConsumerHandle::Result; |
| class SharedMemoryDataConsumerHandle::Context final |
| : public base::RefCountedThreadSafe<Context> { |
| public: |
| - Context() |
| + explicit Context(const base::Closure& on_clear) |
| : result_(Ok), |
| first_offset_(0), |
| client_(nullptr), |
| + writer_task_runner_(base::MessageLoop::current()->task_runner()), |
| + on_clear_(on_clear), |
| + is_on_clear_valid_(!on_clear_.is_null()), |
| is_handle_active_(true), |
| is_two_phase_read_in_progress_(false) {} |
| @@ -60,6 +63,10 @@ class SharedMemoryDataConsumerHandle::Context final |
| void ClearIfNecessary() { |
| if (!is_handle_locked() && !is_handle_active()) { |
| // No one is interested in the contents. |
| + if (is_on_clear_valid_) { |
| + // 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.
|
| + writer_task_runner_->PostTask(FROM_HERE, on_clear_); |
| + } |
| Clear(); |
| } |
| } |
| @@ -105,6 +112,22 @@ class SharedMemoryDataConsumerHandle::Context final |
| base::Bind(&Context::NotifyInternal, this, false)); |
| } |
| void Notify() { NotifyInternal(true); } |
| + void ResetOnClear() { |
| + if (on_clear_.is_null()) { |
| + DCHECK(!is_on_clear_valid_); |
| + return; |
| + } |
| + is_on_clear_valid_ = false; |
| + if (writer_task_runner_->BelongsToCurrentThread()) { |
| + // We can reset the closure immediately. |
| + on_clear_.Reset(); |
| + } else { |
| + // We need to reset |on_clear_| on the right thread because it might |
| + // lead to the object destruction. |
| + writer_task_runner_->PostTask(FROM_HERE, |
| + base::Bind(&Context::ResetOnClear, this)); |
| + } |
| + } |
| bool is_handle_locked() const { return notification_task_runner_; } |
| bool IsReaderBoundToCurrentThread() const { |
| return notification_task_runner_ && |
| @@ -159,10 +182,15 @@ class SharedMemoryDataConsumerHandle::Context final |
| queue_.clear(); |
| first_offset_ = 0; |
| client_ = nullptr; |
| + // 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.
|
| + // have an assert in the destructor. |
| + ResetOnClear(); |
| } |
| friend class base::RefCountedThreadSafe<Context>; |
| ~Context() { |
| + DCHECK(on_clear_.is_null()); |
| + |
| // This is necessary because the queue stores raw pointers. |
| Clear(); |
| } |
| @@ -177,6 +205,12 @@ class SharedMemoryDataConsumerHandle::Context final |
| size_t first_offset_; |
| Client* client_; |
| scoped_refptr<base::SingleThreadTaskRunner> notification_task_runner_; |
| + scoped_refptr<base::SingleThreadTaskRunner> writer_task_runner_; |
| + base::Closure on_clear_; |
| + // We need this boolean variable to remember if |on_clear_| is callable |
| + // 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
|
| + // |on_clear_.is_null()| is untrustworthy. |
| + 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
|
| bool is_handle_active_; |
| bool is_two_phase_read_in_progress_; |
| @@ -191,6 +225,8 @@ SharedMemoryDataConsumerHandle::Writer::Writer( |
| SharedMemoryDataConsumerHandle::Writer::~Writer() { |
| Close(); |
| + base::AutoLock lock(context_->lock()); |
| + context_->ResetOnClear(); |
| } |
| void SharedMemoryDataConsumerHandle::Writer::AddData( |
| @@ -234,6 +270,7 @@ void SharedMemoryDataConsumerHandle::Writer::Close() { |
| base::AutoLock lock(context_->lock()); |
| if (context_->result() == Ok) { |
| context_->set_result(Done); |
| + context_->ResetOnClear(); |
| needs_notification = context_->IsEmpty(); |
| } |
| } |
| @@ -260,6 +297,7 @@ void SharedMemoryDataConsumerHandle::Writer::Fail() { |
| context_->ClearQueue(); |
| } |
| + context_->ResetOnClear(); |
| needs_notification = true; |
| } |
| } |
| @@ -362,7 +400,14 @@ Result SharedMemoryDataConsumerHandle::ReaderImpl::endRead(size_t read_size) { |
| SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( |
| BackpressureMode mode, |
| scoped_ptr<Writer>* writer) |
| - : context_(new Context) { |
| + : SharedMemoryDataConsumerHandle(mode, base::Closure(), writer) { |
| +} |
| + |
| +SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( |
| + BackpressureMode mode, |
| + const base::Closure& on_clear, |
| + scoped_ptr<Writer>* writer) |
| + : context_(new Context(on_clear)) { |
| writer->reset(new Writer(context_, mode)); |
| } |