From 7117846b3e06b27105af7d512aebd79d673fec6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 26 May 2018 20:09:20 +0200 Subject: [PATCH] Use AsyncTask for initial analysis --- src/{AnalThread.cpp => AnalTask.cpp} | 45 +++++++++++++--------------- src/{AnalThread.h => AnalTask.h} | 25 ++++++---------- src/Cutter.h | 8 ++--- src/Cutter.pro | 4 +-- src/dialogs/OptionsDialog.cpp | 17 ++++++----- src/dialogs/OptionsDialog.h | 4 +-- src/utils/AsyncTask.cpp | 44 +++++++++++++++++++++++++++ src/utils/AsyncTask.h | 22 ++++++++++++++ 8 files changed, 111 insertions(+), 58 deletions(-) rename src/{AnalThread.cpp => AnalTask.cpp} (83%) rename src/{AnalThread.h => AnalTask.h} (51%) diff --git a/src/AnalThread.cpp b/src/AnalTask.cpp similarity index 83% rename from src/AnalThread.cpp rename to src/AnalTask.cpp index 0eda8194..af131345 100644 --- a/src/AnalThread.cpp +++ b/src/AnalTask.cpp @@ -1,48 +1,43 @@ #include "Cutter.h" -#include "AnalThread.h" +#include "AnalTask.h" #include "MainWindow.h" #include "dialogs/OptionsDialog.h" #include #include #include -AnalThread::AnalThread(OptionsDialog *parent) : - QThread(parent), +AnalTask::AnalTask(OptionsDialog *parent) : + AsyncTask(parent), level(2), - main(nullptr), - interrupted(false) + main(nullptr) { } -AnalThread::~AnalThread() +AnalTask::~AnalTask() { - if (isRunning()) { - quit(); - wait(); - } } -void AnalThread::start(MainWindow *main, int level, QList advanced) +void AnalTask::setSettings(MainWindow *main, int level, QList advanced) { + this->main = main; this->level = level; this->advanced = advanced; - this->main = main; - - QThread::start(); } -void AnalThread::interruptAndWait() +void AnalTask::interrupt() { - interrupted = true; - - while (isRunning()) { - r_cons_singleton()->breaked = true; - r_sys_usleep(10000); - } + AsyncTask::interrupt(); + r_cons_singleton()->breaked = true; } -// run() will be called when a thread starts -void AnalThread::run() +void AnalTask::interruptAndWait() +{ + do { + interrupt(); + } while(!wait(10)); +} + +void AnalTask::runTask() { const auto optionsDialog = dynamic_cast(parent()); const auto &ui = optionsDialog->ui; @@ -51,7 +46,7 @@ void AnalThread::run() if (ui->entry_loadOffset->text().length() > 0) binLoadAddr = Core()->math(ui->entry_loadOffset->text()); ut64 mapAddr = Core()->math(ui->entry_mapOffset->text()); // Where to map the file once loaded (-m) - interrupted = false; + emit updateProgress(tr("Loading binary...")); // Set the CPU details (handle auto) @@ -83,7 +78,7 @@ void AnalThread::run() if (!fileLoaded) { // Something wrong happened, fallback to open dialog emit openFileFailed(); - interrupted = true; + AsyncTask::interrupt(); return; } } diff --git a/src/AnalThread.h b/src/AnalTask.h similarity index 51% rename from src/AnalThread.h rename to src/AnalTask.h index 6a61f12e..4a308f8e 100644 --- a/src/AnalThread.h +++ b/src/AnalTask.h @@ -1,31 +1,26 @@ #ifndef ANALTHREAD_H #define ANALTHREAD_H -#include +#include "utils/AsyncTask.h" class CutterCore; class MainWindow; class OptionsDialog; -class AnalThread : public QThread +class AnalTask : public AsyncTask { Q_OBJECT -public: - explicit AnalThread(OptionsDialog *parent = nullptr); - ~AnalThread(); - void start(MainWindow *main, int level, QList advanced); +public: + explicit AnalTask(OptionsDialog *parent = nullptr); + ~AnalTask(); + + void setSettings(MainWindow *main, int level, QList advanced); + void interrupt() override; void interruptAndWait(); - bool isInterrupted() - { - return interrupted; - } - protected: - void run(); - - using QThread::start; + void runTask(); signals: void updateProgress(QString str); @@ -35,8 +30,6 @@ private: int level; QList advanced; MainWindow *main; - - bool interrupted; }; #endif // ANALTHREAD_H diff --git a/src/Cutter.h b/src/Cutter.h index 163f2fd9..3ec84b2e 100644 --- a/src/Cutter.h +++ b/src/Cutter.h @@ -312,11 +312,9 @@ public: ~CutterCore(); static CutterCore *getInstance(); - /* Getters */ - RVA getOffset() const - { - return core_->offset; - } + AsyncTaskManager *getAsyncTaskManager() { return asyncTaskManager; } + + RVA getOffset() const { return core_->offset; } static QString sanitizeStringForCommand(QString s); QString cmd(const QString &str); diff --git a/src/Cutter.pro b/src/Cutter.pro index cd81399b..ef0edf3e 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -107,7 +107,7 @@ SOURCES += \ utils/MdHighlighter.cpp \ dialogs/preferences/AsmOptionsWidget.cpp \ dialogs/NewFileDialog.cpp \ - AnalThread.cpp \ + AnalTask.cpp \ widgets/CommentsWidget.cpp \ widgets/ConsoleWidget.cpp \ widgets/Dashboard.cpp \ @@ -183,7 +183,7 @@ HEADERS += \ utils/MdHighlighter.h \ dialogs/OptionsDialog.h \ dialogs/NewFileDialog.h \ - AnalThread.h \ + AnalTask.h \ widgets/CommentsWidget.h \ widgets/ConsoleWidget.h \ widgets/Dashboard.h \ diff --git a/src/dialogs/OptionsDialog.cpp b/src/dialogs/OptionsDialog.cpp index c3b477b6..6837177e 100644 --- a/src/dialogs/OptionsDialog.cpp +++ b/src/dialogs/OptionsDialog.cpp @@ -10,7 +10,7 @@ OptionsDialog::OptionsDialog(MainWindow *main): QDialog(0), // parent may not be main - analThread(this), + analTask(this), main(main), core(Core()), defaultAnalLevel(1), @@ -61,7 +61,7 @@ OptionsDialog::OptionsDialog(MainWindow *main): // Add this so the dialog resizes when widgets are shown/hidden //this->layout()->setSizeConstraint(QLayout::SetFixedSize); - connect(&analThread, SIGNAL(finished()), this, SLOT(analysisFinished())); + connect(&analTask, SIGNAL(finished()), this, SLOT(analysisFinished())); connect(ui->cancelButton, SIGNAL(clicked()), this, SLOT(reject())); ui->programLineEdit->setText(main->getFilename()); @@ -170,9 +170,10 @@ void OptionsDialog::setupAndStartAnalysis(int level, QList advanced) connect(&analTimer, SIGNAL(timeout()), this, SLOT(updateProgressTimer())); // Threads stuff, connect signal/slot - connect(&analThread, &AnalThread::updateProgress, this, &OptionsDialog::updateProgress); - connect(&analThread, &AnalThread::openFileFailed, main, &MainWindow::openNewFileFailed); - analThread.start(main, level, advanced); + connect(&analTask, &AnalTask::updateProgress, this, &OptionsDialog::updateProgress); + connect(&analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed); + analTask.setSettings(main, level, advanced); + Core()->getAsyncTaskManager()->start(&analTask); } void OptionsDialog::updateProgressTimer() @@ -249,7 +250,7 @@ void OptionsDialog::on_okButton_clicked() void OptionsDialog::analysisFinished() { - if (analThread.isInterrupted()) { + if (analTask.isInterrupted()) { updateProgress(tr("Analysis aborted.")); done(1); return; @@ -264,8 +265,8 @@ void OptionsDialog::analysisFinished() void OptionsDialog::closeEvent(QCloseEvent *event) { - if (analThread.isRunning()) { - analThread.interruptAndWait(); + if (analTask.isRunning()) { + analTask.interruptAndWait(); } event->accept(); } diff --git a/src/dialogs/OptionsDialog.h b/src/dialogs/OptionsDialog.h index 1fb49ac0..2b87aaf3 100644 --- a/src/dialogs/OptionsDialog.h +++ b/src/dialogs/OptionsDialog.h @@ -7,7 +7,7 @@ #include #include #include "Cutter.h" -#include "AnalThread.h" +#include "AnalTask.h" #include "ui_OptionsDialog.h" class MainWindow; @@ -46,7 +46,7 @@ protected: void closeEvent(QCloseEvent *event) override; private: - AnalThread analThread; + AnalTask analTask; MainWindow *main; CutterCore *core; int defaultAnalLevel; diff --git a/src/utils/AsyncTask.cpp b/src/utils/AsyncTask.cpp index f54dd80a..436f6fd8 100644 --- a/src/utils/AsyncTask.cpp +++ b/src/utils/AsyncTask.cpp @@ -1,10 +1,53 @@ #include "AsyncTask.h" +AsyncTask::AsyncTask(QObject *parent) + : QObject(parent), + QRunnable() +{ + setAutoDelete(false); + running = false; +} + +AsyncTask::~AsyncTask() +{ + wait(); +} + +void AsyncTask::wait() +{ + runningMutex.lock(); + runningMutex.unlock(); +} + +bool AsyncTask::wait(int timeout) +{ + bool r = runningMutex.tryLock(timeout); + if (r) { + runningMutex.unlock(); + } + return r; +} + +void AsyncTask::interrupt() +{ + interrupted = true; +} + +void AsyncTask::prepareRun() +{ + interrupted = false; + wait(); +} + void AsyncTask::run() { + runningMutex.lock(); + running = true; runTask(); emit finished(); + running = false; + runningMutex.unlock(); } AsyncTaskManager::AsyncTaskManager(QObject *parent) @@ -19,5 +62,6 @@ AsyncTaskManager::~AsyncTaskManager() void AsyncTaskManager::start(AsyncTask *task) { + task->prepareRun(); threadPool->start(task); } diff --git a/src/utils/AsyncTask.h b/src/utils/AsyncTask.h index 700f663f..f58dd350 100644 --- a/src/utils/AsyncTask.h +++ b/src/utils/AsyncTask.h @@ -4,18 +4,40 @@ #include #include +#include + +class AsyncTaskManager; class AsyncTask : public QObject, public QRunnable { Q_OBJECT + friend class AsyncTaskManager; + public: + AsyncTask(QObject *parent = nullptr); + ~AsyncTask(); + void run() override final; + void wait(); + bool wait(int timeout); + virtual void interrupt(); + bool isInterrupted() { return interrupted; } + bool isRunning() { return running; } + +protected: virtual void runTask() =0; signals: void finished(); + +private: + bool running; + bool interrupted; + QMutex runningMutex; + + void prepareRun(); };