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()); |