Chromium Code Reviews| Index: mojo/edk/system/raw_channel.cc |
| diff --git a/mojo/edk/system/raw_channel.cc b/mojo/edk/system/raw_channel.cc |
| index 819762b301641ba7dba8030d134da1ae2abbaa38..554c1fdabf7dac4f0da442b12c71a13639db2cc7 100644 |
| --- a/mojo/edk/system/raw_channel.cc |
| +++ b/mojo/edk/system/raw_channel.cc |
| @@ -170,6 +170,7 @@ RawChannel::RawChannel() |
| write_ready_(false), |
| write_stopped_(false), |
| error_occurred_(false), |
| + pending_error_(false), |
| weak_ptr_factory_(this) { |
| read_buffer_.reset(new ReadBuffer); |
| write_buffer_.reset(new WriteBuffer()); |
| @@ -330,11 +331,12 @@ bool RawChannel::SendQueuedMessagesNoLock() { |
| if (io_result == IO_PENDING) |
| return true; |
| - bool result = OnWriteCompletedNoLock(io_result, platform_handles_written, |
| - bytes_written); |
| + bool result = OnWriteCompletedInternalNoLock( |
| + io_result, platform_handles_written, bytes_written); |
| if (!result) { |
| // Even if we're on the I/O thread, don't call |OnError()| in the nested |
| // context. |
| + pending_error_ = true; |
|
yzshen1
2015/10/14 18:23:45
pending_error_ is never reset to false, is that in
jam
2015/10/14 20:01:44
yep
|
| message_loop_for_io_->PostTask( |
| FROM_HERE, |
| base::Bind(&RawChannel::LockAndCallOnError, |
| @@ -377,10 +379,13 @@ void RawChannel::SetSerializedData( |
| } |
| void RawChannel::OnReadCompleted(IOResult io_result, size_t bytes_read) { |
| - DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io_); |
| - |
| base::AutoLock locker(read_lock_); |
| + OnReadCompletedNoLock(io_result, bytes_read); |
| +} |
| +void RawChannel::OnReadCompletedNoLock(IOResult io_result, size_t bytes_read) { |
| + DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io_); |
| + read_lock_.AssertAcquired(); |
| // Keep reading data in a loop, and dispatch messages if enough data is |
| // received. Exit the loop if any of the following happens: |
| // - one or more messages were dispatched; |
| @@ -440,20 +445,21 @@ void RawChannel::OnReadCompleted(IOResult io_result, size_t bytes_read) { |
| void RawChannel::OnWriteCompleted(IOResult io_result, |
| size_t platform_handles_written, |
| size_t bytes_written) { |
| + base::AutoLock locker(write_lock_); |
| + OnWriteCompletedNoLock(io_result, platform_handles_written, bytes_written); |
| +} |
| + |
| +void RawChannel::OnWriteCompletedNoLock(IOResult io_result, |
| + size_t platform_handles_written, |
| + size_t bytes_written) { |
| DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io_); |
| + write_lock_.AssertAcquired(); |
| DCHECK_NE(io_result, IO_PENDING); |
| - bool did_fail = false; |
| - { |
| - base::AutoLock locker(write_lock_); |
| - did_fail = !OnWriteCompletedNoLock(io_result, platform_handles_written, |
| - bytes_written); |
| - } |
| - |
| - if (did_fail) { |
| + bool did_fail = !OnWriteCompletedInternalNoLock( |
| + io_result, platform_handles_written, bytes_written); |
| + if (did_fail) |
| LockAndCallOnError(Delegate::ERROR_WRITE); |
| - return; // |this| may have been destroyed in |CallOnError()|. |
| - } |
| } |
| void RawChannel::SerializeReadBuffer(size_t additional_bytes_read, |
| @@ -465,9 +471,9 @@ void RawChannel::SerializeReadBuffer(size_t additional_bytes_read, |
| } |
| void RawChannel::SerializeWriteBuffer( |
| - std::vector<char>* buffer, |
| size_t additional_bytes_written, |
| - size_t additional_platform_handles_written) { |
| + size_t additional_platform_handles_written, |
| + std::vector<char>* buffer) { |
| if (write_buffer_->IsEmpty()) { |
| DCHECK_EQ(0u, additional_bytes_written); |
| DCHECK_EQ(0u, additional_platform_handles_written); |
| @@ -497,6 +503,7 @@ void RawChannel::EnqueueMessageNoLock(scoped_ptr<MessageInTransit> message) { |
| bool RawChannel::OnReadMessageForRawChannel( |
| const MessageInTransit::View& message_view) { |
| if (message_view.type() == MessageInTransit::Type::RAW_CHANNEL_QUIT) { |
| + pending_error_ = true; |
| message_loop_for_io_->PostTask( |
| FROM_HERE, base::Bind(&RawChannel::LockAndCallOnError, |
| weak_ptr_factory_.GetWeakPtr(), |
| @@ -530,9 +537,14 @@ RawChannel::Delegate::Error RawChannel::ReadIOResultToError( |
| void RawChannel::CallOnError(Delegate::Error error) { |
| DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io_); |
| read_lock_.AssertAcquired(); |
| + bool called_on_error_before = error_occurred_; |
| error_occurred_ = true; |
| if (delegate_) { |
| - delegate_->OnError(error); |
| + // We only want to call OnError once. The delegate may have posted a task |
| + // to call Shutdown though, so we don't want to null delegate_ the first |
| + // time and have two shutdown calls. |
| + if (!called_on_error_before) |
| + delegate_->OnError(error); |
| } else { |
| // We depend on delegate to delete since it could be waiting to call |
| // ReleaseHandle. |
| @@ -547,9 +559,9 @@ void RawChannel::LockAndCallOnError(Delegate::Error error) { |
| CallOnError(error); |
| } |
| -bool RawChannel::OnWriteCompletedNoLock(IOResult io_result, |
| - size_t platform_handles_written, |
| - size_t bytes_written) { |
| +bool RawChannel::OnWriteCompletedInternalNoLock(IOResult io_result, |
| + size_t platform_handles_written, |
| + size_t bytes_written) { |
| write_lock_.AssertAcquired(); |
| DCHECK(!write_buffer_->message_queue_.IsEmpty()); |