aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/thread/Task.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/thread/Task.cpp')
-rw-r--r--src/core/thread/Task.cpp370
1 files changed, 199 insertions, 171 deletions
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp
index 7173b69e..dc0cfe94 100644
--- a/src/core/thread/Task.cpp
+++ b/src/core/thread/Task.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2021 Saturneric
+ * Copyright (C) 2021 Saturneric <[email protected]>
*
* This file is part of GpgFrontend.
*
@@ -19,209 +19,237 @@
* 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.
+ * All the source code of GpgFrontend was modified and released by
+ * Saturneric <[email protected]> starting on May 12, 2021.
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#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 <qscopedpointer.h>
-#include "core/thread/TaskRunner.h"
+#include "utils/MemoryUtils.h"
-const std::string GpgFrontend::Thread::Task::DEFAULT_TASK_NAME = "default-task";
+namespace GpgFrontend::Thread {
-GpgFrontend::Thread::Task::Task(std::string name)
- : uuid_(generate_uuid()), name_(name) {
- SPDLOG_TRACE("task {}/ created", GetFullID());
- init();
-}
+class Task::Impl {
+ public:
+ Impl(Task *parent, QString name)
+ : parent_(parent), uuid_(generate_uuid()), name_(std::move(name)) {
+ GF_CORE_LOG_TRACE("task {} created", GetFullID());
+ init();
+ }
-GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name,
- DataObjectPtr data_object, bool sequency)
- : uuid_(generate_uuid()),
- name_(name),
- runnable_(std::move(runnable)),
- callback_(std::move([](int, const std::shared_ptr<DataObject> &) {})),
- callback_thread_(QThread::currentThread()),
- data_object_(data_object),
- sequency_(sequency) {
- SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}",
- GetFullID(), static_cast<void *>(callback_thread_));
- init();
-}
+ Impl(Task *parent, TaskRunnable runnable, QString name,
+ DataObjectPtr data_object)
+ : parent_(parent),
+ uuid_(generate_uuid()),
+ name_(std::move(name)),
+ runnable_(std::move(runnable)),
+ callback_([](int, const DataObjectPtr &) {}),
+ callback_thread_(QThread::currentThread()),
+ data_object_(std::move(data_object)) {
+ GF_CORE_LOG_TRACE("task {} created with runnable, callback_thread_: {}",
+ GetFullID(), static_cast<void *>(callback_thread_));
+ init();
+ }
-GpgFrontend::Thread::Task::Task(TaskRunnable runnable, std::string name,
- DataObjectPtr data_object,
- TaskCallback callback, bool sequency)
- : uuid_(generate_uuid()),
- name_(name),
- runnable_(std::move(runnable)),
- callback_(std::move(callback)),
- callback_thread_(QThread::currentThread()),
- data_object_(data_object),
- sequency_(sequency) {
- init();
- SPDLOG_TRACE(
- "task {} created with runnable and callback, callback_thread_: {}",
- GetFullID(), static_cast<void *>(callback_thread_));
-}
+ Impl(Task *parent, TaskRunnable runnable, QString name,
+ DataObjectPtr data_object, TaskCallback callback)
+ : parent_(parent),
+ uuid_(generate_uuid()),
+ name_(std::move(name)),
+ runnable_(std::move(runnable)),
+ callback_(std::move(callback)),
+ callback_thread_(QThread::currentThread()),
+ data_object_(std::move(data_object)) {
+ GF_CORE_LOG_TRACE(
+ "task {} created with runnable and callback, callback_thread_: {}",
+ GetFullID(), static_cast<void *>(callback_thread_));
+ init();
+ }
-GpgFrontend::Thread::Task::~Task() {
- SPDLOG_TRACE("task {} destroyed", GetFullID());
-}
+ ~Impl() { GF_CORE_LOG_TRACE("task {} destroyed", GetFullID()); }
+
+ /**
+ * @brief
+ *
+ * @return QString
+ */
+ [[nodiscard]] auto GetFullID() const -> QString {
+ return uuid_ + "/" + name_;
+ }
+
+ /**
+ * @brief
+ *
+ * @return QString
+ */
+ [[nodiscard]] auto GetUUID() const -> QString { return uuid_; }
+
+ /**
+ * @brief
+ *
+ * @return int
+ */
+ auto Run() -> int {
+ GF_CORE_LOG_TRACE("task {} is in classical runnable and callback mode",
+ GetFullID());
+
+ if (runnable_) return runnable_(data_object_);
+
+ GF_CORE_LOG_WARN("no runnable in task, do callback operation, task: {}",
+ GetFullID());
+ return 0;
+ }
+
+ /**
+ * @brief Set the Finish After Run object
+ *
+ * @param finish_after_run
+ */
+ void HoldOnLifeCycle(bool hold_on) { parent_->setAutoDelete(!hold_on); }
+
+ /**
+ * @brief
+ *
+ * @param rtn
+ */
+ void SetRTN(int rtn) { this->rtn_ = rtn; }
+
+ /**
+ * @brief
+ *
+ * @return auto
+ */
+ [[nodiscard]] auto GetRTN() const { return this->rtn_; }
+
+ private:
+ Task *const parent_;
+ const QString uuid_;
+ const QString name_;
+ TaskRunnable runnable_; ///<
+ TaskCallback callback_; ///<
+ int rtn_ = -99; ///<
+ QThread *callback_thread_ = nullptr; ///<
+ DataObjectPtr data_object_ = nullptr; ///<
+
+ void init() {
+ GF_CORE_LOG_TRACE("task {} created, parent: {}, impl: {}", name_,
+ static_cast<void *>(parent_), static_cast<void *>(this));
+
+ //
+ HoldOnLifeCycle(false);
+
+ //
+ connect(parent_, &Task::SignalRun, parent_, &Task::slot_exception_safe_run);
+
+ auto *callback_thread = callback_thread_ != nullptr
+ ? callback_thread_
+ : QCoreApplication::instance()->thread();
+ //
+ connect(parent_, &Task::SignalTaskShouldEnd, callback_thread,
+ [this](int rtn) {
+ // set task returning code
+ SetRTN(rtn);
+ try {
+ if (callback_) {
+ GF_CORE_LOG_TRACE(
+ "task callback {} is starting with runnerable rtn: {}",
+ GetFullID(), rtn);
+
+ callback_(rtn_, data_object_);
+ GF_CORE_LOG_TRACE("task callback {} finished, rtn: {}",
+ GetFullID(), rtn);
+ }
+ } catch (...) {
+ GF_CORE_LOG_ERROR("task {} callback caught exception, rtn: {}",
+ GetFullID(), rtn);
+ }
+ emit parent_->SignalTaskEnd();
+ });
+
+ //
+ connect(parent_, &Task::SignalTaskEnd, parent_, &Task::deleteLater);
+ }
+
+ /**
+ * @brief
+ *
+ * @return QString
+ */
+ static auto generate_uuid() -> QString {
+ return QUuid::createUuid().toString();
+ }
+};
+
+Task::Task(QString name) : p_(new Impl(this, name)) {}
+
+Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object)
+ : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object)) {}
+
+Task::Task(TaskRunnable runnable, QString name, DataObjectPtr data_object,
+ TaskCallback callback)
+ : p_(SecureCreateUniqueObject<Impl>(this, runnable, name, data_object,
+ callback)) {}
+
+Task::~Task() = default;
/**
* @brief
*
- * @return std::string
+ * @return QString
*/
-std::string GpgFrontend::Thread::Task::GetFullID() const {
- return uuid_ + "/" + name_;
-}
-
-std::string GpgFrontend::Thread::Task::GetUUID() const { return uuid_; }
+QString Task::GetFullID() const { return p_->GetFullID(); }
-bool GpgFrontend::Thread::Task::GetSequency() const { return sequency_; }
+QString Task::GetUUID() const { return p_->GetUUID(); }
-void GpgFrontend::Thread::Task::SetFinishAfterRun(
- bool run_callback_after_runnable_finished) {
- this->run_callback_after_runnable_finished_ =
- run_callback_after_runnable_finished;
-}
+void Task::HoldOnLifeCycle(bool hold_on) { p_->HoldOnLifeCycle(hold_on); }
-void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; }
-
-void GpgFrontend::Thread::Task::init() {
- // after runnable finished, running callback
- connect(this, &Task::SignalTaskRunnableEnd, this,
- &Task::slot_task_run_callback);
-}
+void Task::setRTN(int rtn) { p_->SetRTN(rtn); }
-void GpgFrontend::Thread::Task::slot_task_run_callback(int rtn) {
- SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn);
- // set return value
- this->SetRTN(rtn);
+void Task::SafelyRun() { emit SignalRun(); }
- try {
- if (callback_) {
- if (callback_thread_ == QThread::currentThread()) {
- SPDLOG_DEBUG("callback thread is the same thread");
- if (!QMetaObject::invokeMethod(callback_thread_,
- [callback = callback_, rtn = rtn_,
- data_object = data_object_, this]() {
- callback(rtn, data_object);
- // do cleaning work
- emit SignalTaskEnd();
- })) {
- SPDLOG_ERROR("failed to invoke callback");
- }
- // just finished, let callack thread to raise SignalTaskEnd
- return;
- } else {
- // waiting for callback to finish
- if (!QMetaObject::invokeMethod(
- callback_thread_,
- [callback = callback_, rtn = rtn_,
- data_object = data_object_]() { callback(rtn, data_object); },
- Qt::BlockingQueuedConnection)) {
- SPDLOG_ERROR("failed to invoke callback");
- }
- }
- }
- } catch (std::exception &e) {
- SPDLOG_ERROR("exception caught: {}", e.what());
- } catch (...) {
- SPDLOG_ERROR("unknown exception caught");
- }
+int Task::Run() { return p_->Run(); }
- // raise signal, announcing this task come to an end
- SPDLOG_DEBUG("task {}, starting calling signal SignalTaskEnd", GetFullID());
- emit SignalTaskEnd();
+void Task::run() {
+ GF_CORE_LOG_TRACE("interface run() of task {} was called by thread: {}",
+ GetFullID(), QThread::currentThread()->currentThreadId());
+ this->SafelyRun();
}
-void GpgFrontend::Thread::Task::run() {
- SPDLOG_TRACE("task {} starting", GetFullID());
+Task::TaskHandler::TaskHandler(Task *task) : task_(task) {}
- // build runnable package for running
- auto runnable_package = [=, id = GetFullID()]() {
- SPDLOG_DEBUG("task {} runnable start runing", id);
- // Run() will set rtn by itself
- Run();
- // raise signal to anounce after runnable returned
- if (run_callback_after_runnable_finished_) emit SignalTaskRunnableEnd(rtn_);
- };
-
- if (thread() != QThread::currentThread()) {
- SPDLOG_DEBUG("task running thread is not object living thread");
- // if running sequently
- if (sequency_) {
- // running in another thread, blocking until returned
- if (!QMetaObject::invokeMethod(thread(), runnable_package,
- Qt::BlockingQueuedConnection)) {
- SPDLOG_ERROR("qt invoke method failed");
- }
- } else {
- // running in another thread, non-blocking
- if (!QMetaObject::invokeMethod(thread(), runnable_package)) {
- SPDLOG_ERROR("qt invoke method failed");
- }
- }
- } else {
- if (!QMetaObject::invokeMethod(this, runnable_package)) {
- SPDLOG_ERROR("qt invoke method failed");
- }
- }
+void Task::TaskHandler::Start() {
+ if (task_ != nullptr) task_->SafelyRun();
}
-void GpgFrontend::Thread::Task::SlotRun() { run(); }
-
-void GpgFrontend::Thread::Task::Run() {
- if (runnable_) {
- SetRTN(runnable_(data_object_));
- } else {
- SPDLOG_WARN("no runnable in task, do callback operation");
- }
+void Task::TaskHandler::Cancel() {
+ if (task_ != nullptr) emit task_->SignalTaskEnd();
}
-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;
+auto Task::TaskHandler::GetTask() -> Task * {
+ if (task_ != nullptr) return task_;
+ return nullptr;
}
-GpgFrontend::Thread::Task::DataObject::~DataObject() {
- if (!data_objects_.empty())
- SPDLOG_WARN("data_objects_ is not empty",
- "address:", static_cast<void *>(this));
- while (!data_objects_.empty()) {
- free_heap_ptr(data_objects_.top());
- data_objects_.pop();
- }
-}
+void Task::slot_exception_safe_run() noexcept {
+ auto rtn = p_->GetRTN();
+ try {
+ GF_CORE_LOG_TRACE("task runnable {} is starting...", GetFullID());
-size_t GpgFrontend::Thread::Task::DataObject::GetObjectSize() {
- return data_objects_.size();
-}
+ // Run() will set rtn by itself
+ rtn = this->Run();
-void GpgFrontend::Thread::Task::DataObject::free_heap_ptr(Destructor *ptr) {
- SPDLOG_TRACE("p_obj: {} data object: {}",
- static_cast<const void *>(ptr->p_obj),
- static_cast<void *>(this));
- if (ptr->destroy != nullptr) {
- ptr->destroy(ptr->p_obj);
+ GF_CORE_LOG_TRACE("task runnable {} finished, rtn: {}", GetFullID());
+ } catch (...) {
+ GF_CORE_LOG_ERROR("exception was caught at task: {}", GetFullID());
}
- free(const_cast<void *>(ptr->p_obj));
- delete ptr;
-}
-std::string GpgFrontend::Thread::Task::generate_uuid() {
- return boost::uuids::to_string(boost::uuids::random_generator()());
+ // raise signal to anounce after runnable returned
+ if (this->autoDelete()) emit this->SignalTaskShouldEnd(rtn);
}
+auto Task::GetRTN() { return p_->GetRTN(); }
+} // namespace GpgFrontend::Thread \ No newline at end of file