diff options
Diffstat (limited to 'host/lib')
| -rw-r--r-- | host/lib/rfnoc/node.cpp | 92 | 
1 files changed, 51 insertions, 41 deletions
| diff --git a/host/lib/rfnoc/node.cpp b/host/lib/rfnoc/node.cpp index cc2d7b7a9..33649b23f 100644 --- a/host/lib/rfnoc/node.cpp +++ b/host/lib/rfnoc/node.cpp @@ -72,25 +72,22 @@ void node_t::clear_command_time(const size_t instance)  void node_t::register_property(property_base_t* prop, resolve_callback_t&& clean_callback)  {      std::lock_guard<std::mutex> _l(_prop_mutex); -      const auto src_type          = prop->get_src_info().type; -    auto prop_already_registered = [prop](const property_base_t* existing_prop) { -        return (prop->get_src_info() == existing_prop->get_src_info() -                   && prop->get_id() == existing_prop->get_id()) -               || (prop == existing_prop); -    };      // If the map is empty for this source type, create an empty vector      if (_props.count(src_type) == 0) {          _props[src_type] = {};      } -    // Now go and make sure no one has registered this property before -    auto& props = _props[src_type]; -    for (const auto& existing_prop : props) { -        if (prop_already_registered(existing_prop)) { -            throw uhd::runtime_error("Attempting to double-register prop"); -        } +    auto prop_already_registered = [prop](const property_base_t* existing_prop) { +        return (prop == existing_prop) || +            (prop->get_src_info() == existing_prop->get_src_info() +                   && prop->get_id() == existing_prop->get_id()); +    }; +    if (!filter_props(prop_already_registered).empty()) { +        throw uhd::runtime_error(std::string("Attempting to double-register property: ") +                                 + prop->get_id() + "[" + prop->get_src_info().to_string() +                                 + "]");      }      _props[src_type].push_back(prop); @@ -347,43 +344,56 @@ void node_t::init_props()  void node_t::resolve_props()  {      prop_accessor_t prop_accessor{}; -    const prop_ptrs_t dirty_props = +    const prop_ptrs_t initial_dirty_props =          filter_props([](property_base_t* prop) { return prop->is_dirty(); }); +    std::list<property_base_t*> all_dirty_props( +        initial_dirty_props.cbegin(), initial_dirty_props.cend()); +    prop_ptrs_t processed_props{};      prop_ptrs_t written_props{}; -    UHD_LOG_TRACE(get_unique_id(), -        "Locally resolving " << dirty_props.size() << " dirty properties."); - -    // Helper to determine if any element from inputs is in dirty_props -    auto in_dirty_props = [&dirty_props](const prop_ptrs_t inputs) { -        return std::any_of( -            inputs.cbegin(), inputs.cend(), [&dirty_props](property_base_t* prop) { -                return dirty_props.count(prop) != 1; -            }); -    }; - -    for (auto& resolver_tuple : _prop_resolvers) { -        auto& inputs  = std::get<0>(resolver_tuple); -        auto& outputs = std::get<1>(resolver_tuple); -        if (in_dirty_props(inputs)) { +    RFNOC_LOG_TRACE("Locally resolving " << all_dirty_props.size() +                                         << " dirty properties plus dependencies."); + +    // Loop through all dirty properties. The list can be amended during the +    // loop execution. +    for (auto it = all_dirty_props.begin(); it != all_dirty_props.end(); ++it) { +        auto current_input_prop = *it; +        if (processed_props.count(current_input_prop)) {              continue;          } +        // Find all resolvers that take this dirty property as an input: +        for (auto& resolver_tuple : _prop_resolvers) { +            auto& inputs  = std::get<0>(resolver_tuple); +            auto& outputs = std::get<1>(resolver_tuple); +            if (!inputs.count(current_input_prop)) { +                continue; +            } -        // Enable outputs -        std::vector<uhd::utils::scope_exit::uptr> access_holder; -        access_holder.reserve(outputs.size()); -        for (auto& output : outputs) { -            access_holder.emplace_back(prop_accessor.get_scoped_prop_access(*output, -                written_props.count(output) ? property_base_t::access_t::RWLOCKED -                                            : property_base_t::access_t::RW)); -        } +            // Enable outputs +            std::vector<uhd::utils::scope_exit::uptr> access_holder; +            access_holder.reserve(outputs.size()); +            for (auto& output : outputs) { +                access_holder.emplace_back(prop_accessor.get_scoped_prop_access(*output, +                    written_props.count(output) ? property_base_t::access_t::RWLOCKED +                                                : property_base_t::access_t::RW)); +            } -        // Run resolver -        std::get<2>(resolver_tuple)(); +            // Run resolver +            std::get<2>(resolver_tuple)(); -        // Take note of outputs -        written_props.insert(outputs.cbegin(), outputs.cend()); +            // Take note of outputs +            written_props.insert(outputs.cbegin(), outputs.cend()); -        // RW or RWLOCKED gets released here as access_holder goes out of scope. +            // Add all outputs that are dirty to the list, unless they have +            // already been processed +            for (auto& output_prop : outputs) { +                if (output_prop->is_dirty() && processed_props.count(output_prop) == 0) { +                    all_dirty_props.push_back(output_prop); +                } +            } + +            // RW or RWLOCKED gets released here as access_holder goes out of scope. +        } +        processed_props.insert(current_input_prop);      }  } | 
