diff options
author | Saturneric <[email protected]> | 2022-05-14 18:24:55 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2022-05-14 18:24:55 +0000 |
commit | 5b7501d19064225d2a5ce3d9baf310a4e2a3eb42 (patch) | |
tree | b8d24db89efaec64fd9832938ae4fc42f1661391 | |
parent | Merge remote-tracking branch 'origin/develop-2.0.8' into develop-2.0.8 (diff) | |
download | GpgFrontend-5b7501d19064225d2a5ce3d9baf310a4e2a3eb42.tar.gz GpgFrontend-5b7501d19064225d2a5ce3d9baf310a4e2a3eb42.zip |
feat(core): upgrade task runner system.
-rw-r--r-- | src/core/thread/Task.cpp | 91 | ||||
-rw-r--r-- | src/core/thread/Task.h | 141 | ||||
-rw-r--r-- | src/core/thread/TaskRunner.cpp | 28 | ||||
-rw-r--r-- | src/core/thread/ThreadingModel.h | 34 |
4 files changed, 270 insertions, 24 deletions
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp index 9626ba69..7b8423b2 100644 --- a/src/core/thread/Task.cpp +++ b/src/core/thread/Task.cpp @@ -26,24 +26,48 @@ #include "core/thread/Task.h" +#include <boost/uuid/uuid.hpp> +#include <boost/uuid/uuid_generators.hpp> +#include <boost/uuid/uuid_io.hpp> #include <functional> +#include <string> +#include <utility> #include "core/thread/TaskRunner.h" +#include "easylogging++.h" -GpgFrontend::Thread::Task::Task() { init(); } +GpgFrontend::Thread::Task::Task() : uuid_(generate_uuid()) { + LOG(INFO) << "Task" << uuid_ << "created"; + init(); +} -GpgFrontend::Thread::Task::Task(TaskCallback callback) - : callback_(std::move(callback)) { +GpgFrontend::Thread::Task::Task(TaskCallback callback, + DataObjectPtr data_object) + : uuid_(generate_uuid()), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(data_object) { + LOG(INFO) << "Task" << uuid_ << "created with callback" + << "callback_thread_: " << callback_thread_; init(); } -GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback) - : runnable_(runnable), callback_(std::move(callback)) { +GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback, + DataObjectPtr data_object) + : uuid_(generate_uuid()), + runnable_(std::move(runnable)), + callback_(std::move(callback)), + callback_thread_(QThread::currentThread()), + data_object_(data_object) { init(); + LOG(INFO) << "Task" << uuid_ << "created with runnable and callback" + << "callback_thread_: " << callback_thread_; } GpgFrontend::Thread::Task::~Task() = default; +std::string GpgFrontend::Thread::Task::GetUUID() const { return uuid_; } + void GpgFrontend::Thread::Task::SetFinishAfterRun(bool finish_after_run) { this->finish_after_run_ = finish_after_run; } @@ -51,24 +75,71 @@ void GpgFrontend::Thread::Task::SetFinishAfterRun(bool finish_after_run) { void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; } void GpgFrontend::Thread::Task::init() { - LOG(INFO) << "called"; connect(this, &Task::SignalTaskFinished, this, &Task::before_finish_task); connect(this, &Task::SignalTaskFinished, this, &Task::deleteLater); } void GpgFrontend::Thread::Task::before_finish_task() { - LOG(INFO) << "called"; - if (callback_) callback_(rtn_); + LOG(INFO) << "Task" << uuid_ << "finished"; + if (callback_) { + bool if_invoke = QMetaObject::invokeMethod( + callback_thread_, + [callback = callback_, rtn = rtn_, data_object = data_object_]() { + callback(rtn, data_object); + }); + if (!if_invoke) { + LOG(ERROR) << "failed to invoke callback"; + } + } } void GpgFrontend::Thread::Task::run() { - LOG(INFO) << "called"; + LOG(INFO) << "Task" << uuid_ << "started"; Run(); if (finish_after_run_) emit SignalTaskFinished(); } void GpgFrontend::Thread::Task::Run() { if (runnable_) { - rtn_ = runnable_(); + bool if_invoke = QMetaObject::invokeMethod( + this, [=]() { return runnable_(data_object_); }, &rtn_); + if (!if_invoke) { + LOG(ERROR) << "invokeMethod failed"; + } + } +} + +GpgFrontend::Thread::Task::DataObject::Destructor * +GpgFrontend::Thread::Task::DataObject::get_heap_ptr(size_t bytes_size) { + Destructor *dstr_ptr = new Destructor(); + dstr_ptr->p_obj = malloc(bytes_size); + return dstr_ptr; +} + +GpgFrontend::Thread::Task::DataObject::~DataObject() { + if (!data_objects_.empty()) + LOG(WARNING) << "data_objects_ is not empty" + << "address:" << this; + while (!data_objects_.empty()) { + free_heap_ptr(data_objects_.top()); + data_objects_.pop(); + } +} + +size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() { + return data_objects_.size(); +} + +void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) { + LOG(INFO) << "p_obj: " << ptr->p_obj << "destructor: " << ptr->destroy + << "DataObject:" << this; + if (ptr->destroy != nullptr) { + ptr->destroy(ptr->p_obj); } + free((void *)ptr->p_obj); + delete ptr; +} + +std::string GpgFrontend::Thread::Task::generate_uuid() { + return boost::uuids::to_string(boost::uuids::random_generator()()); } diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h index 4b536176..e2105415 100644 --- a/src/core/thread/Task.h +++ b/src/core/thread/Task.h @@ -28,6 +28,11 @@ #define GPGFRONTEND_TASK_H #include <functional> +#include <memory> +#include <stack> +#include <string> +#include <type_traits> +#include <utility> #include "core/GpgFrontendCore.h" @@ -38,11 +43,97 @@ class TaskRunner; class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { Q_OBJECT public: - using TaskRunnable = std::function<int()>; ///< - using TaskCallback = std::function<void(int)>; ///< + class DataObject; + using DataObjectPtr = std::shared_ptr<DataObject>; ///< + using TaskRunnable = std::function<int(DataObjectPtr)>; ///< + using TaskCallback = std::function<void(int, DataObjectPtr)>; ///< + friend class TaskRunner; /** + * @brief DataObject to be passed to the callback function. + * + */ + class DataObject { + public: + struct Destructor { + const void *p_obj; + void (*destroy)(const void *); + }; + + /** + * @brief Get the Objects Size + * + * @return size_t + */ + size_t GetObjectSize(); + + /** + * @brief + * + * @tparam T + * @param ptr + */ + template <typename T> + void AppendObject(T &&obj) { + LOG(INFO) << "called:" << this; + auto *obj_dstr = this->get_heap_ptr(sizeof(T)); + auto *ptr_heap = new ((void *)obj_dstr->p_obj) T(std::move(obj)); + if (std::is_class_v<T>) { + auto destructor = [](const void *x) { + static_cast<const T *>(x)->~T(); + }; + obj_dstr->destroy = destructor; + } else { + obj_dstr->destroy = nullptr; + } + data_objects_.push(std::move(obj_dstr)); + } + + /** + * @brief + * + * @tparam T + * @return std::shared_ptr<T> + */ + template <typename T> + T PopObject() { + LOG(INFO) << "called:" << this; + if (data_objects_.empty()) throw std::runtime_error("No object to pop"); + auto *obj_dstr = data_objects_.top(); + auto *heap_ptr = (T *)obj_dstr->p_obj; + auto obj = std::move(*(T *)(heap_ptr)); + this->free_heap_ptr(obj_dstr); + data_objects_.pop(); + return obj; + } + + /** + * @brief Destroy the Data Object object + * + */ + ~DataObject(); + + private: + std::stack<Destructor *> data_objects_; ///< + + /** + * @brief Get the heap ptr object + * + * @param bytes_size + * @return void* + */ + Destructor *get_heap_ptr(size_t bytes_size); + + /** + * @brief + * + * @param heap_ptr + */ + void free_heap_ptr(Destructor *); + }; + + /** * @brief Construct a new Task object * */ @@ -52,9 +143,8 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @brief Construct a new Task object * * @param callback The callback function to be executed. - * callback must not be nullptr, and not tp opreate UI object. */ - Task(TaskCallback callback); + Task(TaskCallback callback, DataObjectPtr data_object = nullptr); /** * @brief Construct a new Task object @@ -62,7 +152,9 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * @param runnable */ Task( - TaskRunnable runnable, TaskCallback callback = [](int) {}); + TaskRunnable runnable, + TaskCallback callback = [](int, std::shared_ptr<DataObject>) {}, + DataObjectPtr data = nullptr); /** * @brief Destroy the Task object @@ -76,19 +168,43 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { */ virtual void Run(); + /** + * @brief + * + * @return std::string + */ + std::string GetUUID() const; + signals: + /** + * @brief + * + */ void SignalTaskFinished(); protected: + /** + * @brief Set the Finish After Run object + * + * @param finish_after_run + */ void SetFinishAfterRun(bool finish_after_run); + /** + * @brief + * + * @param rtn + */ void SetRTN(int rtn); private: - TaskCallback callback_; ///< - TaskRunnable runnable_; ///< - bool finish_after_run_ = true; ///< - int rtn_ = 0; ///< + const std::string uuid_; + TaskCallback callback_; ///< + TaskRunnable runnable_; ///< + bool finish_after_run_ = true; ///< + int rtn_ = 0; ///< + QThread *callback_thread_ = nullptr; ///< + DataObjectPtr data_object_ = nullptr; ///< /** * @brief @@ -107,6 +223,13 @@ class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable { * */ virtual void run() override; + + /** + * @brief + * + * @return std::string + */ + static std::string generate_uuid(); }; } // namespace GpgFrontend::Thread diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp index 2223bdda..3b565abb 100644 --- a/src/core/thread/TaskRunner.cpp +++ b/src/core/thread/TaskRunner.cpp @@ -26,6 +26,8 @@ #include "core/thread/TaskRunner.h" +#include <exception> + #include "core/thread/Task.h" #include "easylogging++.h" @@ -34,7 +36,9 @@ GpgFrontend::Thread::TaskRunner::TaskRunner() = default; GpgFrontend::Thread::TaskRunner::~TaskRunner() = default; void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { - LOG(INFO) << "called"; + LOG(INFO) << "called" + << "Post Task" << task->GetUUID(); + if (task == nullptr) return; task->setParent(nullptr); task->moveToThread(this); @@ -46,13 +50,14 @@ void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) { } void GpgFrontend::Thread::TaskRunner::run() { - LOG(INFO) << "called"; + LOG(INFO) << "called" + << "thread id:" << QThread::currentThreadId(); while (true) { if (tasks.empty()) { - LOG(INFO) << "TaskRunner: No tasks to run"; + LOG(INFO) << "TaskRunner: No tasks to run."; exec(); } else { - LOG(INFO) << "TaskRunner: Running task, queue size:" << tasks.size(); + LOG(INFO) << "TaskRunner: Queue size:" << tasks.size(); Task* task = nullptr; { @@ -60,7 +65,20 @@ void GpgFrontend::Thread::TaskRunner::run() { task = std::move(tasks.front()); tasks.pop(); } - if (task != nullptr) task->run(); + + if (task != nullptr) { + // Run the task + LOG(INFO) << "TaskRunner: Running Task" << task->GetUUID(); + try { + task->run(); + } catch (const std::exception& e) { + LOG(ERROR) << "TaskRunner: Exception in Task" << task->GetUUID() + << "Exception: " << e.what(); + } catch (...) { + LOG(ERROR) << "TaskRunner: Unknwon Exception in Task" + << task->GetUUID(); + } + } } } } diff --git a/src/core/thread/ThreadingModel.h b/src/core/thread/ThreadingModel.h new file mode 100644 index 00000000..ceb2b053 --- /dev/null +++ b/src/core/thread/ThreadingModel.h @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2021 Saturneric + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * The source code version of this software was modified and released + * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021. + * + */ + +#ifndef GPGFRONTEND_THREADINGMODEL_H +#define GPGFRONTEND_THREADINGMODEL_H + +#include "core/thread/Task.h" +#include "core/thread/TaskRunner.h" +#include "core/thread/TaskRunnerGetter.h" + +#endif // GPGFRONTEND_THREADINGMODEL_H
\ No newline at end of file |