From 8422965d0baefe4438ee982ddcf562f65ec6d41e Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 11 Jul 2024 23:30:54 +0200 Subject: [PATCH] impr: Run data processor in a worker task --- .../include/hex/data_processor/node.hpp | 50 +++------- lib/libimhex/source/data_processor/node.cpp | 53 +++++++++++ .../content/views/view_data_processor.hpp | 6 +- .../data_processor_nodes/control_nodes.cpp | 4 + .../data_processor_nodes/visual_nodes.cpp | 5 +- .../content/views/view_data_processor.cpp | 93 ++++++++++++------- 6 files changed, 136 insertions(+), 75 deletions(-) diff --git a/lib/libimhex/include/hex/data_processor/node.hpp b/lib/libimhex/include/hex/data_processor/node.hpp index 537807683..e9bc297dc 100644 --- a/lib/libimhex/include/hex/data_processor/node.hpp +++ b/lib/libimhex/include/hex/data_processor/node.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace hex::prv { class Provider; @@ -42,8 +43,9 @@ namespace hex::dp { m_overlay = overlay; } - virtual void drawNode() { } + void draw(); virtual void process() = 0; + virtual void reset() { } virtual void store(nlohmann::json &j) const { hex::unused(j); } virtual void load(const nlohmann::json &j) { hex::unused(j); } @@ -80,6 +82,11 @@ namespace hex::dp { void setIntegerOnOutput(u32 index, i128 integer); void setFloatOnOutput(u32 index, double floatingPoint); + static void interrupt(); + + protected: + virtual void drawNode() { } + private: int m_id; UnlocalizedString m_unlocalizedTitle, m_unlocalizedName; @@ -90,45 +97,16 @@ namespace hex::dp { static int s_idCounter; - Attribute& getAttribute(u32 index) { - if (index >= this->getAttributes().size()) - throw std::runtime_error("Attribute index out of bounds!"); - - return this->getAttributes()[index]; - } - - Attribute *getConnectedInputAttribute(u32 index) { - const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes(); - - if (connectedAttribute.empty()) - return nullptr; - - return connectedAttribute.begin()->second; - } - - void markInputProcessed(u32 index) { - const auto &[iter, inserted] = m_processedInputs.insert(index); - if (!inserted) - throwNodeError("Recursion detected!"); - } - - void unmarkInputProcessed(u32 index) { - m_processedInputs.erase(index); - } + Attribute& getAttribute(u32 index); + Attribute *getConnectedInputAttribute(u32 index); + void markInputProcessed(u32 index); + void unmarkInputProcessed(u32 index); protected: - [[noreturn]] void throwNodeError(const std::string &message) { - throw NodeError { this, message }; - } + [[noreturn]] void throwNodeError(const std::string &message); void setOverlayData(u64 address, const std::vector &data); - - void setAttributes(std::vector attributes) { - m_attributes = std::move(attributes); - - for (auto &attr : m_attributes) - attr.setParentNode(this); - } + void setAttributes(std::vector attributes); }; } \ No newline at end of file diff --git a/lib/libimhex/source/data_processor/node.cpp b/lib/libimhex/source/data_processor/node.cpp index be97886c8..67b57fbc9 100644 --- a/lib/libimhex/source/data_processor/node.cpp +++ b/lib/libimhex/source/data_processor/node.cpp @@ -8,12 +8,18 @@ namespace hex::dp { int Node::s_idCounter = 1; + static std::atomic_bool s_interrupted; Node::Node(UnlocalizedString unlocalizedTitle, std::vector attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) { for (auto &attr : m_attributes) attr.setParentNode(this); } + void Node::draw() { + this->drawNode(); + } + + const std::vector& Node::getBufferOnInput(u32 index) { auto attribute = this->getConnectedInputAttribute(index); @@ -148,9 +154,56 @@ namespace hex::dp { m_overlay->getData() = data; } + [[noreturn]] void Node::throwNodeError(const std::string &message) { + throw NodeError { this, message }; + } + + void Node::setAttributes(std::vector attributes) { + m_attributes = std::move(attributes); + + for (auto &attr : m_attributes) + attr.setParentNode(this); + } + void Node::setIdCounter(int id) { if (id > s_idCounter) s_idCounter = id; } + Attribute& Node::getAttribute(u32 index) { + if (index >= this->getAttributes().size()) + throw std::runtime_error("Attribute index out of bounds!"); + + return this->getAttributes()[index]; + } + + Attribute *Node::getConnectedInputAttribute(u32 index) { + const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes(); + + if (connectedAttribute.empty()) + return nullptr; + + return connectedAttribute.begin()->second; + } + + void Node::markInputProcessed(u32 index) { + const auto &[iter, inserted] = m_processedInputs.insert(index); + if (!inserted) + throwNodeError("Recursion detected!"); + + if (s_interrupted) { + s_interrupted = false; + throwNodeError("Execution interrupted!"); + } + } + + void Node::unmarkInputProcessed(u32 index) { + m_processedInputs.erase(index); + } + + void Node::interrupt() { + s_interrupted = true; + } + + } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_data_processor.hpp b/plugins/builtin/include/content/views/view_data_processor.hpp index 6ea7ab04e..b7abbf15d 100644 --- a/plugins/builtin/include/content/views/view_data_processor.hpp +++ b/plugins/builtin/include/content/views/view_data_processor.hpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace hex::plugin::builtin { @@ -17,6 +18,8 @@ namespace hex::plugin::builtin { struct Workspace { Workspace() = default; + + std::unique_ptr context = { []{ ImNodesContext *ctx = ImNodes::CreateContext(); ctx->Style = ImNodes::GetStyle(); @@ -47,7 +50,7 @@ namespace hex::plugin::builtin { static void eraseLink(Workspace &workspace, int id); static void eraseNodes(Workspace &workspace, const std::vector &ids); - static void processNodes(Workspace &workspace); + void processNodes(Workspace &workspace); void reloadCustomNodes(); void updateNodePositions(); @@ -74,6 +77,7 @@ namespace hex::plugin::builtin { PerProvider m_mainWorkspace; PerProvider> m_workspaceStack; + TaskHolder m_evaluationTask; }; } \ No newline at end of file diff --git a/plugins/builtin/source/content/data_processor_nodes/control_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes/control_nodes.cpp index 6d94c3ccb..1f71bef58 100644 --- a/plugins/builtin/source/content/data_processor_nodes/control_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes/control_nodes.cpp @@ -138,6 +138,10 @@ namespace hex::plugin::builtin { this->setIntegerOnOutput(4, m_value); } + void reset() override { + m_started = false; + } + private: bool m_started = false; i128 m_value = 0; diff --git a/plugins/builtin/source/content/data_processor_nodes/visual_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes/visual_nodes.cpp index a00b3980a..cb295eb1f 100644 --- a/plugins/builtin/source/content/data_processor_nodes/visual_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes/visual_nodes.cpp @@ -28,10 +28,7 @@ namespace hex::plugin::builtin { } void process() override { - m_value.reset(); - const auto &input = this->getIntegerOnInput(0); - - m_value = input; + m_value = this->getIntegerOnInput(0); } private: diff --git a/plugins/builtin/source/content/views/view_data_processor.cpp b/plugins/builtin/source/content/views/view_data_processor.cpp index f14aaa38c..afb4bef08 100644 --- a/plugins/builtin/source/content/views/view_data_processor.cpp +++ b/plugins/builtin/source/content/views/view_data_processor.cpp @@ -390,10 +390,6 @@ namespace hex::plugin::builtin { m_updateNodePositions = true; }); - EventDataChanged::subscribe(this, [this](prv::Provider *provider) { - ViewDataProcessor::processNodes(*m_workspaceStack.get(provider).back()); - }); - /* Import Nodes */ ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.data_processor" }, ICON_VS_CHIP, 4050, Shortcut::None, [this]{ fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } }, @@ -532,36 +528,49 @@ namespace hex::plugin::builtin { // Reset any potential node errors workspace.currNodeError.reset(); - // Process all nodes in the workspace - try { - for (auto &endNode : workspace.endNodes) { - // Reset the output data of the end node - endNode->resetOutputData(); + m_evaluationTask = TaskManager::createTask("Evaluating Nodes...", 0, [this, workspace = &workspace](Task& task) { + task.setInterruptCallback([]{ + dp::Node::interrupt(); + }); + do { - // Reset processed inputs of all nodes - for (auto &node : workspace.nodes) - node->resetProcessedInputs(); + // Process all nodes in the workspace + try { + for (auto &endNode : workspace->endNodes) { + // Reset the output data of the end node + endNode->resetOutputData(); - // Process the end node - endNode->process(); - } - } catch (const dp::Node::NodeError &e) { - // Handle user errors + // Reset processed inputs of all nodes + for (auto &node : workspace->nodes) { + node->reset(); + node->resetProcessedInputs(); + } - // Add the node error to the current workspace, so it can be displayed - workspace.currNodeError = e; + // Process the end node + endNode->process(); + } + } catch (const dp::Node::NodeError &e) { + // Handle user errors + + // Add the node error to the current workspace, so it can be displayed + workspace->currNodeError = e; + + // Delete all overlays + for (auto overlay : workspace->dataOverlays) + ImHexApi::Provider::get()->deleteOverlay(overlay); + workspace->dataOverlays.clear(); + } catch (const std::runtime_error &e) { + // Handle internal errors + log::fatal("Data processor node implementation bug! {}", e.what()); + } catch (const std::exception &e) { + // Handle other fatal errors + log::fatal("Unhandled exception thrown in data processor node! {}", e.what()); + } + + task.update(); + } while (m_continuousEvaluation); + }); - // Delete all overlays - for (auto overlay : workspace.dataOverlays) - ImHexApi::Provider::get()->deleteOverlay(overlay); - workspace.dataOverlays.clear(); - } catch (const std::runtime_error &e) { - // Handle internal errors - log::fatal("Data processor node implementation bug! {}", e.what()); - } catch (const std::exception &e) { - // Handle other fatal errors - log::fatal("Unhandled exception thrown in data processor node! {}", e.what()); - } } void ViewDataProcessor::reloadCustomNodes() { @@ -774,7 +783,9 @@ namespace hex::plugin::builtin { // Draw the node's body ImGui::PopStyleVar(); - node.drawNode(); + if (!m_evaluationTask.isRunning()) { + node.draw(); + } ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0F, 1.0F)); // Draw all attributes of the node @@ -851,6 +862,8 @@ namespace hex::plugin::builtin { void ViewDataProcessor::drawContent() { auto &workspace = *m_workspaceStack->back(); + ImGui::BeginDisabled(m_evaluationTask.isRunning()); + bool popWorkspace = false; // Set the ImNodes context to the current workspace context ImNodes::SetCurrentContext(workspace.context.get()); @@ -873,6 +886,9 @@ namespace hex::plugin::builtin { if (ImGui::BeginChild("##node_editor", ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 1.3F))) { ImNodes::BeginNodeEditor(); + if (m_evaluationTask.isRunning()) + ImNodes::GetCurrentContext()->MousePos = { FLT_MAX, FLT_MAX }; + // Loop over all nodes that have been placed in the workspace bool stillUpdating = m_updateNodePositions; for (auto &node : workspace.nodes) { @@ -933,10 +949,19 @@ namespace hex::plugin::builtin { } ImGui::EndChild(); + ImGui::EndDisabled(); + // Draw the control bar at the bottom { - if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)) || m_continuousEvaluation) - this->processNodes(workspace); + if (!m_evaluationTask.isRunning()) { + if (ImGuiExt::IconButton(ICON_VS_DEBUG_START, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) { + this->processNodes(workspace); + } + } else { + if (ImGuiExt::IconButton(ICON_VS_DEBUG_STOP, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) { + m_evaluationTask.interrupt(); + } + } ImGui::SameLine(); @@ -944,7 +969,7 @@ namespace hex::plugin::builtin { } - // Erase links that have been distroyed + // Erase links that have been destroyed { int linkId; if (ImNodes::IsLinkDestroyed(&linkId)) {