blob: 4aa88ee5cbf6db32aca19cd18bd43957d7c49eae [file] [log] [blame]
// Copyright 2021 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 "node_properties.h"
#include <zircon/assert.h>
#include <vector>
#include "fuchsia/sysmem2/llcpp/fidl.h"
#include "logical_buffer_collection.h"
namespace sysmem_driver {
NodeProperties::~NodeProperties() {
ZX_DEBUG_ASSERT(child_count() == 0);
if (node_) {
logical_buffer_collection_->RemoveCountsForNode(*node_);
node_->EnsureDetachedFromNodeProperties();
}
}
// static
std::unique_ptr<NodeProperties> NodeProperties::NewRoot(
LogicalBufferCollection* logical_buffer_collection) {
auto result = std::unique_ptr<NodeProperties>(new NodeProperties(logical_buffer_collection));
ZX_DEBUG_ASSERT(!result->parent_);
// Set later with SetNode().
ZX_DEBUG_ASSERT(!result->node_);
ZX_DEBUG_ASSERT(result->children_.empty());
return result;
}
NodeProperties* NodeProperties::NewChild(LogicalBufferCollection* logical_buffer_collection) {
auto result = std::unique_ptr<NodeProperties>(new NodeProperties(logical_buffer_collection));
auto result_ptr = result.get();
// The parent Node owns the child Node.
const auto& [child_iter, inserted] = this->children_.emplace(result_ptr, std::move(result));
ZX_DEBUG_ASSERT(inserted);
result_ptr->parent_ = this;
// Set later with SetNode().
ZX_DEBUG_ASSERT(!result_ptr->node_);
ZX_DEBUG_ASSERT(result_ptr->children_.empty());
// Default to parent's debug info until/unless overriden later (by the client, or by later code
// that always runs regardless of client behavior).
//
// struct copy
result_ptr->client_debug_info_ = client_debug_info_;
// Soon we'll do another &= on this mask with the rights_attenuation_mask supplied by the client
// when creating the child, but the child starts with the same rights masked away as the parent.
result_ptr->rights_attenuation_mask_ = rights_attenuation_mask_;
ZX_DEBUG_ASSERT(result_ptr->error_propagation_mode_ == ErrorPropagationMode::kPropagate);
return result_ptr;
}
// static
std::unique_ptr<NodeProperties> NodeProperties::NewTemporary(
LogicalBufferCollection* logical_buffer_collection,
fuchsia_sysmem2::wire::BufferCollectionConstraints buffer_collection_constraints,
std::string debug_name) {
auto result = std::unique_ptr<NodeProperties>(new NodeProperties(logical_buffer_collection));
ZX_DEBUG_ASSERT(!result->parent_);
// Since temporary, won't ever have a node_.
ZX_DEBUG_ASSERT(!result->node_);
ZX_DEBUG_ASSERT(result->children_.empty());
result->SetBufferCollectionConstraints(TableHolder(logical_buffer_collection->table_set(),
std::move(buffer_collection_constraints)));
result->client_debug_info().name = debug_name;
return result;
}
void NodeProperties::RemoveFromTreeAndDelete() {
ZX_DEBUG_ASSERT(child_count() == 0);
// This also deletes "this".
if (parent_) {
// Set parent_ to nullptr before "this" is deleted, just in case it makes any use-after-free
// quicker to track down.
auto local_parent = parent_;
parent_ = nullptr;
local_parent->children_.erase(this);
} else {
logical_buffer_collection_->DeleteRoot();
}
// "this" is now gone
}
std::vector<NodeProperties*> NodeProperties::BreadthFirstOrder(
fit::function<NodeFilterResult(const NodeProperties&)> node_filter) {
std::vector<NodeProperties*> iterate_children_tmp;
std::vector<NodeProperties*> result;
NodeFilterResult this_result;
if (node_filter) {
this_result = node_filter(*this);
}
if (this_result.keep_node) {
result.push_back(this);
}
if (this_result.iterate_children) {
iterate_children_tmp.push_back(this);
}
for (uint32_t i = 0; i < iterate_children_tmp.size(); ++i) {
NodeProperties* node = iterate_children_tmp[i];
for (auto& [child_ptr, unused] : node->children_) {
NodeFilterResult child_result;
if (node_filter) {
child_result = node_filter(*child_ptr);
}
if (child_result.keep_node) {
result.push_back(child_ptr);
}
if (child_result.iterate_children) {
iterate_children_tmp.push_back(child_ptr);
}
}
}
return result;
}
NodeProperties* NodeProperties::parent() const {
// Can be nullptr if this is the root.
return parent_;
}
Node* NodeProperties::node() const {
// Can be nullptr if no Node is owned yet.
return node_.get();
}
uint32_t NodeProperties::child_count() const { return children_.size(); }
ClientDebugInfo& NodeProperties::client_debug_info() { return client_debug_info_; }
const ClientDebugInfo& NodeProperties::client_debug_info() const { return client_debug_info_; }
uint32_t& NodeProperties::rights_attenuation_mask() { return rights_attenuation_mask_; }
ErrorPropagationMode& NodeProperties::error_propagation_mode() { return error_propagation_mode_; }
const ErrorPropagationMode& NodeProperties::error_propagation_mode() const {
return error_propagation_mode_;
}
bool NodeProperties::buffers_logically_allocated() const { return buffers_logically_allocated_; }
void NodeProperties::SetBuffersLogicallyAllocated() {
ZX_DEBUG_ASSERT(!buffers_logically_allocated_);
buffers_logically_allocated_ = true;
}
bool NodeProperties::has_constraints() const { return !!buffer_collection_constraints_; }
const fuchsia_sysmem2::wire::BufferCollectionConstraints*
NodeProperties::buffer_collection_constraints() const {
if (!buffer_collection_constraints_) {
return nullptr;
}
return &(**buffer_collection_constraints_);
}
void NodeProperties::SetBufferCollectionConstraints(
TableHolder<fuchsia_sysmem2::wire::BufferCollectionConstraints> buffer_collection_constraints) {
ZX_DEBUG_ASSERT(!buffer_collection_constraints_);
buffer_collection_constraints_.emplace(std::move(buffer_collection_constraints));
}
void NodeProperties::SetNode(fbl::RefPtr<Node> node) {
// Once a Node is owned, it's ok to switch to a different Node, but not ok to set back to nullptr.
ZX_DEBUG_ASSERT(node);
logical_buffer_collection_->AddCountsForNode(*node);
if (node_) {
logical_buffer_collection_->RemoveCountsForNode(*node_);
node_->EnsureDetachedFromNodeProperties();
}
node_ = std::move(node);
}
NodeProperties::NodeProperties(LogicalBufferCollection* logical_buffer_collection)
: logical_buffer_collection_(logical_buffer_collection) {
ZX_DEBUG_ASSERT(logical_buffer_collection_);
}
uint32_t NodeProperties::node_count() const { return node_count_; }
uint32_t NodeProperties::connected_client_count() const { return connected_client_count_; }
uint32_t NodeProperties::buffer_collection_count() const { return buffer_collection_count_; }
uint32_t NodeProperties::buffer_collection_token_count() const {
return buffer_collection_token_count_;
}
void NodeProperties::LogInfo(Location location, const char* format, ...) const {
va_list args;
va_start(args, format);
logical_buffer_collection_->VLogClientInfo(location, this, format, args);
va_end(args);
}
void NodeProperties::LogConstraints(Location location) {
if (!has_constraints()) {
LogInfo(FROM_HERE, "No constraints yet.");
return;
}
logical_buffer_collection_->LogConstraints(location, this, *buffer_collection_constraints());
}
} // namespace sysmem_driver