| // Copyright 2017 The Fuchsia 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 <algorithm> |
| |
| #include <lib/async/default.h> |
| |
| #include "garnet/lib/ui/gfx/engine/resource_linker.h" |
| |
| namespace scenic_impl { |
| namespace gfx { |
| |
| static zx_signals_t kEventPairDeathSignals = ZX_EVENTPAIR_PEER_CLOSED; |
| |
| #define ASSERT_INTERNAL_EXPORTS_CONSISTENCY \ |
| { \ |
| size_t i = 0; \ |
| for (auto& it : koids_to_import_ptrs_) \ |
| i += it.second.size(); \ |
| FXL_DCHECK(imports_.size() == i); \ |
| } |
| |
| UnresolvedImports::UnresolvedImports(ResourceLinker* resource_linker) |
| : resource_linker_(resource_linker){}; |
| |
| void UnresolvedImports::AddUnresolvedImport(Import* import, |
| zx::eventpair import_token, |
| zx_koid_t import_koid) { |
| // Make sure the import koid we've been passed is valid. |
| FXL_DCHECK(import_koid != ZX_KOID_INVALID); |
| FXL_DCHECK(import_koid == fsl::GetKoid(import_token.get())); |
| |
| // Make sure we're not using the same import twice. |
| FXL_DCHECK(imports_.find(import) == imports_.end()); |
| |
| // Add to our data structures. |
| imports_[import] = ImportEntry{.import_ptr = import, |
| .import_token = std::move(import_token), |
| .import_koid = import_koid}; |
| koids_to_import_ptrs_[import_koid].push_back(import); |
| |
| ASSERT_INTERNAL_EXPORTS_CONSISTENCY; |
| } |
| |
| void UnresolvedImports::ListenForTokenPeerDeath(Import* import) { |
| auto import_entry_iter = imports_.find(import); |
| if (import_entry_iter != imports_.end()) { |
| zx_handle_t import_handle = import_entry_iter->second.import_token.get(); |
| zx_koid_t import_koid = import_entry_iter->second.import_koid; |
| |
| // The resource must be removed from being considered for import |
| // if its peer is closed. |
| auto wait = |
| std::make_unique<async::Wait>(import_handle, kEventPairDeathSignals); |
| wait->set_handler(std::bind(&UnresolvedImports::OnTokenPeerDeath, this, |
| import_koid, std::placeholders::_3, |
| std::placeholders::_4)); |
| zx_status_t status = wait->Begin(async_get_default_dispatcher()); |
| FXL_CHECK(status == ZX_OK); |
| |
| import_entry_iter->second.token_peer_death_waiter = std::move(wait); |
| } |
| ASSERT_INTERNAL_EXPORTS_CONSISTENCY; |
| } |
| |
| std::vector<Import*> UnresolvedImports::RemoveUnresolvedImportsForKoid( |
| zx_koid_t import_koid) { |
| auto imports = GetAndRemoveUnresolvedImportsForKoid(import_koid); |
| |
| for (auto& entry : imports) { |
| resource_linker_->OnImportResolvedForResource( |
| entry, nullptr, ImportResolutionResult::kExportHandleDiedBeforeBind); |
| } |
| |
| return imports; |
| } |
| |
| std::vector<Import*> UnresolvedImports::GetAndRemoveUnresolvedImportsForKoid( |
| zx_koid_t import_koid) { |
| // Look up the import entries for this koid. |
| auto import_ptr_collection_iter = koids_to_import_ptrs_.find(import_koid); |
| FXL_DCHECK(import_ptr_collection_iter != koids_to_import_ptrs_.end()); |
| |
| // Construct a list of the callbacks, and erase the imports from our data |
| // structures. |
| std::vector<Import*> imports = std::move(import_ptr_collection_iter->second); |
| |
| for (auto& import_ptr : imports) { |
| // Look up entry and add its resolution_callback to |callbacks|. |
| auto entry_iter = imports_.find(import_ptr); |
| FXL_DCHECK(entry_iter != imports_.end()); |
| |
| // Remove from |imports_|. |
| imports_.erase(entry_iter); |
| } |
| |
| // Remove from |koids_to_import_ptrs_|. |
| koids_to_import_ptrs_.erase(import_ptr_collection_iter); |
| |
| ASSERT_INTERNAL_EXPORTS_CONSISTENCY; |
| |
| return imports; |
| } |
| |
| void Remove(Import* import, std::vector<Import*>* vec) { |
| auto it = std::find(vec->begin(), vec->end(), import); |
| FXL_DCHECK(it != vec->end()); |
| vec->erase(it); |
| } |
| |
| void UnresolvedImports::OnImportDestroyed(Import* import) { |
| auto entry_iter = imports_.find(import); |
| if (entry_iter == imports_.end()) |
| return; |
| |
| // Call the resolution callback. |
| resource_linker_->OnImportResolvedForResource( |
| import, nullptr, ImportResolutionResult::kImportDestroyedBeforeBind); |
| |
| // Remove from |koids_to_import_ptrs_|. |
| zx_koid_t import_koid = entry_iter->second.import_koid; |
| Remove(import, &koids_to_import_ptrs_[import_koid]); |
| |
| // Remove from |imports_|. |
| imports_.erase(entry_iter); |
| |
| resource_linker_->InvokeExpirationCallback( |
| import, ResourceLinker::ExpirationCause::kResourceDestroyed); |
| |
| ASSERT_INTERNAL_EXPORTS_CONSISTENCY; |
| } |
| |
| size_t UnresolvedImports::NumUnresolvedImportsForKoid( |
| zx_koid_t import_koid) const { |
| // Look up the import entries for this koid. |
| auto import_ptr_collection_iter = koids_to_import_ptrs_.find(import_koid); |
| if (import_ptr_collection_iter == koids_to_import_ptrs_.end()) { |
| return 0; |
| } else { |
| return import_ptr_collection_iter->second.size(); |
| } |
| } |
| |
| void UnresolvedImports::OnTokenPeerDeath(zx_koid_t import_koid, |
| zx_status_t status, |
| const zx_packet_signal* signal) { |
| // Remove |import_koid|, even if there was an error (i.e. status != ZX_OK). |
| auto imports = RemoveUnresolvedImportsForKoid(import_koid); |
| |
| for (auto& import : imports) { |
| resource_linker_->InvokeExpirationCallback( |
| import, status == ZX_OK |
| ? ResourceLinker::ExpirationCause::kExportTokenClosed |
| : ResourceLinker::ExpirationCause::kInternalError); |
| } |
| } |
| |
| } // namespace gfx |
| } // namespace scenic_impl |