From e779285be45352cb8d8b36b090eaf23bec2f464d Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 17 Aug 2022 16:15:36 +0200 Subject: [PATCH] feat: Added basic ability to interrupt long running tasks --- lib/libimhex/include/hex/api/imhex_api.hpp | 9 - lib/libimhex/include/hex/api/task.hpp | 98 ++++++++-- lib/libimhex/source/api/imhex_api.cpp | 29 +-- lib/libimhex/source/api/task.cpp | 172 ++++++++++++++---- .../source/ui/imgui_imhex_extensions.cpp | 4 +- lib/libimhex/source/ui/view.cpp | 2 +- main/source/init/tasks.cpp | 3 +- main/source/window/window.cpp | 20 +- .../content/views/view_disassembler.hpp | 2 +- .../include/content/views/view_find.hpp | 2 +- .../content/views/view_information.hpp | 3 +- .../include/content/views/view_yara.hpp | 4 +- plugins/builtin/source/content/events.cpp | 10 +- .../source/content/main_menu_items.cpp | 40 ++-- .../builtin/source/content/tools_entries.cpp | 117 ++++++------ plugins/builtin/source/content/ui_items.cpp | 69 ++++--- .../source/content/views/view_about.cpp | 2 +- .../content/views/view_disassembler.cpp | 14 +- .../source/content/views/view_find.cpp | 13 +- .../source/content/views/view_hex_editor.cpp | 16 +- .../source/content/views/view_information.cpp | 23 +-- .../content/views/view_pattern_editor.cpp | 7 +- .../source/content/views/view_settings.cpp | 4 +- .../source/content/views/view_store.cpp | 2 +- .../source/content/views/view_yara.cpp | 61 +++---- .../builtin/source/content/welcome_screen.cpp | 6 +- 26 files changed, 422 insertions(+), 310 deletions(-) diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index 455458d32..8e3ee64c2 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -150,15 +150,6 @@ namespace hex { } - namespace Tasks { - - Task createTask(const std::string &unlocalizedName, u64 maxValue); - - void doLater(const std::function &function); - std::vector> &getDeferredCalls(); - - } - namespace System { namespace impl { diff --git a/lib/libimhex/include/hex/api/task.hpp b/lib/libimhex/include/hex/api/task.hpp index a5b8a2fbc..4671ade18 100644 --- a/lib/libimhex/include/hex/api/task.hpp +++ b/lib/libimhex/include/hex/api/task.hpp @@ -2,40 +2,100 @@ #include -#include +#include +#include +#include +#include #include -#include +#include +#include +#include namespace hex { + class TaskHolder; + class TaskManager; + class Task { public: Task() = default; - Task(const std::string &unlocalizedName, u64 maxValue); + Task(std::string unlocalizedName, u64 maxValue, std::function function); + + Task(const Task&) = delete; + Task(Task &&other) noexcept; ~Task(); - Task(Task &&other) noexcept; + void update(u64 value = 0); + void setMaxValue(u64 value); - void setMaxValue(u64 maxValue); - void update(u64 currValue); - void finish(); + [[nodiscard]] bool isFinished() const; + [[nodiscard]] bool hadException() const; + [[nodiscard]] bool wasInterrupted() const; + void clearException(); - [[nodiscard]] double getProgress() const; + [[nodiscard]] const std::string &getUnlocalizedName(); + [[nodiscard]] u64 getValue() const; + [[nodiscard]] u64 getMaxValue() const; - [[nodiscard]] const std::string &getName() const; - - [[nodiscard]] bool isPending() const; - - static size_t getRunningTaskCount(); - static std::list &getRunningTasks() { return Task::s_runningTasks; } - static std::mutex &getTaskMutex() { return Task::s_taskMutex; } + void interrupt(); private: - std::string m_name; - u64 m_maxValue = 0, m_currValue = 0; + void finish(); + void interruption(); + void exception(); - static std::list s_runningTasks; - static std::mutex s_taskMutex; + private: + mutable std::mutex m_mutex; + + std::string m_unlocalizedName; + u64 m_currValue, m_maxValue; + std::thread m_thread; + + bool m_shouldInterrupt = false; + + bool m_interrupted = false; + bool m_finished = false; + bool m_hadException = false; + + struct TaskInterruptor { virtual ~TaskInterruptor() = default; }; + + friend class TaskHolder; + friend class TaskManager; + }; + + class TaskHolder { + public: + TaskHolder() = default; + explicit TaskHolder(std::weak_ptr task) : m_task(std::move(task)) { } + + [[nodiscard]] bool isRunning() const; + [[nodiscard]] bool hadException() const; + [[nodiscard]] bool wasInterrupted() const; + + void interrupt(); + private: + std::weak_ptr m_task; + }; + + class TaskManager { + public: + TaskManager() = delete; + + constexpr static auto NoProgress = 0; + + static TaskHolder createTask(std::string name, u64 maxValue, std::function function); + static void collectGarbage(); + + static size_t getRunningTaskCount(); + static std::list> &getRunningTasks(); + + static void doLater(const std::function &function); + static void runDeferredCalls(); + private: + static std::mutex s_deferredCallsMutex; + + static std::list> s_tasks; + static std::list> s_deferredCalls; }; } \ No newline at end of file diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index fe598673f..7283bd50b 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -236,7 +236,7 @@ namespace hex { } void setCurrentProvider(u32 index) { - if (Task::getRunningTaskCount() > 0) + if (TaskManager::getRunningTaskCount() > 0) return; if (index < s_providers.size() && s_currentProvider != index) { @@ -266,7 +266,7 @@ namespace hex { } void add(prv::Provider *provider, bool skipLoadInterface) { - if (Task::getRunningTaskCount() > 0) + if (TaskManager::getRunningTaskCount() > 0) return; if (skipLoadInterface) @@ -282,7 +282,7 @@ namespace hex { if (provider == nullptr) return; - if (Task::getRunningTaskCount() > 0) + if (TaskManager::getRunningTaskCount() > 0) return; if (!noQuestions) { @@ -319,29 +319,6 @@ namespace hex { } - - namespace ImHexApi::Tasks { - - Task createTask(const std::string &unlocalizedName, u64 maxValue) { - return { unlocalizedName, maxValue }; - } - - void doLater(const std::function &function) { - static std::mutex tasksMutex; - std::scoped_lock lock(tasksMutex); - - getDeferredCalls().push_back(function); - } - - std::vector> &getDeferredCalls() { - static std::vector> deferredCalls; - - return deferredCalls; - } - - } - - namespace ImHexApi::System { namespace impl { diff --git a/lib/libimhex/source/api/task.cpp b/lib/libimhex/source/api/task.cpp index b6d2f15d3..a56777c10 100644 --- a/lib/libimhex/source/api/task.cpp +++ b/lib/libimhex/source/api/task.cpp @@ -6,66 +6,174 @@ namespace hex { - std::list Task::s_runningTasks; - std::mutex Task::s_taskMutex; + std::mutex TaskManager::s_deferredCallsMutex; - Task::Task(const std::string &unlocalizedName, u64 maxValue) : m_name(LangEntry(unlocalizedName)), m_maxValue(maxValue), m_currValue(0) { - std::scoped_lock lock(Task::s_taskMutex); + std::list> TaskManager::s_tasks; + std::list> TaskManager::s_deferredCalls; - Task::s_runningTasks.push_back(this); - } + Task::Task(std::string unlocalizedName, u64 maxValue, std::function function) + : m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) { + this->m_thread = std::thread([this, func = std::move(function)] { + try { + func(*this); + } catch (const TaskInterruptor &) { + this->interruption(); + } catch (...) { + this->exception(); + } - Task::~Task() { - this->finish(); + this->finish(); + }); } Task::Task(hex::Task &&other) noexcept { - std::scoped_lock lock(Task::s_taskMutex); + std::scoped_lock thisLock(this->m_mutex); + std::scoped_lock otherLock(other.m_mutex); + + this->m_thread = std::move(other.m_thread); + this->m_unlocalizedName = std::move(other.m_unlocalizedName); - this->m_name = other.m_name; this->m_maxValue = other.m_maxValue; this->m_currValue = other.m_currValue; - auto it = std::find(Task::s_runningTasks.begin(), Task::s_runningTasks.end(), &other); - if (it != Task::s_runningTasks.end()) { - *it = this; - } + this->m_finished = other.m_finished; + this->m_hadException = other.m_hadException; + this->m_interrupted = other.m_interrupted; + this->m_shouldInterrupt = other.m_shouldInterrupt; + } + + Task::~Task() { + this->interrupt(); + this->m_thread.join(); + } + + void Task::update(u64 value) { + std::scoped_lock lock(this->m_mutex); + + this->m_currValue = value; + + if (this->m_shouldInterrupt) + throw TaskInterruptor(); + } + + void Task::setMaxValue(u64 value) { + std::scoped_lock lock(this->m_mutex); + + this->m_maxValue = value; + } + + + void Task::interrupt() { + std::scoped_lock lock(this->m_mutex); + + this->m_shouldInterrupt = true; + } + + bool Task::isFinished() const { + std::scoped_lock lock(this->m_mutex); + + return this->m_finished; + } + + bool Task::hadException() const { + std::scoped_lock lock(this->m_mutex); + + return this->m_hadException; + } + + bool Task::wasInterrupted() const { + std::scoped_lock lock(this->m_mutex); + + return this->m_interrupted; + } + + void Task::clearException() { + std::scoped_lock lock(this->m_mutex); + + this->m_hadException = false; + } + + const std::string &Task::getUnlocalizedName() { + return this->m_unlocalizedName; + } + + u64 Task::getValue() const { + return this->m_currValue; + } + + u64 Task::getMaxValue() const { + return this->m_maxValue; } void Task::finish() { - std::scoped_lock lock(Task::s_taskMutex); + std::scoped_lock lock(this->m_mutex); - Task::s_runningTasks.remove(this); + this->m_finished = true; } - void Task::setMaxValue(u64 maxValue) { - this->m_maxValue = maxValue; + void Task::interruption() { + std::scoped_lock lock(this->m_mutex); + + this->m_interrupted = true; } - void Task::update(u64 currValue) { - if (this->m_currValue < this->m_maxValue) - this->m_currValue = currValue; + void Task::exception() { + std::scoped_lock lock(this->m_mutex); + + this->m_hadException = true; } - double Task::getProgress() const { - if (this->m_maxValue == 0) - return 100; - return static_cast(this->m_currValue) / static_cast(this->m_maxValue); + bool TaskHolder::isRunning() const { + return !m_task.expired() && !m_task.lock()->isFinished(); } - bool Task::isPending() const { - return this->m_maxValue == 0; + bool TaskHolder::hadException() const { + return m_task.expired() || m_task.lock()->hadException(); } - const std::string &Task::getName() const { - return this->m_name; + bool TaskHolder::wasInterrupted() const { + return m_task.expired() || m_task.lock()->wasInterrupted(); } - size_t Task::getRunningTaskCount() { - std::scoped_lock lock(Task::s_taskMutex); + void TaskHolder::interrupt() { + if (!this->m_task.expired()) + this->m_task.lock()->interrupt(); + } - return Task::s_runningTasks.size(); + + TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function function) { + s_tasks.emplace_back(std::make_shared(std::move(name), maxValue, std::move(function))); + + return TaskHolder(s_tasks.back()); + } + + void TaskManager::collectGarbage() { + std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); }); + } + + std::list> &TaskManager::getRunningTasks() { + return s_tasks; + } + + size_t TaskManager::getRunningTaskCount() { + return s_tasks.size(); + } + + + void TaskManager::doLater(const std::function &function) { + std::scoped_lock lock(s_deferredCallsMutex); + + s_deferredCalls.push_back(function); + } + + void TaskManager::runDeferredCalls() { + std::scoped_lock lock(s_deferredCallsMutex); + + for (const auto &call : s_deferredCalls) + call(); + + s_deferredCalls.clear(); } } \ No newline at end of file diff --git a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp index aee98fa2c..66e42bf2b 100644 --- a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp +++ b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp @@ -13,6 +13,8 @@ #include +#include + namespace ImGui { int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) { @@ -536,7 +538,7 @@ namespace ImGui { const ImGuiStyle &style = g.Style; ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset); - ImVec2 size = CalcItemSize(ImVec2(100, 5), 100, g.FontSize + style.FramePadding.y * 2.0f); + ImVec2 size = CalcItemSize(ImVec2(100, 5) * hex::ImHexApi::System::getGlobalScale(), 100, g.FontSize + style.FramePadding.y * 2.0f); ImRect bb(pos, pos + size); ItemSize(size, 0); if (!ItemAdd(bb, 0)) diff --git a/lib/libimhex/source/ui/view.cpp b/lib/libimhex/source/ui/view.cpp index 0bf24c5a4..853c5bae2 100644 --- a/lib/libimhex/source/ui/view.cpp +++ b/lib/libimhex/source/ui/view.cpp @@ -49,7 +49,7 @@ namespace hex { } ImVec2 View::getMinSize() const { - return scaled(ImVec2(480, 720)); + return scaled(ImVec2(10, 10)); } ImVec2 View::getMaxSize() const { diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index 6e429fe6a..da0f119d2 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -173,7 +173,6 @@ namespace hex::init { ContentRegistry::Provider::getEntries().clear(); ImHexApi::System::getInitArguments().clear(); - ImHexApi::Tasks::getDeferredCalls().clear(); ImHexApi::HexEditor::impl::getBackgroundHighlights().clear(); ImHexApi::HexEditor::impl::getForegroundHighlights().clear(); ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear(); @@ -215,7 +214,7 @@ namespace hex::init { ShortcutManager::clearShortcuts(); - hex::Task::getRunningTasks().clear(); + TaskManager::getRunningTasks().clear(); ContentRegistry::DataProcessorNode::getEntries().clear(); diff --git a/main/source/window/window.cpp b/main/source/window/window.cpp index 9f8a73673..56535334c 100644 --- a/main/source/window/window.cpp +++ b/main/source/window/window.cpp @@ -86,11 +86,11 @@ namespace hex { { for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) { if (argument == "no-plugins") { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Plugins"); }); + TaskManager::doLater([] { ImGui::OpenPopup("No Plugins"); }); } else if (argument == "no-builtin-plugin") { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); }); + TaskManager::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); }); } else if (argument == "multiple-builtin-plugins") { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); }); + TaskManager::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); }); } } } @@ -179,7 +179,7 @@ namespace hex { } else { glfwPollEvents(); - bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty(); + bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || TaskManager::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty(); const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime)); if ((this->m_lastFrameTime - this->m_frameRateUnlockTime) > 5 && this->m_frameRateTemporarilyUnlocked && !frameRateUnlocked) { @@ -424,7 +424,6 @@ namespace hex { } } - this->m_popupsToOpen.remove_if([](const auto &name) { if (ImGui::IsPopupOpen(name.c_str())) return true; @@ -434,17 +433,12 @@ namespace hex { return false; }); + TaskManager::runDeferredCalls(); + EventManager::post(); } void Window::frame() { - { - auto &calls = ImHexApi::Tasks::getDeferredCalls(); - for (const auto &callback : calls) - callback(); - calls.clear(); - } - auto &io = ImGui::GetIO(); for (auto &[name, view] : ContentRegistry::Views::getEntries()) { ImGui::GetCurrentContext()->NextWindowData.ClearFlags(); @@ -489,6 +483,8 @@ namespace hex { void Window::frameEnd() { EventManager::post(); + TaskManager::collectGarbage(); + this->endNativeWindowFrame(); ImGui::Render(); diff --git a/plugins/builtin/include/content/views/view_disassembler.hpp b/plugins/builtin/include/content/views/view_disassembler.hpp index 3bbaadd30..eb506555b 100644 --- a/plugins/builtin/include/content/views/view_disassembler.hpp +++ b/plugins/builtin/include/content/views/view_disassembler.hpp @@ -28,7 +28,7 @@ namespace hex::plugin::builtin { void drawContent() override; private: - bool m_disassembling = false; + TaskHolder m_disassemblerTask; u64 m_baseAddress = 0; ui::SelectedRegion m_range = ui::SelectedRegion::EntireData; diff --git a/plugins/builtin/include/content/views/view_find.hpp b/plugins/builtin/include/content/views/view_find.hpp index 368237619..836cd583e 100644 --- a/plugins/builtin/include/content/views/view_find.hpp +++ b/plugins/builtin/include/content/views/view_find.hpp @@ -74,7 +74,7 @@ namespace hex::plugin::builtin { std::map> m_foundOccurrences, m_sortedOccurrences; std::map m_occurrenceTree; - std::atomic m_searchRunning; + TaskHolder m_searchTask; bool m_settingsValid = false; std::string m_currFilter; diff --git a/plugins/builtin/include/content/views/view_information.hpp b/plugins/builtin/include/content/views/view_information.hpp index 779e9c754..0e8cd81df 100644 --- a/plugins/builtin/include/content/views/view_information.hpp +++ b/plugins/builtin/include/content/views/view_information.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -27,7 +28,7 @@ namespace hex::plugin::builtin { double m_entropyHandlePosition; std::array m_valueCounts = { 0 }; - bool m_analyzing = false; + TaskHolder m_analyzerTask; Region m_analyzedRegion = { 0, 0 }; diff --git a/plugins/builtin/include/content/views/view_yara.hpp b/plugins/builtin/include/content/views/view_yara.hpp index 7fec699ad..af426cc81 100644 --- a/plugins/builtin/include/content/views/view_yara.hpp +++ b/plugins/builtin/include/content/views/view_yara.hpp @@ -5,6 +5,8 @@ #include #include +#include + namespace hex::plugin::builtin { class ViewYara : public View { @@ -29,7 +31,7 @@ namespace hex::plugin::builtin { std::vector> m_rules; std::vector m_matches; u32 m_selectedRule = 0; - bool m_matching = false; + TaskHolder m_matcherTask; std::vector m_consoleMessages; diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index 02729f3ef..77d6de100 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -30,14 +30,14 @@ namespace hex::plugin::builtin { EventManager::subscribe([](GLFWwindow *window) { if (ImHexApi::Provider::isDirty()) { glfwSetWindowShouldClose(window, GLFW_FALSE); - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); }); } }); EventManager::subscribe([](hex::prv::Provider *provider, bool *shouldClose) { if (provider->isDirty()) { *shouldClose = false; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.close_provider.title"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.popup.close_provider.title"_lang); }); } }); @@ -87,12 +87,12 @@ namespace hex::plugin::builtin { if (provider->hasFilePicker()) { if (!provider->handleFilePicker()) { - ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } if (!provider->open()) { View::showErrorPopup("hex.builtin.popup.error.open"_lang); - ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } } @@ -101,7 +101,7 @@ namespace hex::plugin::builtin { else { if (!provider->open() || !provider->isAvailable()) { View::showErrorPopup("hex.builtin.popup.error.open"_lang); - ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); } } }); diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index 22f57b1e6..6dd843a14 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -9,8 +9,6 @@ #include #include -#include - namespace hex::plugin::builtin { static bool g_demoWindowOpen = false; @@ -20,7 +18,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.file", 1000); ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1050, [&] { - bool taskRunning = Task::getRunningTaskCount() > 0; + bool taskRunning = TaskManager::getRunningTaskCount() > 0; if (ImGui::MenuItem("hex.builtin.menu.file.open_file"_lang, "CTRL + O", false, !taskRunning)) { @@ -44,7 +42,7 @@ namespace hex::plugin::builtin { /* File open, quit imhex */ ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1150, [&] { bool providerValid = ImHexApi::Provider::isValid(); - bool taskRunning = Task::getRunningTaskCount() > 0; + bool taskRunning = TaskManager::getRunningTaskCount() > 0; if (ImGui::MenuItem("hex.builtin.menu.file.close"_lang, "CTRL + W", false, providerValid && !taskRunning)) { ImHexApi::Provider::remove(ImHexApi::Provider::get()); @@ -59,7 +57,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1250, [&] { auto provider = ImHexApi::Provider::get(); bool providerValid = ImHexApi::Provider::isValid(); - bool taskRunning = Task::getRunningTaskCount() > 0; + bool taskRunning = TaskManager::getRunningTaskCount() > 0; if (ImGui::MenuItem("hex.builtin.menu.file.open_project"_lang, "", false, !taskRunning)) { fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} @@ -85,7 +83,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1300, [&] { auto provider = ImHexApi::Provider::get(); bool providerValid = ImHexApi::Provider::isValid(); - bool taskRunning = Task::getRunningTaskCount() > 0; + bool taskRunning = TaskManager::getRunningTaskCount() > 0; /* Import */ if (ImGui::BeginMenu("hex.builtin.menu.file.import"_lang, !taskRunning)) { @@ -126,9 +124,7 @@ namespace hex::plugin::builtin { if (ImGui::MenuItem("hex.builtin.menu.file.import.ips"_lang, nullptr, false)) { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { - std::thread([path] { - auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0); - + TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) { auto patchData = fs::File(path, fs::File::Mode::Read).readBytes(); auto patch = hex::loadIPSPatch(patchData); @@ -144,15 +140,13 @@ namespace hex::plugin::builtin { } provider->createUndoPoint(); - }).detach(); + }); }); } if (ImGui::MenuItem("hex.builtin.menu.file.import.ips32"_lang, nullptr, false)) { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { - std::thread([path] { - auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0); - + TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) { auto patchData = fs::File(path, fs::File::Mode::Read).readBytes(); auto patch = hex::loadIPS32Patch(patchData); @@ -168,7 +162,7 @@ namespace hex::plugin::builtin { } provider->createUndoPoint(); - }).detach(); + }); }); } @@ -186,12 +180,10 @@ namespace hex::plugin::builtin { patches[0x00454F45] = value; } - std::thread([patches] { - auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0); - + TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) { auto data = generateIPSPatch(patches); - ImHexApi::Tasks::doLater([data] { + TaskManager::doLater([data] { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { auto file = fs::File(path, fs::File::Mode::Create); if (!file.isValid()) { @@ -202,7 +194,7 @@ namespace hex::plugin::builtin { file.write(data); }); }); - }).detach(); + }); } if (ImGui::MenuItem("hex.builtin.menu.file.export.ips32"_lang, nullptr, false)) { @@ -213,23 +205,21 @@ namespace hex::plugin::builtin { patches[0x45454F45] = value; } - std::thread([patches] { - auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0); - + TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) { auto data = generateIPS32Patch(patches); - ImHexApi::Tasks::doLater([data] { + TaskManager::doLater([data] { fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) { auto file = fs::File(path, fs::File::Mode::Create); if (!file.isValid()) { - View::showErrorPopup("hex.builtin.menu.file.export.popup.create"_lang); + View::showErrorPopup("hex.builtin.menu.file.export.base64.popup.export_error"_lang); return; } file.write(data); }); }); - }).detach(); + }); } ImGui::EndMenu(); diff --git a/plugins/builtin/source/content/tools_entries.cpp b/plugins/builtin/source/content/tools_entries.cpp index 79843ce1e..1d7d7465c 100644 --- a/plugins/builtin/source/content/tools_entries.cpp +++ b/plugins/builtin/source/content/tools_entries.cpp @@ -745,15 +745,15 @@ namespace hex::plugin::builtin { void drawFileToolShredder() { - static bool shredding = false; static std::u8string selectedFile; static bool fastMode = false; + static TaskHolder shredderTask; ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.warning"_lang); ImGui::NewLine(); if (ImGui::BeginChild("settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 4 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { - ImGui::BeginDisabled(shredding); + ImGui::BeginDisabled(shredderTask.isRunning()); { ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.input"_lang); ImGui::SameLine(); @@ -771,17 +771,14 @@ namespace hex::plugin::builtin { } ImGui::EndChild(); - if (shredding) + if (shredderTask.isRunning()) ImGui::TextSpinner("hex.builtin.tools.file_tools.shredder.shredding"_lang); else { ImGui::BeginDisabled(selectedFile.empty()); { if (ImGui::Button("hex.builtin.tools.file_tools.shredder.shred"_lang)) { - shredding = true; - - std::thread([] { + shredderTask = TaskManager::createTask("hex.builtin.tools.file_tools.shredder.shredding", 0, [](auto &task) { ON_SCOPE_EXIT { - shredding = false; selectedFile.clear(); }; fs::File file(selectedFile, fs::File::Mode::Write); @@ -791,6 +788,8 @@ namespace hex::plugin::builtin { return; } + task.setMaxValue(file.getSize()); + std::vector> overwritePattern; if (fastMode) { /* Should be sufficient for modern disks */ @@ -803,40 +802,40 @@ namespace hex::plugin::builtin { /* Fill fixed patterns */ overwritePattern = { - { }, - { }, - {}, - {}, - { 0x55, 0x55, 0x55 }, - { 0xAA, 0xAA, 0xAA }, - { 0x92, 0x49, 0x24 }, - { 0x49, 0x24, 0x92 }, - { 0x24, 0x92, 0x49 }, - { 0x00, 0x00, 0x00 }, - { 0x11, 0x11, 0x11 }, - { 0x22, 0x22, 0x22 }, - { 0x33, 0x33, 0x44 }, - { 0x55, 0x55, 0x55 }, - { 0x66, 0x66, 0x66 }, - { 0x77, 0x77, 0x77 }, - { 0x88, 0x88, 0x88 }, - { 0x99, 0x99, 0x99 }, - { 0xAA, 0xAA, 0xAA }, - { 0xBB, 0xBB, 0xBB }, - { 0xCC, 0xCC, 0xCC }, - { 0xDD, 0xDD, 0xDD }, - { 0xEE, 0xEE, 0xEE }, - { 0xFF, 0xFF, 0xFF }, - { 0x92, 0x49, 0x24 }, - { 0x49, 0x24, 0x92 }, - { 0x24, 0x92, 0x49 }, - { 0x6D, 0xB6, 0xDB }, - { 0xB6, 0xDB, 0x6D }, - { 0xBD, 0x6D, 0xB6 }, - {}, - {}, - {}, - {} + { }, + { }, + {}, + {}, + { 0x55, 0x55, 0x55 }, + { 0xAA, 0xAA, 0xAA }, + { 0x92, 0x49, 0x24 }, + { 0x49, 0x24, 0x92 }, + { 0x24, 0x92, 0x49 }, + { 0x00, 0x00, 0x00 }, + { 0x11, 0x11, 0x11 }, + { 0x22, 0x22, 0x22 }, + { 0x33, 0x33, 0x44 }, + { 0x55, 0x55, 0x55 }, + { 0x66, 0x66, 0x66 }, + { 0x77, 0x77, 0x77 }, + { 0x88, 0x88, 0x88 }, + { 0x99, 0x99, 0x99 }, + { 0xAA, 0xAA, 0xAA }, + { 0xBB, 0xBB, 0xBB }, + { 0xCC, 0xCC, 0xCC }, + { 0xDD, 0xDD, 0xDD }, + { 0xEE, 0xEE, 0xEE }, + { 0xFF, 0xFF, 0xFF }, + { 0x92, 0x49, 0x24 }, + { 0x49, 0x24, 0x92 }, + { 0x24, 0x92, 0x49 }, + { 0x6D, 0xB6, 0xDB }, + { 0xB6, 0xDB, 0x6D }, + { 0xBD, 0x6D, 0xB6 }, + {}, + {}, + {}, + {} }; /* Fill random patterns */ @@ -848,7 +847,6 @@ namespace hex::plugin::builtin { size_t fileSize = file.getSize(); - auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.shredder.shredding", fileSize); for (const auto &pattern : overwritePattern) { for (u64 offset = 0; offset < fileSize; offset += 3) { file.write(pattern.data(), std::min(pattern.size(), fileSize - offset)); @@ -861,7 +859,7 @@ namespace hex::plugin::builtin { file.remove(); View::showInfoPopup("hex.builtin.tools.file_tools.shredder.success"_lang); - }).detach(); + }); } } ImGui::EndDisabled(); @@ -890,14 +888,14 @@ namespace hex::plugin::builtin { 1 }; - static bool splitting = false; static std::u8string selectedFile; static std::u8string baseOutputPath; static u64 splitSize = sizes[0]; static int selectedItem = 0; + static TaskHolder splitterTask; if (ImGui::BeginChild("split_settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 7 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) { - ImGui::BeginDisabled(splitting); + ImGui::BeginDisabled(splitterTask.isRunning()); { ImGui::InputText("##path", selectedFile); ImGui::SameLine(); @@ -926,7 +924,7 @@ namespace hex::plugin::builtin { } } ImGui::EndDisabled(); - ImGui::BeginDisabled(splitting || selectedItem != sizes.size() - 1); + ImGui::BeginDisabled(splitterTask.isRunning() || selectedItem != sizes.size() - 1); { ImGui::InputScalar("###custom_size", ImGuiDataType_U64, &splitSize); ImGui::SameLine(); @@ -938,15 +936,13 @@ namespace hex::plugin::builtin { ImGui::BeginDisabled(selectedFile.empty() || baseOutputPath.empty() || splitSize == 0); { - if (splitting) + if (splitterTask.isRunning()) ImGui::TextSpinner("hex.builtin.tools.file_tools.splitter.splitting"_lang); else { if (ImGui::Button("hex.builtin.tools.file_tools.splitter.split"_lang)) { - splitting = true; - std::thread([] { + splitterTask = TaskManager::createTask("hex.builtin.tools.file_tools.splitter.splitting", 0, [](auto &task) { ON_SCOPE_EXIT { - splitting = false; selectedFile.clear(); baseOutputPath.clear(); }; @@ -962,7 +958,8 @@ namespace hex::plugin::builtin { return; } - auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.splitter.splitting", file.getSize()); + task.setMaxValue(file.getSize()); + u32 index = 1; for (u64 offset = 0; offset < file.getSize(); offset += splitSize) { task.update(offset); @@ -987,7 +984,7 @@ namespace hex::plugin::builtin { } View::showInfoPopup("hex.builtin.tools.file_tools.splitter.success"_lang); - }).detach(); + }); } } } @@ -995,10 +992,10 @@ namespace hex::plugin::builtin { } void drawFileToolCombiner() { - static bool combining = false; static std::vector files; static std::u8string outputPath; static u32 selectedIndex; + static TaskHolder combinerTask; if (ImGui::BeginTable("files_table", 2, ImGuiTableFlags_SizingStretchProp)) { ImGui::TableSetupColumn("file list", ImGuiTableColumnFlags_NoHeaderLabel, 10); @@ -1041,7 +1038,7 @@ namespace hex::plugin::builtin { ImGui::TableNextRow(); ImGui::TableNextColumn(); - ImGui::BeginDisabled(combining); + ImGui::BeginDisabled(combinerTask.isRunning()); { if (ImGui::Button("hex.builtin.tools.file_tools.combiner.add"_lang)) { fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) { @@ -1063,7 +1060,7 @@ namespace hex::plugin::builtin { ImGui::EndTable(); } - ImGui::BeginDisabled(combining); + ImGui::BeginDisabled(combinerTask.isRunning()); { ImGui::InputText("##output_path", outputPath); ImGui::SameLine(); @@ -1079,14 +1076,12 @@ namespace hex::plugin::builtin { ImGui::BeginDisabled(files.empty() || outputPath.empty()); { - if (combining) + if (combinerTask.isRunning()) ImGui::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang); else { if (ImGui::Button("hex.builtin.tools.file_tools.combiner.combine"_lang)) { - combining = true; - std::thread([] { - ON_SCOPE_EXIT { combining = false; }; + combinerTask = TaskManager::createTask("hex.builtin.tools.file_tools.combiner.combining", 0, [](auto &task) { fs::File output(outputPath, fs::File::Mode::Create); @@ -1095,7 +1090,7 @@ namespace hex::plugin::builtin { return; } - auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.combiner.combining", files.size()); + task.setMaxValue(files.size()); u64 fileIndex = 0; for (const auto &file : files) { @@ -1121,7 +1116,7 @@ namespace hex::plugin::builtin { outputPath.clear(); View::showInfoPopup("hex.builtin.tools.file_tools.combiner.success"_lang); - }).detach(); + }); } } } diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 79f3f302b..19c8d7449 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -161,19 +161,19 @@ namespace hex::plugin::builtin { EventManager::subscribe([](const std::string &message) { s_popupMessage = message; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.info"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.common.info"_lang); }); }); EventManager::subscribe([](const std::string &message) { s_popupMessage = message; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.error"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.common.error"_lang); }); }); EventManager::subscribe([](const std::string &message) { s_popupMessage = message; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.fatal"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.common.fatal"_lang); }); }); EventManager::subscribe([](const std::string &message, const std::function &yesCallback, const std::function &noCallback) { @@ -182,7 +182,7 @@ namespace hex::plugin::builtin { s_yesCallback = yesCallback; s_noCallback = noCallback; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.question"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.common.question"_lang); }); }); EventManager::subscribe([](const std::vector &paths, const std::vector &validExtensions, const std::function &callback) { @@ -191,7 +191,7 @@ namespace hex::plugin::builtin { s_selectableFilesValidExtensions = validExtensions; s_selectableFileOpenCallback = callback; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.choose_file"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.common.choose_file"_lang); }); }); } @@ -213,28 +213,51 @@ namespace hex::plugin::builtin { }); ContentRegistry::Interface::addFooterItem([] { - size_t taskCount = 0; - double taskProgress = 0.0; - std::string taskName; - - { - std::scoped_lock lock(Task::getTaskMutex()); - - taskCount = Task::getRunningTasks().size(); - if (taskCount > 0) { - auto frontTask = Task::getRunningTasks().front(); - taskProgress = frontTask->getProgress(); - taskName = frontTask->getName(); - } - } - + auto taskCount = TaskManager::getRunningTaskCount(); if (taskCount > 0) { + auto &tasks = TaskManager::getRunningTasks(); + auto frontTask = tasks.front(); + + auto widgetStart = ImGui::GetCursorPos(); + ImGui::TextSpinner(hex::format("({})", taskCount).c_str()); + ImGui::SameLine(); + ImGui::SmallProgressBar(frontTask->getMaxValue() == 0 ? 1 : (float(frontTask->getValue()) / frontTask->getMaxValue()), (ImGui::GetCurrentWindow()->MenuBarHeight() - 10_scaled) / 2.0); + ImGui::SameLine(); + + auto widgetEnd = ImGui::GetCursorPos(); + ImGui::SetCursorPos(widgetStart); + ImGui::InvisibleButton("FrontTask", ImVec2(widgetEnd.x - widgetStart.x, ImGui::GetCurrentWindow()->MenuBarHeight())); + ImGui::SetCursorPos(widgetEnd); + + ImGui::InfoTooltip(LangEntry(frontTask->getUnlocalizedName()).get().c_str()); + + if (ImGui::BeginPopupContextItem("FrontTask", ImGuiPopupFlags_MouseButtonLeft)) { + for (const auto &task : tasks) { + ImGui::PushID(&task); + ImGui::TextFormatted("{}", LangEntry(task->getUnlocalizedName())); + ImGui::SameLine(); + ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); + ImGui::SameLine(); + ImGui::SmallProgressBar(frontTask->getMaxValue() == 0 ? 1 : (float(frontTask->getValue()) / frontTask->getMaxValue()), (ImGui::GetTextLineHeightWithSpacing() - 5_scaled) / 2); + ImGui::SameLine(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + if (ImGui::ToolBarButton(ICON_VS_DEBUG_STOP, ImGui::GetStyleColorVec4(ImGuiCol_Text))) + task->interrupt(); + ImGui::PopStyleVar(); + + ImGui::PopID(); + } + ImGui::EndPopup(); + } ImGui::SameLine(); - ImGui::SmallProgressBar(taskProgress, (ImGui::GetCurrentWindow()->MenuBarHeight() - 10_scaled) / 2.0); - ImGui::InfoTooltip(taskName.c_str()); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, scaled(ImVec2(1, 2))); + if (ImGui::ToolBarButton(ICON_VS_DEBUG_STOP, ImGui::GetStyleColorVec4(ImGuiCol_Text))) + frontTask->interrupt(); + ImGui::PopStyleVar(); } }); } @@ -243,7 +266,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addToolbarItem([] { auto provider = ImHexApi::Provider::get(); bool providerValid = provider != nullptr; - bool tasksRunning = Task::getRunningTaskCount() > 0; + bool tasksRunning = TaskManager::getRunningTaskCount() > 0; // Undo ImGui::BeginDisabled(!providerValid || !provider->canUndo()); diff --git a/plugins/builtin/source/content/views/view_about.cpp b/plugins/builtin/source/content/views/view_about.cpp index 2d17c7ab7..373b3d37b 100644 --- a/plugins/builtin/source/content/views/view_about.cpp +++ b/plugins/builtin/source/content/views/view_about.cpp @@ -14,7 +14,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.help", 1000, [&, this] { if (ImGui::MenuItem("hex.builtin.view.help.about.name"_lang, "")) { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.help.about.name").c_str()); }); + TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.help.about.name").c_str()); }); this->m_aboutWindowOpen = true; this->getWindowOpenState() = true; } diff --git a/plugins/builtin/source/content/views/view_disassembler.cpp b/plugins/builtin/source/content/views/view_disassembler.cpp index edf0877e9..4f813de0e 100644 --- a/plugins/builtin/source/content/views/view_disassembler.cpp +++ b/plugins/builtin/source/content/views/view_disassembler.cpp @@ -24,9 +24,8 @@ namespace hex::plugin::builtin { void ViewDisassembler::disassemble() { this->m_disassembly.clear(); - this->m_disassembling = true; - std::thread([this] { + this->m_disassemblerTask = TaskManager::createTask("hex.builtin.view.disassembler.disassembling", this->m_codeRegion.getSize(), [this](auto &task) { csh capstoneHandle; cs_insn *instructions = nullptr; @@ -40,7 +39,6 @@ namespace hex::plugin::builtin { std::vector buffer(2048, 0x00); size_t size = this->m_codeRegion.getSize(); - auto task = ImHexApi::Tasks::createTask("hex.builtin.view.disassembler.disassembling", size); for (u64 address = 0; address < size; address += 2048) { task.update(address); @@ -80,9 +78,7 @@ namespace hex::plugin::builtin { cs_close(&capstoneHandle); } - - this->m_disassembling = false; - }).detach(); + }); } void ViewDisassembler::drawContent() { @@ -321,14 +317,14 @@ namespace hex::plugin::builtin { } ImGui::EndChild(); - ImGui::BeginDisabled(this->m_disassembling); + ImGui::BeginDisabled(this->m_disassemblerTask.isRunning()); { if (ImGui::Button("hex.builtin.view.disassembler.disassemble"_lang)) this->disassemble(); } ImGui::EndDisabled(); - if (this->m_disassembling) { + if (this->m_disassemblerTask.isRunning()) { ImGui::SameLine(); ImGui::TextSpinner("hex.builtin.view.disassembler.disassembling"_lang); } @@ -345,7 +341,7 @@ namespace hex::plugin::builtin { ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.bytes"_lang); ImGui::TableSetupColumn("hex.builtin.view.disassembler.disassembly.title"_lang); - if (!this->m_disassembling) { + if (!this->m_disassemblerTask.isRunning()) { ImGuiListClipper clipper; clipper.Begin(this->m_disassembly.size()); diff --git a/plugins/builtin/source/content/views/view_find.cpp b/plugins/builtin/source/content/views/view_find.cpp index cfe884554..f5888367a 100644 --- a/plugins/builtin/source/content/views/view_find.cpp +++ b/plugins/builtin/source/content/views/view_find.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include @@ -319,9 +318,7 @@ namespace hex::plugin::builtin { } }(); - this->m_searchRunning = true; - std::thread([this, settings = this->m_searchSettings, searchRegion]{ - auto task = ImHexApi::Tasks::createTask("hex.builtin.view.find.searching", searchRegion.getSize()); + this->m_searchTask = TaskManager::createTask("hex.builtin.view.find.searching", searchRegion.getSize(), [this, settings = this->m_searchSettings, searchRegion](auto &task) { auto provider = ImHexApi::Provider::get(); switch (settings.mode) { @@ -338,7 +335,7 @@ namespace hex::plugin::builtin { case BinaryPattern: this->m_foundOccurrences[provider] = searchBinaryPattern(task, provider, searchRegion, settings.binaryPattern); break; - } + } this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider]; @@ -346,9 +343,7 @@ namespace hex::plugin::builtin { for (const auto &occurrence : this->m_foundOccurrences[provider]) intervals.push_back(OccurrenceTree::interval(occurrence.region.getStartAddress(), occurrence.region.getEndAddress(), occurrence)); this->m_occurrenceTree[provider] = std::move(intervals); - - this->m_searchRunning = false; - }).detach(); + }); } std::string ViewFind::decodeValue(prv::Provider *provider, Occurrence occurrence) const { @@ -408,7 +403,7 @@ namespace hex::plugin::builtin { if (ImGui::Begin(View::toWindowName("hex.builtin.view.find.name").c_str(), &this->getWindowOpenState())) { auto provider = ImHexApi::Provider::get(); - ImGui::BeginDisabled(this->m_searchRunning); + ImGui::BeginDisabled(this->m_searchTask.isRunning()); { ui::regionSelectionPicker(&this->m_searchSettings.range, true, true); diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index 974a10680..4fdd6f220 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -189,13 +189,10 @@ namespace hex::plugin::builtin { ImGui::EndTabBar(); } - if (!this->m_searchRunning && !searchSequence.empty() && this->m_shouldSearch) { - this->m_searchRunning = true; - std::thread([this, searchSequence, editor]{ - auto task = ImHexApi::Tasks::createTask("Searching", ImHexApi::Provider::get()->getSize()); - + if (!this->m_searchTask.isRunning() && !searchSequence.empty() && this->m_shouldSearch) { + this->m_searchTask = TaskManager::createTask("hex.builtin.common.processing", ImHexApi::Provider::get()->getActualSize(), [this, editor, searchSequence](auto &) { if (auto region = this->findSequence(editor, searchSequence, this->m_backwards); region.has_value()) { - ImHexApi::Tasks::doLater([editor, region]{ + TaskManager::doLater([editor, region]{ editor->setSelection(region->getStartAddress(), region->getEndAddress()); editor->jumpToSelection(); }); @@ -203,8 +200,7 @@ namespace hex::plugin::builtin { this->m_shouldSearch = false; this->m_requestFocus = true; - this->m_searchRunning = false; - }).detach(); + }); } } @@ -218,7 +214,7 @@ namespace hex::plugin::builtin { this->m_requestFocus = false; } - ImGui::BeginDisabled(this->m_searchRunning); + ImGui::BeginDisabled(this->m_searchTask.isRunning()); { ImGui::SameLine(); if (ImGui::IconButton(ICON_VS_SEARCH "##search", ButtonColor, ButtonSize)) { @@ -285,7 +281,7 @@ namespace hex::plugin::builtin { std::atomic m_shouldSearch = false; std::atomic m_backwards = false; - std::atomic m_searchRunning = false; + TaskHolder m_searchTask; }; class PopupBaseAddress : public ViewHexEditor::Popup { diff --git a/plugins/builtin/source/content/views/view_information.cpp b/plugins/builtin/source/content/views/view_information.cpp index 96a926cc3..a23f45e33 100644 --- a/plugins/builtin/source/content/views/view_information.cpp +++ b/plugins/builtin/source/content/views/view_information.cpp @@ -4,20 +4,15 @@ #include #include + #include -#include -#include +#include #include #include -#include #include #include #include -#include -#include - -#include #include @@ -80,12 +75,10 @@ namespace hex::plugin::builtin { } void ViewInformation::analyze() { - this->m_analyzing = true; - - std::thread([this] { + this->m_analyzerTask = TaskManager::createTask("hex.builtin.view.information.analyzing", 0, [this](auto &task) { auto provider = ImHexApi::Provider::get(); - auto task = ImHexApi::Tasks::createTask("hex.builtin.view.information.analyzing", provider->getActualSize()); + task.setMaxValue(provider->getActualSize()); this->m_analyzedRegion = { provider->getBaseAddress(), provider->getBaseAddress() + provider->getSize() }; @@ -127,9 +120,7 @@ namespace hex::plugin::builtin { else this->m_highestBlockEntropy = 0; } - - this->m_analyzing = false; - }).detach(); + }); } void ViewInformation::drawContent() { @@ -138,14 +129,14 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); if (ImHexApi::Provider::isValid() && provider->isReadable()) { - ImGui::BeginDisabled(this->m_analyzing); + ImGui::BeginDisabled(this->m_analyzerTask.isRunning()); { if (ImGui::Button("hex.builtin.view.information.analyze"_lang, ImVec2(ImGui::GetContentRegionAvail().x, 0))) this->analyze(); } ImGui::EndDisabled(); - if (this->m_analyzing) { + if (this->m_analyzerTask.isRunning()) { ImGui::TextSpinner("hex.builtin.view.information.analyzing"_lang); } else { ImGui::NewLine(); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 07e090593..113e26431 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -815,10 +815,7 @@ namespace hex::plugin::builtin { EventManager::post(); - std::thread([this, code, &runtime] { - auto task = ImHexApi::Tasks::createTask("hex.builtin.view.pattern_editor.evaluating", 1); - - + TaskManager::createTask("hex.builtin.view.pattern_editor.evaluating", TaskManager::NoProgress, [this, &runtime, code](auto &) { std::map envVars; for (const auto &[id, name, value, type] : this->m_envVarEntries) envVars.insert({ name, value }); @@ -851,7 +848,7 @@ namespace hex::plugin::builtin { this->m_runningEvaluators--; this->m_lastEvaluationProcessed = false; - }).detach(); + }); } } diff --git a/plugins/builtin/source/content/views/view_settings.cpp b/plugins/builtin/source/content/views/view_settings.cpp index 1efe834a8..3ba0e19df 100644 --- a/plugins/builtin/source/content/views/view_settings.cpp +++ b/plugins/builtin/source/content/views/view_settings.cpp @@ -11,14 +11,14 @@ namespace hex::plugin::builtin { ViewSettings::ViewSettings() : View("hex.builtin.view.settings.name") { EventManager::subscribe(this, [this](const std::string &name) { if (name == "Settings") { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.settings.name").c_str()); }); + TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.settings.name").c_str()); }); this->getWindowOpenState() = true; } }); ContentRegistry::Interface::addMenuItem("hex.builtin.menu.help", 2000, [&, this] { if (ImGui::MenuItem("hex.builtin.view.settings.name"_lang)) { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.settings.name").c_str()); }); + TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.settings.name").c_str()); }); this->getWindowOpenState() = true; } }); diff --git a/plugins/builtin/source/content/views/view_store.cpp b/plugins/builtin/source/content/views/view_store.cpp index efefe2f02..3ac759b59 100644 --- a/plugins/builtin/source/content/views/view_store.cpp +++ b/plugins/builtin/source/content/views/view_store.cpp @@ -29,7 +29,7 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.help", 3000, [&, this] { if (ImGui::MenuItem("hex.builtin.view.store.name"_lang)) { - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.store.name").c_str()); }); + TaskManager::doLater([] { ImGui::OpenPopup(View::toWindowName("hex.builtin.view.store.name").c_str()); }); this->getWindowOpenState() = true; } }); diff --git a/plugins/builtin/source/content/views/view_yara.cpp b/plugins/builtin/source/content/views/view_yara.cpp index a01717bb6..dbf8528de 100644 --- a/plugins/builtin/source/content/views/view_yara.cpp +++ b/plugins/builtin/source/content/views/view_yara.cpp @@ -44,7 +44,7 @@ namespace hex::plugin::builtin { if (ImGui::Button("hex.builtin.view.yara.reload"_lang)) this->reloadRules(); } else { - ImGui::BeginDisabled(this->m_matching); + ImGui::BeginDisabled(this->m_matcherTask.isRunning()); { if (ImGui::BeginCombo("hex.builtin.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].first.string().c_str())) { for (u32 i = 0; i < this->m_rules.size(); i++) { @@ -63,7 +63,7 @@ namespace hex::plugin::builtin { } ImGui::EndDisabled(); - if (this->m_matching) { + if (this->m_matcherTask.isRunning()) { ImGui::SameLine(); ImGui::TextSpinner("hex.builtin.view.yara.matching"_lang); } @@ -86,7 +86,7 @@ namespace hex::plugin::builtin { ImGui::TableHeadersRow(); - if (!this->m_matching) { + if (!this->m_matcherTask.isRunning()) { ImGuiListClipper clipper; clipper.Begin(this->m_matches.size()); @@ -173,19 +173,13 @@ namespace hex::plugin::builtin { void ViewYara::applyRules() { this->clearResult(); - this->m_matching = true; - - std::thread([this] { + this->m_matcherTask = TaskManager::createTask("hex.builtin.view.yara.matching", 0, [this](auto &task) { if (!ImHexApi::Provider::isValid()) return; - auto provider = ImHexApi::Provider::get(); - auto task = ImHexApi::Tasks::createTask("hex.builtin.view.yara.matching", provider->getActualSize()); - YR_COMPILER *compiler = nullptr; yr_compiler_create(&compiler); ON_SCOPE_EXIT { yr_compiler_destroy(compiler); - this->m_matching = false; }; yr_compiler_set_include_callback( @@ -209,8 +203,8 @@ namespace hex::plugin::builtin { delete[] ptr; }, - fs::toShortPath(this->m_rules[this->m_selectedRule].second).string().data()); - + fs::toShortPath(this->m_rules[this->m_selectedRule].second).string().data() + ); fs::File file(this->m_rules[this->m_selectedRule].second, fs::File::Mode::Read); if (!file.isValid()) return; @@ -220,7 +214,7 @@ namespace hex::plugin::builtin { yr_compiler_get_error_message(compiler, errorMessage.data(), errorMessage.size()); hex::trim(errorMessage); - ImHexApi::Tasks::doLater([this, errorMessage] { + TaskManager::doLater([this, errorMessage] { this->clearResult(); this->m_consoleMessages.push_back("Error: " + errorMessage); @@ -246,15 +240,14 @@ namespace hex::plugin::builtin { context.currBlock.base = 0; context.currBlock.fetch_data = [](auto *block) -> const u8 * { auto &context = *static_cast(block->context); - auto provider = ImHexApi::Provider::get(); context.buffer.resize(context.currBlock.size); - if (context.buffer.empty()) return nullptr; + if (context.buffer.empty()) + return nullptr; block->size = context.currBlock.size; - provider->read(context.currBlock.base + provider->getBaseAddress(), context.buffer.data(), context.buffer.size()); return context.buffer.data(); @@ -301,11 +294,11 @@ namespace hex::plugin::builtin { ResultContext resultContext; yr_rules_scan_mem_blocks( - rules, &iterator, 0, [](YR_SCAN_CONTEXT *context, int message, void *data, void *userData) -> int { - auto &results = *static_cast(userData); + rules, &iterator, 0, [](YR_SCAN_CONTEXT *context, int message, void *data, void *userData) -> int { + auto &results = *static_cast(userData); - switch (message) { - case CALLBACK_MSG_RULE_MATCHING: + switch (message) { + case CALLBACK_MSG_RULE_MATCHING: { auto rule = static_cast(data); @@ -315,30 +308,30 @@ namespace hex::plugin::builtin { if (rule->strings != nullptr) { yr_rule_strings_foreach(rule, string) { yr_string_matches_foreach(context, string, match) { - results.newMatches.push_back({ rule->identifier, string->identifier, u64(match->offset), size_t(match->match_length), false, 0, 0 }); - } + results.newMatches.push_back({ rule->identifier, string->identifier, u64(match->offset), size_t(match->match_length), false, 0, 0 }); + } } } else { results.newMatches.push_back({ rule->identifier, "", 0, 0, true, 0, 0 }); } } - break; - case CALLBACK_MSG_CONSOLE_LOG: + break; + case CALLBACK_MSG_CONSOLE_LOG: { results.consoleMessages.emplace_back(static_cast(data)); } - break; - default: - break; - } + break; + default: + break; + } - return CALLBACK_CONTINUE; - }, - &resultContext, - 0); + return CALLBACK_CONTINUE; + }, + &resultContext, + 0); - ImHexApi::Tasks::doLater([this, resultContext] { + TaskManager::doLater([this, resultContext] { this->m_matches = resultContext.newMatches; this->m_consoleMessages = resultContext.consoleMessages; @@ -348,7 +341,7 @@ namespace hex::plugin::builtin { match.tooltipId = ImHexApi::HexEditor::addTooltip({ match. address, match.size }, hex::format("{0} [{1}]", match.identifier, match.variable), YaraColor); } }); - }).detach(); + }); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 112d5aad2..539643db4 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -83,7 +83,7 @@ namespace hex::plugin::builtin { if (!provider->open() || !provider->isAvailable()) { View::showErrorPopup("hex.builtin.popup.error.open"_lang); - ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); }); + TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); return; } @@ -517,7 +517,7 @@ namespace hex::plugin::builtin { for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) { if (auto filePath = std::fs::path(path) / CrashBackupFileName; fs::exists(filePath)) { s_safetyBackupPath = filePath; - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.welcome.safety_backup.title"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.welcome.safety_backup.title"_lang); }); } } @@ -526,7 +526,7 @@ namespace hex::plugin::builtin { bool showTipOfTheDay = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1); if (showTipOfTheDay) - ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.welcome.tip_of_the_day"_lang); }); + TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.welcome.tip_of_the_day"_lang); }); } }