| // 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/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::HandleTable() {} |
| |
| HandleTable::~HandleTable() {} |
| |
| 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_++; |
| auto result = |
| handles_.insert(std::make_pair(handle, Entry(std::move(dispatcher)))); |
| DCHECK(result.second); |
| |
| 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; |
| |
| DCHECK_LE(dispatchers.size(), std::numeric_limits<uint32_t>::max()); |
| // If this insertion would cause handle overflow, we're out of handles. |
| if (next_available_handle_ + dispatchers.size() < next_available_handle_) |
| return false; |
| |
| for (size_t i = 0; i < dispatchers.size(); ++i) { |
| MojoHandle handle = MOJO_HANDLE_INVALID; |
| if (dispatchers[i].dispatcher) { |
| handle = next_available_handle_++; |
| auto result = handles_.insert( |
| std::make_pair(handle, Entry(dispatchers[i].dispatcher))); |
| DCHECK(result.second); |
| } |
| handles[i] = handle; |
| } |
| |
| return true; |
| } |
| |
| scoped_refptr<Dispatcher> HandleTable::GetDispatcher(MojoHandle handle) const { |
| auto it = handles_.find(handle); |
| if (it == handles_.end()) |
| return nullptr; |
| return it->second.dispatcher; |
| } |
| |
| MojoResult HandleTable::GetAndRemoveDispatcher( |
| MojoHandle handle, |
| scoped_refptr<Dispatcher>* dispatcher) { |
| auto it = handles_.find(handle); |
| if (it == handles_.end()) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| if (it->second.busy) |
| return MOJO_RESULT_BUSY; |
| |
| *dispatcher = std::move(it->second.dispatcher); |
| handles_.erase(it); |
| 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) { |
| auto it = handles_.find(handles[i]); |
| if (it == handles_.end()) |
| return MOJO_RESULT_INVALID_ARGUMENT; |
| if (it->second.busy) |
| return MOJO_RESULT_BUSY; |
| |
| Dispatcher::DispatcherInTransit d; |
| d.local_handle = handles[i]; |
| d.dispatcher = it->second.dispatcher; |
| if (!d.dispatcher->BeginTransit()) |
| return MOJO_RESULT_BUSY; |
| it->second.busy = true; |
| dispatchers->push_back(d); |
| } |
| return MOJO_RESULT_OK; |
| } |
| |
| void HandleTable::CompleteTransitAndClose( |
| const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) { |
| for (const auto& dispatcher : dispatchers) { |
| auto it = handles_.find(dispatcher.local_handle); |
| DCHECK(it != handles_.end() && it->second.busy); |
| handles_.erase(it); |
| dispatcher.dispatcher->CompleteTransitAndClose(); |
| } |
| } |
| |
| void HandleTable::CancelTransit( |
| const std::vector<Dispatcher::DispatcherInTransit>& dispatchers) { |
| for (const auto& dispatcher : dispatchers) { |
| auto it = handles_.find(dispatcher.local_handle); |
| DCHECK(it != handles_.end() && it->second.busy); |
| it->second.busy = false; |
| dispatcher.dispatcher->CancelTransit(); |
| } |
| } |
| |
| void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) { |
| handles->clear(); |
| for (const auto& entry : handles_) |
| 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 : handles_) { |
| // ++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() {} |
| |
| HandleTable::Entry::Entry(scoped_refptr<Dispatcher> dispatcher) |
| : dispatcher(std::move(dispatcher)) {} |
| |
| HandleTable::Entry::Entry(const Entry& other) = default; |
| |
| HandleTable::Entry::~Entry() {} |
| |
| } // namespace core |
| } // namespace mojo |