// 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 <stdint.h> #include <limits> namespace mojo { namespace edk { HandleTable::HandleTable() {} HandleTable::~HandleTable() {} 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 = 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, uint32_t num_handles, std::vector<Dispatcher::DispatcherInTransit>* dispatchers) { dispatchers->clear(); dispatchers->reserve(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); } 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 edk } // namespace mojo