// 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/edk/system/handle_table.h" #include #include #include "base/trace_event/memory_dump_manager.h" namespace mojo { namespace edk { 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"; } NOTREACHED(); return "unknown"; } } // namespace HandleTable::HandleTable() { } HandleTable::~HandleTable() { } base::Lock& HandleTable::GetLock() { return lock_; } MojoHandle HandleTable::AddDispatcher(scoped_refptr 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& 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::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 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) { 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* 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& 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& 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* 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 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]; // 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(std::move(dispatcher)) {} HandleTable::Entry::Entry(const Entry& other) = default; HandleTable::Entry::~Entry() {} } // namespace edk } // namespace mojo