blob: 1e2e423011f66d43d2e439b023db508e86338dcd [file] [log] [blame]
// 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