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