123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- // Copyright 2014 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "mojo/core/handle_table.h"
- #include <stdint.h>
- #include <limits>
- #include "base/cpu_reduction_experiment.h"
- #include "base/trace_event/memory_dump_manager.h"
- namespace mojo {
- namespace core {
- namespace {
- const char* GetNameForDispatcherType(Dispatcher::Type type) {
- switch (type) {
- case Dispatcher::Type::UNKNOWN:
- return "unknown";
- case Dispatcher::Type::MESSAGE_PIPE:
- return "message_pipe";
- case Dispatcher::Type::DATA_PIPE_PRODUCER:
- return "data_pipe_producer";
- case Dispatcher::Type::DATA_PIPE_CONSUMER:
- return "data_pipe_consumer";
- case Dispatcher::Type::SHARED_BUFFER:
- return "shared_buffer";
- case Dispatcher::Type::WATCHER:
- return "watcher";
- case Dispatcher::Type::PLATFORM_HANDLE:
- return "platform_handle";
- case Dispatcher::Type::INVITATION:
- return "invitation";
- }
- NOTREACHED();
- return "unknown";
- }
- } // namespace
- HandleTable::EntriesAccessor::EntriesAccessor() = default;
- HandleTable::EntriesAccessor::~EntriesAccessor() = default;
- bool HandleTable::EntriesAccessor::Add(const MojoHandle handle, Entry entry) {
- return handles_.emplace(handle, std::move(entry)).second;
- }
- const scoped_refptr<Dispatcher>* HandleTable::EntriesAccessor::GetDispatcher(
- const MojoHandle handle) {
- // TODO(crbug.com/1295441): Remove the if-block below.
- // This intentionally duplicates code in this function a bit, so that this
- // entire if-block can later be removed cleanly.
- if (!base::IsRunningCpuReductionExperiment()) {
- const auto iter = handles_.find(handle);
- return iter == handles_.end() ? nullptr : &iter->second.dispatcher;
- }
- if (last_read_handle_ != MOJO_HANDLE_INVALID && last_read_handle_ == handle) {
- return &last_read_dispatcher_;
- }
- const auto iter = handles_.find(handle);
- if (iter == handles_.end()) {
- return nullptr;
- }
- last_read_handle_ = handle;
- last_read_dispatcher_ = iter->second.dispatcher;
- return &last_read_dispatcher_;
- }
- HandleTable::Entry* HandleTable::EntriesAccessor::GetMutable(
- const MojoHandle handle) {
- const auto iter = handles_.find(handle);
- return iter == handles_.end() ? nullptr : &iter->second;
- }
- MojoResult HandleTable::EntriesAccessor::Remove(
- const MojoHandle handle,
- const HandleTable::EntriesAccessor::RemovalCondition removal_condition,
- scoped_refptr<Dispatcher>* dispatcher) {
- auto iter = handles_.find(handle);
- if (iter == handles_.end()) {
- return MOJO_RESULT_NOT_FOUND;
- }
- const bool is_busy = iter->second.busy;
- const bool remove_only_if_busy =
- removal_condition == RemovalCondition::kRemoveOnlyIfBusy;
- if (remove_only_if_busy == is_busy) {
- if (dispatcher != nullptr) {
- *dispatcher = iter->second.dispatcher;
- }
- if (iter->first == last_read_handle_) {
- last_read_handle_ = MOJO_HANDLE_INVALID;
- last_read_dispatcher_.reset();
- }
- handles_.erase(iter);
- }
- return is_busy ? MOJO_RESULT_BUSY : MOJO_RESULT_OK;
- }
- const std::unordered_map<MojoHandle, HandleTable::Entry>&
- HandleTable::EntriesAccessor::GetUnderlyingMap() const {
- return handles_;
- }
- HandleTable::HandleTable() = default;
- HandleTable::~HandleTable() = default;
- base::Lock& HandleTable::GetLock() {
- return lock_;
- }
- MojoHandle HandleTable::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) {
- // Oops, we're out of handles.
- if (next_available_handle_ == MOJO_HANDLE_INVALID)
- return MOJO_HANDLE_INVALID;
- MojoHandle handle = next_available_handle_++;
- const bool inserted = entries_.Add(handle, Entry(std::move(dispatcher)));
- DCHECK(inserted);
- return handle;
- }
- bool HandleTable::AddDispatchersFromTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers,
- MojoHandle* handles) {
- // Oops, we're out of handles.
- if (next_available_handle_ == MOJO_HANDLE_INVALID) {
- return false;
- }
- // MOJO_HANDLE_INVALID is zero.
- DCHECK_GE(next_available_handle_, 1u);
- // If this insertion would cause handle overflow, we're out of handles.
- const uintptr_t num_handles_available =
- std::numeric_limits<uintptr_t>::max() - next_available_handle_ + 1;
- if (num_handles_available < dispatchers.size()) {
- return false;
- }
- for (size_t i = 0; i < dispatchers.size(); ++i) {
- MojoHandle handle = MOJO_HANDLE_INVALID;
- if (dispatchers[i].dispatcher) {
- handle = next_available_handle_++;
- const bool inserted =
- entries_.Add(handle, Entry(dispatchers[i].dispatcher));
- DCHECK(inserted);
- }
- handles[i] = handle;
- }
- return true;
- }
- scoped_refptr<Dispatcher> HandleTable::GetDispatcher(MojoHandle handle) {
- const scoped_refptr<Dispatcher>* dispatcher = entries_.GetDispatcher(handle);
- return dispatcher == nullptr ? nullptr : *dispatcher;
- }
- MojoResult HandleTable::GetAndRemoveDispatcher(
- MojoHandle handle,
- scoped_refptr<Dispatcher>* dispatcher) {
- scoped_refptr<Dispatcher> removed_dispatcher;
- const MojoResult remove_result = entries_.Remove(
- handle, EntriesAccessor::RemovalCondition::kRemoveOnlyIfNotBusy,
- &removed_dispatcher);
- if (remove_result == MOJO_RESULT_NOT_FOUND) {
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
- if (remove_result == MOJO_RESULT_BUSY) {
- return MOJO_RESULT_BUSY;
- }
- *dispatcher = std::move(removed_dispatcher);
- return MOJO_RESULT_OK;
- }
- MojoResult HandleTable::BeginTransit(
- const MojoHandle* handles,
- size_t num_handles,
- std::vector<Dispatcher::DispatcherInTransit>* dispatchers) {
- dispatchers->reserve(dispatchers->size() + num_handles);
- for (size_t i = 0; i < num_handles; ++i) {
- Entry* entry = entries_.GetMutable(handles[i]);
- if (entry == nullptr) {
- return MOJO_RESULT_INVALID_ARGUMENT;
- }
- if (entry->busy) {
- return MOJO_RESULT_BUSY;
- }
- Dispatcher::DispatcherInTransit d;
- d.local_handle = handles[i];
- d.dispatcher = entry->dispatcher;
- if (!d.dispatcher->BeginTransit())
- return MOJO_RESULT_BUSY;
- entry->busy = true;
- dispatchers->push_back(d);
- }
- return MOJO_RESULT_OK;
- }
- void HandleTable::CompleteTransitAndClose(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
- for (const auto& dispatcher : dispatchers) {
- const MojoResult remove_result =
- entries_.Remove(dispatcher.local_handle,
- EntriesAccessor::RemovalCondition::kRemoveOnlyIfBusy,
- /*dispatcher=*/nullptr);
- DCHECK(remove_result == MOJO_RESULT_BUSY);
- dispatcher.dispatcher->CompleteTransitAndClose();
- }
- }
- void HandleTable::CancelTransit(
- const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) {
- for (const auto& dispatcher : dispatchers) {
- Entry* entry = entries_.GetMutable(dispatcher.local_handle);
- DCHECK(entry != nullptr && entry->busy);
- entry->busy = false;
- dispatcher.dispatcher->CancelTransit();
- }
- }
- void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
- handles->clear();
- for (const auto& entry : entries_.GetUnderlyingMap())
- handles->push_back(entry.first);
- }
- // MemoryDumpProvider implementation.
- bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
- base::trace_event::ProcessMemoryDump* pmd) {
- // Create entries for all relevant dispatcher types to ensure they are present
- // in the final dump.
- std::map<Dispatcher::Type, int> handle_count;
- handle_count[Dispatcher::Type::MESSAGE_PIPE];
- handle_count[Dispatcher::Type::DATA_PIPE_PRODUCER];
- handle_count[Dispatcher::Type::DATA_PIPE_CONSUMER];
- handle_count[Dispatcher::Type::SHARED_BUFFER];
- handle_count[Dispatcher::Type::WATCHER];
- handle_count[Dispatcher::Type::PLATFORM_HANDLE];
- handle_count[Dispatcher::Type::INVITATION];
- // Count the number of each dispatcher type.
- {
- base::AutoLock lock(GetLock());
- for (const auto& entry : entries_.GetUnderlyingMap()) {
- ++handle_count[entry.second.dispatcher->GetType()];
- }
- }
- for (const auto& entry : handle_count) {
- base::trace_event::MemoryAllocatorDump* inner_dump =
- pmd->CreateAllocatorDump(std::string("mojo/") +
- GetNameForDispatcherType(entry.first));
- inner_dump->AddScalar(
- base::trace_event::MemoryAllocatorDump::kNameObjectCount,
- base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
- }
- return true;
- }
- HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher)
- : dispatcher(std::move(dispatcher)) {}
- HandleTable::Entry::~Entry() = default;
- HandleTable::Entry::Entry(const Entry& entry) = default;
- } // namespace core
- } // namespace mojo
|