| 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 f11435ada87c22572379c59ce9b80f2e50c85b44..7bf404a5281e2884dc031534fb89343cb0e4db89 100644
 | 
| --- a/content/child/shared_memory_data_consumer_handle.cc
 | 
| +++ b/content/child/shared_memory_data_consumer_handle.cc
 | 
| @@ -46,6 +46,8 @@ class DelegateThreadSafeReceivedData final
 | 
|  
 | 
|  using Result = blink::WebDataConsumerHandle::Result;
 | 
|  
 | 
| +// All methods (except for ctor/dtor) must be called with |lock_| aquired
 | 
| +// unless otherwise stated.
 | 
|  class SharedMemoryDataConsumerHandle::Context final
 | 
|      : public base::RefCountedThreadSafe<Context> {
 | 
|   public:
 | 
| @@ -59,8 +61,12 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|          is_handle_active_(true),
 | 
|          is_two_phase_read_in_progress_(false) {}
 | 
|  
 | 
| -  bool IsEmpty() const { return queue_.empty(); }
 | 
| +  bool IsEmpty() const {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return queue_.empty();
 | 
| +  }
 | 
|    void ClearIfNecessary() {
 | 
| +    lock_.AssertAcquired();
 | 
|      if (!is_handle_locked() && !is_handle_active()) {
 | 
|        // No one is interested in the contents.
 | 
|        if (is_on_reader_detached_valid_) {
 | 
| @@ -73,20 +79,35 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      }
 | 
|    }
 | 
|    void ClearQueue() {
 | 
| +    lock_.AssertAcquired();
 | 
|      for (auto& data : queue_) {
 | 
|        delete data;
 | 
|      }
 | 
|      queue_.clear();
 | 
|      first_offset_ = 0;
 | 
|    }
 | 
| -  RequestPeer::ThreadSafeReceivedData* Top() { return queue_.front(); }
 | 
| +  RequestPeer::ThreadSafeReceivedData* Top() {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return queue_.front();
 | 
| +  }
 | 
|    void Push(scoped_ptr<RequestPeer::ThreadSafeReceivedData> data) {
 | 
| +    lock_.AssertAcquired();
 | 
|      queue_.push_back(data.release());
 | 
|    }
 | 
| -  size_t first_offset() const { return first_offset_; }
 | 
| -  Result result() const { return result_; }
 | 
| -  void set_result(Result r) { result_ = r; }
 | 
| +  size_t first_offset() const {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return first_offset_;
 | 
| +  }
 | 
| +  Result result() const {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return result_;
 | 
| +  }
 | 
| +  void set_result(Result r) {
 | 
| +    lock_.AssertAcquired();
 | 
| +    result_ = r;
 | 
| +  }
 | 
|    void AcquireReaderLock(Client* client) {
 | 
| +    lock_.AssertAcquired();
 | 
|      DCHECK(!notification_task_runner_);
 | 
|      DCHECK(!client_);
 | 
|      notification_task_runner_ = base::ThreadTaskRunnerHandle::Get();
 | 
| @@ -99,11 +120,13 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      }
 | 
|    }
 | 
|    void ReleaseReaderLock() {
 | 
| +    lock_.AssertAcquired();
 | 
|      DCHECK(notification_task_runner_);
 | 
|      notification_task_runner_ = nullptr;
 | 
|      client_ = nullptr;
 | 
|    }
 | 
|    void PostNotify() {
 | 
| +    lock_.AssertAcquired();
 | 
|      auto runner = notification_task_runner_;
 | 
|      if (!runner)
 | 
|        return;
 | 
| @@ -113,10 +136,12 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      runner->PostTask(FROM_HERE,
 | 
|                       base::Bind(&Context::NotifyInternal, this, false));
 | 
|    }
 | 
| +  // Must be called with |lock_| not aquired.
 | 
|    void Notify() { NotifyInternal(true); }
 | 
|    // This function doesn't work in the destructor if |on_reader_detached_| is
 | 
|    // not null.
 | 
|    void ResetOnReaderDetached() {
 | 
| +    lock_.AssertAcquired();
 | 
|      if (on_reader_detached_.is_null()) {
 | 
|        DCHECK(!is_on_reader_detached_valid_);
 | 
|        return;
 | 
| @@ -132,14 +157,25 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|            FROM_HERE, base::Bind(&Context::ResetOnReaderDetachedWithLock, this));
 | 
|      }
 | 
|    }
 | 
| -  bool is_handle_locked() const { return notification_task_runner_; }
 | 
| +  bool is_handle_locked() const {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return notification_task_runner_;
 | 
| +  }
 | 
|    bool IsReaderBoundToCurrentThread() const {
 | 
| +    lock_.AssertAcquired();
 | 
|      return notification_task_runner_ &&
 | 
|             notification_task_runner_->BelongsToCurrentThread();
 | 
|    }
 | 
| -  bool is_handle_active() const { return is_handle_active_; }
 | 
| -  void set_is_handle_active(bool b) { is_handle_active_ = b; }
 | 
| +  bool is_handle_active() const {
 | 
| +    lock_.AssertAcquired();
 | 
| +    return is_handle_active_;
 | 
| +  }
 | 
| +  void set_is_handle_active(bool b) {
 | 
| +    lock_.AssertAcquired();
 | 
| +    is_handle_active_ = b;
 | 
| +  }
 | 
|    void Consume(size_t s) {
 | 
| +    lock_.AssertAcquired();
 | 
|      first_offset_ += s;
 | 
|      auto top = Top();
 | 
|      if (static_cast<size_t>(top->length()) <= first_offset_) {
 | 
| @@ -149,18 +185,24 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      }
 | 
|    }
 | 
|    bool is_two_phase_read_in_progress() const {
 | 
| +    lock_.AssertAcquired();
 | 
|      return is_two_phase_read_in_progress_;
 | 
|    }
 | 
|    void set_is_two_phase_read_in_progress(bool b) {
 | 
| +    lock_.AssertAcquired();
 | 
|      is_two_phase_read_in_progress_ = b;
 | 
|    }
 | 
| +  // Can be called with |lock_| not aquired.
 | 
|    base::Lock& lock() { return lock_; }
 | 
|  
 | 
|   private:
 | 
| +  // Must be called with |lock_| not aquired.
 | 
|    void NotifyInternal(bool repost) {
 | 
| -    // Note that this function is not protected by |lock_|.
 | 
| -
 | 
| -    auto runner = notification_task_runner_;
 | 
| +    scoped_refptr<base::SingleThreadTaskRunner> runner;
 | 
| +    {
 | 
| +      base::AutoLock lock(lock_);
 | 
| +      runner = notification_task_runner_;
 | 
| +    }
 | 
|      if (!runner)
 | 
|        return;
 | 
|  
 | 
| @@ -180,6 +222,7 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      }
 | 
|    }
 | 
|    void Clear() {
 | 
| +    lock_.AssertAcquired();
 | 
|      for (auto& data : queue_) {
 | 
|        delete data;
 | 
|      }
 | 
| @@ -190,6 +233,7 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|      // null. We have an assert in the destructor.
 | 
|      ResetOnReaderDetached();
 | 
|    }
 | 
| +  // Must be called with |lock_| not aquired.
 | 
|    void ResetOnReaderDetachedWithLock() {
 | 
|      base::AutoLock lock(lock_);
 | 
|      ResetOnReaderDetached();
 | 
| @@ -197,6 +241,7 @@ class SharedMemoryDataConsumerHandle::Context final
 | 
|  
 | 
|    friend class base::RefCountedThreadSafe<Context>;
 | 
|    ~Context() {
 | 
| +    base::AutoLock lock(lock_);
 | 
|      DCHECK(on_reader_detached_.is_null());
 | 
|  
 | 
|      // This is necessary because the queue stores raw pointers.
 | 
| @@ -273,44 +318,33 @@ void SharedMemoryDataConsumerHandle::Writer::AddData(
 | 
|  }
 | 
|  
 | 
|  void SharedMemoryDataConsumerHandle::Writer::Close() {
 | 
| -  bool needs_notification = false;
 | 
| -
 | 
| -  {
 | 
| -    base::AutoLock lock(context_->lock());
 | 
| -    if (context_->result() == Ok) {
 | 
| -      context_->set_result(Done);
 | 
| -      context_->ResetOnReaderDetached();
 | 
| -      needs_notification = context_->IsEmpty();
 | 
| +  base::AutoLock lock(context_->lock());
 | 
| +  if (context_->result() == Ok) {
 | 
| +    context_->set_result(Done);
 | 
| +    context_->ResetOnReaderDetached();
 | 
| +    if (context_->IsEmpty()) {
 | 
| +      // We cannot issue the notification synchronously because this function
 | 
| +      // can be called in the client's callback.
 | 
| +      context_->PostNotify();
 | 
|      }
 | 
|    }
 | 
| -  if (needs_notification) {
 | 
| -    // We cannot issue the notification synchronously because this function can
 | 
| -    // be called in the client's callback.
 | 
| -    context_->PostNotify();
 | 
| -  }
 | 
|  }
 | 
|  
 | 
|  void SharedMemoryDataConsumerHandle::Writer::Fail() {
 | 
| -  bool needs_notification = false;
 | 
| -  {
 | 
| -    base::AutoLock lock(context_->lock());
 | 
| -    if (context_->result() == Ok) {
 | 
| -      // TODO(yhirano): Use an appropriate error code other than
 | 
| -      // UnexpectedError.
 | 
| -      context_->set_result(UnexpectedError);
 | 
| -
 | 
| -      if (context_->is_two_phase_read_in_progress()) {
 | 
| -        // If we are in two-phase read session, we cannot discard the data. We
 | 
| -        // will clear the queue at the end of the session.
 | 
| -      } else {
 | 
| -        context_->ClearQueue();
 | 
| -      }
 | 
| +  base::AutoLock lock(context_->lock());
 | 
| +  if (context_->result() == Ok) {
 | 
| +    // TODO(yhirano): Use an appropriate error code other than
 | 
| +    // UnexpectedError.
 | 
| +    context_->set_result(UnexpectedError);
 | 
|  
 | 
| -      context_->ResetOnReaderDetached();
 | 
| -      needs_notification = true;
 | 
| +    if (context_->is_two_phase_read_in_progress()) {
 | 
| +      // If we are in two-phase read session, we cannot discard the data. We
 | 
| +      // will clear the queue at the end of the session.
 | 
| +    } else {
 | 
| +      context_->ClearQueue();
 | 
|      }
 | 
| -  }
 | 
| -  if (needs_notification) {
 | 
| +
 | 
| +    context_->ResetOnReaderDetached();
 | 
|      // We cannot issue the notification synchronously because this function can
 | 
|      // be called in the client's callback.
 | 
|      context_->PostNotify();
 | 
| 
 |