Index: mojo/message_pump/message_pump_mojo.cc |
diff --git a/mojo/common/message_pump_mojo.cc b/mojo/message_pump/message_pump_mojo.cc |
similarity index 68% |
rename from mojo/common/message_pump_mojo.cc |
rename to mojo/message_pump/message_pump_mojo.cc |
index afbf8f983b8fb4b57de6d2982a0a59bd7d600840..471a0ad8332741702f947edc443e12cf78a0e3f0 100644 |
--- a/mojo/common/message_pump_mojo.cc |
+++ b/mojo/message_pump/message_pump_mojo.cc |
@@ -2,25 +2,28 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-#include "mojo/common/message_pump_mojo.h" |
+#include "mojo/message_pump/message_pump_mojo.h" |
#include <algorithm> |
#include <vector> |
#include "base/debug/alias.h" |
-#include "base/lazy_instance.h" |
#include "base/logging.h" |
#include "base/threading/thread_local.h" |
#include "base/time/time.h" |
-#include "mojo/common/message_pump_mojo_handler.h" |
-#include "mojo/common/time_helper.h" |
+#include "mojo/message_pump/message_pump_mojo_handler.h" |
+#include "mojo/message_pump/time_helper.h" |
+#include "mojo/public/cpp/system/message_pipe.h" |
+#include "mojo/public/cpp/system/wait.h" |
namespace mojo { |
namespace common { |
namespace { |
-base::LazyInstance<base::ThreadLocalPointer<MessagePumpMojo> >::Leaky |
- g_tls_current_pump = LAZY_INSTANCE_INITIALIZER; |
+base::ThreadLocalPointer<MessagePumpMojo>* CurrentPump() { |
+ static auto* tls = new base::ThreadLocalPointer<MessagePumpMojo>; |
+ return tls; |
+} |
MojoDeadline TimeTicksToMojoDeadline(base::TimeTicks time_ticks, |
base::TimeTicks now) { |
@@ -44,7 +47,7 @@ struct MessagePumpMojo::WaitState { |
struct MessagePumpMojo::RunState { |
RunState() : should_quit(false) { |
- CreateMessagePipe(NULL, &read_handle, &write_handle); |
+ CreateMessagePipe(nullptr, &read_handle, &write_handle); |
} |
base::TimeTicks delayed_work_time; |
@@ -53,18 +56,22 @@ struct MessagePumpMojo::RunState { |
ScopedMessagePipeHandle read_handle; |
ScopedMessagePipeHandle write_handle; |
+ // Cached structures to avoid the heap allocation cost of std::vector<>. |
+ scoped_ptr<WaitState> wait_state; |
+ scoped_ptr<HandleToHandlerList> cloned_handlers; |
+ |
bool should_quit; |
}; |
-MessagePumpMojo::MessagePumpMojo() : run_state_(NULL), next_handler_id_(0) { |
+MessagePumpMojo::MessagePumpMojo() : run_state_(nullptr), next_handler_id_(0) { |
DCHECK(!current()) |
<< "There is already a MessagePumpMojo instance on this thread."; |
- g_tls_current_pump.Pointer()->Set(this); |
+ CurrentPump()->Set(this); |
} |
MessagePumpMojo::~MessagePumpMojo() { |
DCHECK_EQ(this, current()); |
- g_tls_current_pump.Pointer()->Set(NULL); |
+ CurrentPump()->Set(nullptr); |
} |
// static |
@@ -74,7 +81,7 @@ scoped_ptr<base::MessagePump> MessagePumpMojo::Create() { |
// static |
MessagePumpMojo* MessagePumpMojo::current() { |
- return g_tls_current_pump.Pointer()->Get(); |
+ return CurrentPump()->Get(); |
} |
void MessagePumpMojo::AddHandler(MessagePumpMojoHandler* handler, |
@@ -110,7 +117,7 @@ void MessagePumpMojo::Run(Delegate* delegate) { |
// TODO: better deal with error handling. |
CHECK(run_state.read_handle.is_valid()); |
CHECK(run_state.write_handle.is_valid()); |
- RunState* old_state = NULL; |
+ RunState* old_state = nullptr; |
{ |
base::AutoLock auto_lock(run_state_lock_); |
old_state = run_state_; |
@@ -172,47 +179,75 @@ void MessagePumpMojo::DoRunLoop(RunState* run_state, Delegate* delegate) { |
bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { |
const MojoDeadline deadline = block ? GetDeadlineForWait(run_state) : 0; |
- const WaitState wait_state = GetWaitState(run_state); |
+ if (!run_state_->wait_state) |
+ run_state_->wait_state.reset(new WaitState); |
+ GetWaitState(run_state, run_state_->wait_state.get()); |
const WaitManyResult wait_many_result = |
- WaitMany(wait_state.handles, wait_state.wait_signals, deadline, nullptr); |
+ WaitMany(run_state_->wait_state->handles, |
+ run_state_->wait_state->wait_signals, deadline, nullptr); |
const MojoResult result = wait_many_result.result; |
bool did_work = true; |
if (result == MOJO_RESULT_OK) { |
if (wait_many_result.index == 0) { |
// Control pipe was written to. |
- ReadMessageRaw(run_state.read_handle.get(), NULL, NULL, NULL, NULL, |
- MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
+ ReadMessageRaw(run_state.read_handle.get(), nullptr, nullptr, nullptr, |
+ nullptr, MOJO_READ_MESSAGE_FLAG_MAY_DISCARD); |
} else { |
- DCHECK(handlers_.find(wait_state.handles[wait_many_result.index]) != |
+ DCHECK(handlers_.find( |
+ run_state_->wait_state->handles[wait_many_result.index]) != |
handlers_.end()); |
WillSignalHandler(); |
- handlers_[wait_state.handles[wait_many_result.index]] |
- .handler->OnHandleReady(wait_state.handles[wait_many_result.index]); |
+ handlers_[run_state_->wait_state->handles[wait_many_result.index]] |
+ .handler->OnHandleReady( |
+ run_state_->wait_state->handles[wait_many_result.index]); |
DidSignalHandler(); |
} |
} else { |
switch (result) { |
- case MOJO_RESULT_CANCELLED: |
case MOJO_RESULT_FAILED_PRECONDITION: |
- RemoveInvalidHandle(wait_state, result, wait_many_result.index); |
+ RemoveInvalidHandle(*run_state_->wait_state, result, |
+ wait_many_result.index); |
break; |
case MOJO_RESULT_DEADLINE_EXCEEDED: |
did_work = false; |
break; |
+ case MOJO_RESULT_INVALID_ARGUMENT: |
+ case MOJO_RESULT_CANCELLED: |
+ case MOJO_RESULT_BUSY: |
+ // These results indicate a bug in "our" code (e.g., race conditions). |
+ // Fall through. |
default: |
base::debug::Alias(&result); |
// Unexpected result is likely fatal, crash so we can determine cause. |
CHECK(false); |
} |
} |
+ // To keep memory usage under control, delete the WaitState object at the end |
+ // if it's vectors are too big by a factor of 2. Pre-C++11 doesn't have a way |
+ // to shrink vectors, so just get rid of them and re-create on the next round. |
+ if (run_state_->wait_state->handles.capacity() > |
+ 2 * run_state_->wait_state->handles.size()) { |
+ // NOTE: |handles| and |wait_signals| are always in sync, so it's reasonable |
+ // to only check one of those. |
+ run_state_->wait_state.reset(); |
+ } |
// Notify and remove any handlers whose time has expired. Make a copy in case |
// someone tries to add/remove new handlers from notification. |
- const HandleToHandler cloned_handlers(handlers_); |
+ if (!run_state_->cloned_handlers) { |
+ run_state_->cloned_handlers.reset(new HandleToHandlerList); |
+ } else { |
+ run_state_->cloned_handlers->clear(); |
+ } |
+ run_state_->cloned_handlers->reserve(handlers_.size()); |
+ for (const auto& handler : handlers_) { |
+ run_state_->cloned_handlers->push_back(handler); |
+ } |
const base::TimeTicks now(internal::NowTicks()); |
- for (HandleToHandler::const_iterator i = cloned_handlers.begin(); |
- i != cloned_handlers.end(); ++i) { |
+ for (HandleToHandlerList::const_iterator i = |
+ run_state_->cloned_handlers->begin(); |
+ i != run_state_->cloned_handlers->end(); ++i) { |
// Since we're iterating over a clone of the handlers, verify the handler is |
// still valid before notifying. |
if (!i->second.deadline.is_null() && i->second.deadline < now && |
@@ -225,6 +260,10 @@ bool MessagePumpMojo::DoInternalWork(const RunState& run_state, bool block) { |
did_work = true; |
} |
} |
+ if (run_state_->cloned_handlers->capacity() > |
+ 2 * run_state_->cloned_handlers->size()) { |
+ run_state_->cloned_handlers.reset(); |
+ } |
return did_work; |
} |
@@ -249,25 +288,29 @@ void MessagePumpMojo::RemoveInvalidHandle(const WaitState& wait_state, |
void MessagePumpMojo::SignalControlPipe(const RunState& run_state) { |
const MojoResult result = |
- WriteMessageRaw(run_state.write_handle.get(), NULL, 0, NULL, 0, |
+ WriteMessageRaw(run_state.write_handle.get(), nullptr, 0, nullptr, 0, |
MOJO_WRITE_MESSAGE_FLAG_NONE); |
// If we can't write we likely won't wake up the thread and there is a strong |
// chance we'll deadlock. |
CHECK_EQ(MOJO_RESULT_OK, result); |
} |
-MessagePumpMojo::WaitState MessagePumpMojo::GetWaitState( |
- const RunState& run_state) const { |
- WaitState wait_state; |
- wait_state.handles.push_back(run_state.read_handle.get()); |
- wait_state.wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); |
+void MessagePumpMojo::GetWaitState( |
+ const RunState& run_state, |
+ MessagePumpMojo::WaitState* wait_state) const { |
+ const size_t num_handles = handlers_.size() + 1; |
+ wait_state->handles.clear(); |
+ wait_state->handles.reserve(num_handles); |
+ wait_state->wait_signals.clear(); |
+ wait_state->wait_signals.reserve(num_handles); |
+ wait_state->handles.push_back(run_state.read_handle.get()); |
+ wait_state->wait_signals.push_back(MOJO_HANDLE_SIGNAL_READABLE); |
for (HandleToHandler::const_iterator i = handlers_.begin(); |
i != handlers_.end(); ++i) { |
- wait_state.handles.push_back(i->first); |
- wait_state.wait_signals.push_back(i->second.wait_signals); |
+ wait_state->handles.push_back(i->first); |
+ wait_state->wait_signals.push_back(i->second.wait_signals); |
} |
- return wait_state; |
} |
MojoDeadline MessagePumpMojo::GetDeadlineForWait( |