Index: mojo/system/raw_channel_win.cc |
diff --git a/mojo/system/raw_channel_win.cc b/mojo/system/raw_channel_win.cc |
index fee6c86f854de822676a585885fcddd084e1f659..5dcb418bf00a17bf107b164f6f47be2978724bb7 100644 |
--- a/mojo/system/raw_channel_win.cc |
+++ b/mojo/system/raw_channel_win.cc |
@@ -9,6 +9,7 @@ |
#include "base/auto_reset.h" |
#include "base/bind.h" |
#include "base/compiler_specific.h" |
+#include "base/debug/alias.h" |
#include "base/lazy_instance.h" |
#include "base/location.h" |
#include "base/logging.h" |
@@ -88,6 +89,30 @@ class RawChannelWin : public RawChannel { |
// - there is no pending write. |
class RawChannelIOHandler : public base::MessageLoopForIO::IOHandler { |
public: |
+ // TODO(yzshen): This is for debugging http://crbug.com/385795. |
+ // This code should be removed once the issue is fixed or nothing is |
+ // revealed by it. (No later than Aug 1, 2014.) |
+ struct WriteStats { |
+ WriteStats() |
+ : write_no_lock_call(0), |
+ schedule_write_no_lock_call(0), |
+ os_write_call(0), |
+ os_write_pending(0), |
+ os_write_failure(0), |
+ task_posted_by_schedule_write(0), |
+ write_completion(0), |
+ write_completion_failure(0) {} |
+ |
+ uint32_t write_no_lock_call; |
+ uint32_t schedule_write_no_lock_call; |
+ uint32_t os_write_call; |
+ uint32_t os_write_pending; |
+ uint32_t os_write_failure; |
+ uint32_t task_posted_by_schedule_write; |
+ uint32_t write_completion; |
+ uint32_t write_completion_failure; |
+ }; |
+ |
RawChannelIOHandler(RawChannelWin* owner, |
embedder::ScopedPlatformHandle handle); |
@@ -105,6 +130,7 @@ class RawChannelWin : public RawChannel { |
base::MessageLoopForIO::IOContext* write_context_no_lock(); |
// Instructs the object to wait for an |OnIOCompleted()| notification. |
void OnPendingWriteStartedNoLock(); |
+ WriteStats* write_stats_no_lock(); |
// |base::MessageLoopForIO::IOHandler| implementation: |
// Must be called on the I/O thread. It could be called before or after |
@@ -156,6 +182,8 @@ class RawChannelWin : public RawChannel { |
bool pending_write_; |
base::MessageLoopForIO::IOContext write_context_; |
+ WriteStats write_stats_; |
+ |
DISALLOW_COPY_AND_ASSIGN(RawChannelIOHandler); |
}; |
@@ -199,55 +227,74 @@ RawChannelWin::RawChannelIOHandler::RawChannelIOHandler( |
} |
RawChannelWin::RawChannelIOHandler::~RawChannelIOHandler() { |
- DCHECK(ShouldSelfDestruct()); |
+ CHECK(ShouldSelfDestruct()); |
+ |
+ VLOG(4) << "write_no_lock_call: " << write_stats_.write_no_lock_call << "\n" |
+ << "schedule_write_no_lock_call: " |
+ << write_stats_.schedule_write_no_lock_call << "\n" |
+ << "os_write_call: " << write_stats_.os_write_call << "\n" |
+ << "os_write_pending: " << write_stats_.os_write_pending << "\n" |
+ << "os_write_failure: " << write_stats_.os_write_failure << "\n" |
+ << "task_posted_by_schedule_write: " |
+ << write_stats_.task_posted_by_schedule_write << "\n" |
+ << "write_completion: " << write_stats_.write_completion << "\n" |
+ << "write_completion_failure: " |
+ << write_stats_.write_completion_failure << "\n"; |
} |
bool RawChannelWin::RawChannelIOHandler::pending_read() const { |
- DCHECK(owner_); |
- DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
+ CHECK(owner_); |
+ CHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
return pending_read_; |
} |
base::MessageLoopForIO::IOContext* |
RawChannelWin::RawChannelIOHandler::read_context() { |
- DCHECK(owner_); |
- DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
+ CHECK(owner_); |
+ CHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
return &read_context_; |
} |
void RawChannelWin::RawChannelIOHandler::OnPendingReadStarted() { |
- DCHECK(owner_); |
- DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
- DCHECK(!pending_read_); |
+ CHECK(owner_); |
+ CHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
+ CHECK(!pending_read_); |
pending_read_ = true; |
} |
bool RawChannelWin::RawChannelIOHandler::pending_write_no_lock() const { |
- DCHECK(owner_); |
+ CHECK(owner_); |
owner_->write_lock().AssertAcquired(); |
return pending_write_; |
} |
base::MessageLoopForIO::IOContext* |
RawChannelWin::RawChannelIOHandler::write_context_no_lock() { |
- DCHECK(owner_); |
+ CHECK(owner_); |
owner_->write_lock().AssertAcquired(); |
return &write_context_; |
} |
void RawChannelWin::RawChannelIOHandler::OnPendingWriteStartedNoLock() { |
- DCHECK(owner_); |
+ CHECK(owner_); |
owner_->write_lock().AssertAcquired(); |
- DCHECK(!pending_write_); |
+ CHECK(!pending_write_); |
pending_write_ = true; |
} |
+RawChannelWin::RawChannelIOHandler::WriteStats* |
+RawChannelWin::RawChannelIOHandler::write_stats_no_lock() { |
+ CHECK(owner_); |
+ owner_->write_lock().AssertAcquired(); |
+ return &write_stats_; |
+} |
+ |
void RawChannelWin::RawChannelIOHandler::OnIOCompleted( |
base::MessageLoopForIO::IOContext* context, |
DWORD bytes_transferred, |
DWORD error) { |
- DCHECK(!owner_ || |
- base::MessageLoop::current() == owner_->message_loop_for_io()); |
+ CHECK(!owner_ || |
+ base::MessageLoop::current() == owner_->message_loop_for_io()); |
{ |
// Suppress self-destruction inside |OnReadCompleted()|, etc. (in case they |
@@ -269,8 +316,8 @@ void RawChannelWin::RawChannelIOHandler::OnIOCompleted( |
void RawChannelWin::RawChannelIOHandler::DetachFromOwnerNoLock( |
scoped_ptr<ReadBuffer> read_buffer, |
scoped_ptr<WriteBuffer> write_buffer) { |
- DCHECK(owner_); |
- DCHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
+ CHECK(owner_); |
+ CHECK_EQ(base::MessageLoop::current(), owner_->message_loop_for_io()); |
owner_->write_lock().AssertAcquired(); |
// If read/write is pending, we have to retain the corresponding buffer. |
@@ -294,9 +341,9 @@ bool RawChannelWin::RawChannelIOHandler::ShouldSelfDestruct() const { |
void RawChannelWin::RawChannelIOHandler::OnReadCompleted(DWORD bytes_read, |
DWORD error) { |
- DCHECK(!owner_ || |
- base::MessageLoop::current() == owner_->message_loop_for_io()); |
- DCHECK(suppress_self_destruct_); |
+ CHECK(!owner_ || |
+ base::MessageLoop::current() == owner_->message_loop_for_io()); |
+ CHECK(suppress_self_destruct_); |
CHECK(pending_read_); |
pending_read_ = false; |
@@ -304,24 +351,33 @@ void RawChannelWin::RawChannelIOHandler::OnReadCompleted(DWORD bytes_read, |
return; |
if (error != ERROR_SUCCESS) { |
- DCHECK_EQ(bytes_read, 0u); |
+ CHECK_EQ(bytes_read, 0u); |
LOG_IF(ERROR, error != ERROR_BROKEN_PIPE) |
<< "ReadFile: " << logging::SystemErrorCodeToString(error); |
owner_->OnReadCompleted(false, 0); |
} else { |
- DCHECK_GT(bytes_read, 0u); |
+ CHECK_GT(bytes_read, 0u); |
owner_->OnReadCompleted(true, bytes_read); |
} |
} |
void RawChannelWin::RawChannelIOHandler::OnWriteCompleted(DWORD bytes_written, |
DWORD error) { |
- DCHECK(!owner_ || |
- base::MessageLoop::current() == owner_->message_loop_for_io()); |
- DCHECK(suppress_self_destruct_); |
+ CHECK(!owner_ || |
+ base::MessageLoop::current() == owner_->message_loop_for_io()); |
+ CHECK(suppress_self_destruct_); |
+ |
+ WriteStats stack_copy; |
+ base::debug::Alias(&stack_copy); |
if (!owner_) { |
// No lock needed. |
+ |
+ write_stats_.write_completion++; |
+ if (error != ERROR_SUCCESS) |
+ write_stats_.write_completion_failure++; |
+ stack_copy = write_stats_; |
+ |
CHECK(pending_write_); |
pending_write_ = false; |
return; |
@@ -329,6 +385,12 @@ void RawChannelWin::RawChannelIOHandler::OnWriteCompleted(DWORD bytes_written, |
{ |
base::AutoLock locker(owner_->write_lock()); |
+ |
+ write_stats_.write_completion++; |
+ if (error != ERROR_SUCCESS) |
+ write_stats_.write_completion_failure++; |
+ stack_copy = write_stats_; |
+ |
CHECK(pending_write_); |
pending_write_ = false; |
} |
@@ -346,11 +408,11 @@ RawChannelWin::RawChannelWin(embedder::ScopedPlatformHandle handle) |
io_handler_(NULL), |
skip_completion_port_on_success_( |
g_vista_or_higher_functions.Get().is_vista_or_higher()) { |
- DCHECK(handle_.is_valid()); |
+ CHECK(handle_.is_valid()); |
} |
RawChannelWin::~RawChannelWin() { |
- DCHECK(!io_handler_); |
+ CHECK(!io_handler_); |
} |
size_t RawChannelWin::GetSerializedPlatformHandleSize() const { |
@@ -359,9 +421,9 @@ size_t RawChannelWin::GetSerializedPlatformHandleSize() const { |
} |
RawChannel::IOResult RawChannelWin::Read(size_t* bytes_read) { |
- DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
- DCHECK(io_handler_); |
- DCHECK(!io_handler_->pending_read()); |
+ CHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
+ CHECK(io_handler_); |
+ CHECK(!io_handler_->pending_read()); |
char* buffer = NULL; |
size_t bytes_to_read = 0; |
@@ -374,7 +436,7 @@ RawChannel::IOResult RawChannelWin::Read(size_t* bytes_read) { |
&bytes_read_dword, |
&io_handler_->read_context()->overlapped); |
if (!result) { |
- DCHECK_EQ(bytes_read_dword, 0u); |
+ CHECK_EQ(bytes_read_dword, 0u); |
DWORD error = GetLastError(); |
if (error != ERROR_IO_PENDING) { |
LOG_IF(ERROR, error != ERROR_BROKEN_PIPE) |
@@ -402,14 +464,14 @@ RawChannel::IOResult RawChannelWin::Read(size_t* bytes_read) { |
} |
RawChannel::IOResult RawChannelWin::ScheduleRead() { |
- DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
- DCHECK(io_handler_); |
- DCHECK(!io_handler_->pending_read()); |
+ CHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
+ CHECK(io_handler_); |
+ CHECK(!io_handler_->pending_read()); |
size_t bytes_read = 0; |
IOResult io_result = Read(&bytes_read); |
if (io_result == IO_SUCCEEDED) { |
- DCHECK(skip_completion_port_on_success_); |
+ CHECK(skip_completion_port_on_success_); |
// We have finished reading successfully. Queue a notification manually. |
io_handler_->OnPendingReadStarted(); |
@@ -441,8 +503,15 @@ RawChannel::IOResult RawChannelWin::WriteNoLock( |
size_t* bytes_written) { |
write_lock().AssertAcquired(); |
- DCHECK(io_handler_); |
- DCHECK(!io_handler_->pending_write_no_lock()); |
+ RawChannelIOHandler::WriteStats stack_copy( |
+ *io_handler_->write_stats_no_lock()); |
+ base::debug::Alias(&stack_copy); |
+ |
+ io_handler_->write_stats_no_lock()->write_no_lock_call++; |
+ stack_copy.write_no_lock_call++; |
+ |
+ CHECK(io_handler_); |
+ CHECK(!io_handler_->pending_write_no_lock()); |
if (write_buffer_no_lock()->HavePlatformHandlesToSend()) { |
// TODO(vtl): Implement. |
@@ -451,7 +520,10 @@ RawChannel::IOResult RawChannelWin::WriteNoLock( |
std::vector<WriteBuffer::Buffer> buffers; |
write_buffer_no_lock()->GetBuffers(&buffers); |
- DCHECK(!buffers.empty()); |
+ CHECK(!buffers.empty()); |
+ |
+ io_handler_->write_stats_no_lock()->os_write_call++; |
+ stack_copy.os_write_call++; |
// TODO(yzshen): Handle multi-segment writes more efficiently. |
DWORD bytes_written_dword = 0; |
@@ -460,9 +532,18 @@ RawChannel::IOResult RawChannelWin::WriteNoLock( |
static_cast<DWORD>(buffers[0].size), |
&bytes_written_dword, |
&io_handler_->write_context_no_lock()->overlapped); |
- if (!result && GetLastError() != ERROR_IO_PENDING) { |
- PLOG(ERROR) << "WriteFile"; |
- return IO_FAILED; |
+ |
+ if (!result) { |
+ if (GetLastError() == ERROR_IO_PENDING) { |
+ io_handler_->write_stats_no_lock()->os_write_pending++; |
+ stack_copy.os_write_pending++; |
+ } else { |
+ io_handler_->write_stats_no_lock()->os_write_failure++; |
+ stack_copy.os_write_failure++; |
+ |
+ PLOG(ERROR) << "WriteFile"; |
+ return IO_FAILED; |
+ } |
} |
if (result && skip_completion_port_on_success_) { |
@@ -487,18 +568,29 @@ RawChannel::IOResult RawChannelWin::WriteNoLock( |
RawChannel::IOResult RawChannelWin::ScheduleWriteNoLock() { |
write_lock().AssertAcquired(); |
- DCHECK(io_handler_); |
- DCHECK(!io_handler_->pending_write_no_lock()); |
+ RawChannelIOHandler::WriteStats stack_copy( |
+ *io_handler_->write_stats_no_lock()); |
+ base::debug::Alias(&stack_copy); |
+ |
+ io_handler_->write_stats_no_lock()->schedule_write_no_lock_call++; |
+ stack_copy.schedule_write_no_lock_call++; |
+ |
+ CHECK(io_handler_); |
+ CHECK(!io_handler_->pending_write_no_lock()); |
// TODO(vtl): Do something with |platform_handles_written|. |
size_t platform_handles_written = 0; |
size_t bytes_written = 0; |
IOResult io_result = WriteNoLock(&platform_handles_written, &bytes_written); |
if (io_result == IO_SUCCEEDED) { |
- DCHECK(skip_completion_port_on_success_); |
+ CHECK(skip_completion_port_on_success_); |
// We have finished writing successfully. Queue a notification manually. |
io_handler_->OnPendingWriteStartedNoLock(); |
+ |
+ io_handler_->write_stats_no_lock()->task_posted_by_schedule_write++; |
+ stack_copy.task_posted_by_schedule_write++; |
+ |
// |io_handler_| won't go away before that task is run, so it is safe to use |
// |base::Unretained()|. |
message_loop_for_io()->PostTask( |
@@ -515,16 +607,16 @@ RawChannel::IOResult RawChannelWin::ScheduleWriteNoLock() { |
} |
bool RawChannelWin::OnInit() { |
- DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
+ CHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
- DCHECK(handle_.is_valid()); |
+ CHECK(handle_.is_valid()); |
if (skip_completion_port_on_success_ && |
!g_vista_or_higher_functions.Get().SetFileCompletionNotificationModes( |
handle_.get().handle, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) { |
return false; |
} |
- DCHECK(!io_handler_); |
+ CHECK(!io_handler_); |
io_handler_ = new RawChannelIOHandler(this, handle_.Pass()); |
return true; |
@@ -532,8 +624,8 @@ bool RawChannelWin::OnInit() { |
void RawChannelWin::OnShutdownNoLock(scoped_ptr<ReadBuffer> read_buffer, |
scoped_ptr<WriteBuffer> write_buffer) { |
- DCHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
- DCHECK(io_handler_); |
+ CHECK_EQ(base::MessageLoop::current(), message_loop_for_io()); |
+ CHECK(io_handler_); |
write_lock().AssertAcquired(); |