Moved insight worker and introduced worker tasks

This commit is contained in:
Nav
2021-08-30 22:17:59 +01:00
parent a52d2271b3
commit 3be8d90e09
7 changed files with 141 additions and 8 deletions

View File

@@ -0,0 +1,153 @@
#include "InsightWorker.hpp"
#include <filesystem>
#include <QObject>
#include <QTimer>
#include "src/Helpers/Thread.hpp"
#include "src/Logger/Logger.hpp"
using namespace Bloom;
using namespace Bloom::Exceptions;
using Bloom::Targets::TargetState;
void InsightWorker::startup() {
Logger::debug("Starting InsightWorker thread");
this->eventManager.registerListener(this->eventListener);
this->eventListener->registerCallbackForEventType<Events::TargetControllerStateReported>(
std::bind(&InsightWorker::onTargetControllerStateReported, this, std::placeholders::_1)
);
this->eventListener->registerCallbackForEventType<Events::TargetExecutionStopped>(
std::bind(&InsightWorker::onTargetStoppedEvent, this, std::placeholders::_1)
);
this->eventListener->registerCallbackForEventType<Events::TargetExecutionResumed>(
std::bind(&InsightWorker::onTargetResumedEvent, this, std::placeholders::_1)
);
this->eventListener->registerCallbackForEventType<Events::TargetPinStatesRetrieved>(
std::bind(&InsightWorker::onTargetPinStatesRetrievedEvent, this, std::placeholders::_1)
);
this->eventListener->registerCallbackForEventType<Events::TargetIoPortsUpdated>(
std::bind(&InsightWorker::onTargetIoPortsUpdatedEvent, this, std::placeholders::_1)
);
this->eventDispatchTimer = new QTimer(this);
this->connect(this->eventDispatchTimer, &QTimer::timeout, this, &InsightWorker::dispatchEvents);
this->eventDispatchTimer->start(5);
this->connect(this, &InsightWorker::taskQueued, this, &InsightWorker::executeTasks);
this->eventManager.triggerEvent(
std::make_shared<Events::InsightThreadStateChanged>(ThreadState::READY)
);
}
void InsightWorker::queueTask(InsightWorkerTask* task) {
auto taskQueueLock = this->queuedTasks.acquireLock();
task->moveToThread(this->thread());
task->setParent(this);
this->queuedTasks.getReference().push(task);
emit this->taskQueued();
}
std::optional<InsightWorkerTask*> InsightWorker::getQueuedTask() {
auto task = std::optional<InsightWorkerTask*>();
auto& queuedTasks = this->queuedTasks.getReference();
auto taskQueueLock = this->queuedTasks.acquireLock();
if (!queuedTasks.empty()) {
task = queuedTasks.front();
queuedTasks.pop();
}
return task;
}
void InsightWorker::executeTasks() {
auto task = std::optional<InsightWorkerTask*>();
while ((task = this->getQueuedTask()).has_value()) {
task.value()->execute(this->targetControllerConsole);
}
}
void InsightWorker::requestPinStates(int variantId) {
this->targetControllerConsole.requestPinStates(variantId);
}
void InsightWorker::requestPinStateUpdate(
int variantId,
Bloom::Targets::TargetPinDescriptor pinDescriptor,
Bloom::Targets::TargetPinState pinState
) {
this->targetControllerConsole.setPinState(variantId, pinDescriptor, pinState);
}
void InsightWorker::onTargetStoppedEvent(const Events::TargetExecutionStopped& event) {
/*
* When we report a target halt to Insight, Insight will immediately seek more data from the target (such as GPIO
* pin states). This can be problematic for cases where the target had halted due to a conditional breakpoint.
*
* For conditional breakpoints, a software breakpoint is employed to halt target execution and give the debug
* client an opportunity to check the condition. In cases where the condition is not met, the client will
* immediately request for execution to be resumed. It's important that Insight does not get in the way of this
* process, as it could end up slowing things down significantly.
*
* For the above reason, we don't want to report any target halts to Insight, unless we can be sure that the client
* isn't going to immediately resume execution upon checking the condition.
*
* We do this by providing a time window for the TargetExecutionResumed event. If the event is triggered within
* that time window, we won't report the target halt to Insight, thus preventing Insight from needlessly seeking
* data from the target and slowing things down.
*
* This isn't the best approach, TBH, as it introduces a delay to Insight's response to the target halting. The
* problem is, we cannot differentiate a conditional breakpoint with a software breakpoint, so this seems to be the
* only way. It would be nice if the debug client gave us some form of indication of whether the breakpoint is a
* conditional one.
*/
auto resumedEvent = this->eventListener->waitForEvent<Events::TargetExecutionResumed>(
std::chrono::milliseconds(650)
);
if (!resumedEvent.has_value()) {
emit this->targetStateUpdated(TargetState::STOPPED);
emit this->targetProgramCounterUpdated(event.programCounter);
}
}
void InsightWorker::onTargetResumedEvent(const Events::TargetExecutionResumed& event) {
emit this->targetStateUpdated(TargetState::RUNNING);
}
void InsightWorker::onTargetPinStatesRetrievedEvent(const Events::TargetPinStatesRetrieved& event) {
emit this->targetPinStatesUpdated(event.variantId, event.pinSatesByNumber);
}
void InsightWorker::onTargetIoPortsUpdatedEvent(const Events::TargetIoPortsUpdated& event) {
emit this->targetIoPortsUpdated();
}
void InsightWorker::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) {
if (this->lastTargetControllerState == TargetControllerState::ACTIVE
&& event.state == TargetControllerState::SUSPENDED
) {
emit this->targetControllerSuspended();
} else if (this->lastTargetControllerState == TargetControllerState::SUSPENDED
&& event.state == TargetControllerState::ACTIVE
) {
try {
emit this->targetControllerResumed(this->targetControllerConsole.getTargetDescriptor());
} catch (const Exception& exception) {
Logger::error("Insight resume failed - " + exception.getMessage());
}
}
this->lastTargetControllerState = event.state;
}

View File

@@ -0,0 +1,76 @@
#pragma once
#include <QtCore>
#include <QApplication>
#include "src/Helpers/Thread.hpp"
#include "src/Helpers/SyncSafe.hpp"
#include "src/ApplicationConfig.hpp"
#include "src/EventManager/EventManager.hpp"
#include "src/EventManager/EventListener.hpp"
#include "src/TargetController/TargetControllerConsole.hpp"
#include "src/TargetController/TargetControllerState.hpp"
#include "Tasks/InsightWorkerTask.hpp"
namespace Bloom
{
/**
* The InsightWorker runs on a separate thread to the main GUI thread. Its purpose is to handle any
* blocking/time-expensive operations.
*/
class InsightWorker: public QObject
{
Q_OBJECT
private:
EventManager& eventManager;
EventListenerPointer eventListener = std::make_shared<EventListener>("InsightWorkerEventListener");
TargetControllerConsole targetControllerConsole = TargetControllerConsole(
this->eventManager,
*(this->eventListener)
);
TargetControllerState lastTargetControllerState = TargetControllerState::ACTIVE;
QTimer* eventDispatchTimer = nullptr;
SyncSafe<std::queue<InsightWorkerTask*>> queuedTasks;
std::optional<InsightWorkerTask*> getQueuedTask();
void onTargetStoppedEvent(const Events::TargetExecutionStopped& event);
void onTargetResumedEvent(const Events::TargetExecutionResumed& event);
void onTargetPinStatesRetrievedEvent(const Events::TargetPinStatesRetrieved& event);
void onTargetIoPortsUpdatedEvent(const Events::TargetIoPortsUpdated& event);
void onTargetControllerStateReported(const Events::TargetControllerStateReported& event);
private slots:
void executeTasks();
public:
explicit InsightWorker(EventManager& eventManager): eventManager(eventManager) {};
void dispatchEvents() {
this->eventListener->dispatchCurrentEvents();
}
void queueTask(InsightWorkerTask* task);
public slots:
void startup();
void requestPinStates(int variantId);
void requestPinStateUpdate(
int variantId,
Bloom::Targets::TargetPinDescriptor pinDescriptor,
Bloom::Targets::TargetPinState pinState
);
signals:
void taskQueued();
void targetStateUpdated(Bloom::Targets::TargetState newState);
void targetProgramCounterUpdated(quint32 programCounter);
void targetPinStatesUpdated(int variantId, Bloom::Targets::TargetPinStateMappingType pinStatesByNumber);
void targetIoPortsUpdated();
void targetControllerSuspended();
void targetControllerResumed(const Bloom::Targets::TargetDescriptor& targetDescriptor);
};
}

View File

@@ -0,0 +1,17 @@
#include "InsightWorkerTask.hpp"
using namespace Bloom;
void InsightWorkerTask::execute(TargetControllerConsole& targetControllerConsole) {
try {
this->state = InsightWorkerTaskState::STARTED;
emit this->started();
this->run(targetControllerConsole);
this->state = InsightWorkerTaskState::COMPLETED;
emit this->completed();
} catch (std::exception& exception) {
this->state = InsightWorkerTaskState::FAILED;
emit this->failed(QString::fromStdString(exception.what()));
}
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <QObject>
#include <QString>
#include "src/TargetController/TargetControllerConsole.hpp"
namespace Bloom
{
enum class InsightWorkerTaskState: std::uint8_t
{
CREATED,
STARTED,
FAILED,
COMPLETED,
};
class InsightWorkerTask: public QObject
{
Q_OBJECT
protected:
virtual void run(TargetControllerConsole& targetControllerConsole) = 0;
public:
InsightWorkerTaskState state;
InsightWorkerTask() = default;
InsightWorkerTask(QObject* parent): QObject(parent) {};
void execute(TargetControllerConsole& targetControllerConsole);
signals:
void started();
void failed(QString errorMessage);
void completed();
};
}

View File

@@ -0,0 +1,7 @@
#include "ReadTargetRegisters.hpp"
using namespace Bloom;
void ReadTargetRegisters::run(TargetControllerConsole& targetControllerConsole) {
emit this->targetRegistersRead(targetControllerConsole.readRegisters(this->descriptors));
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include <QObject>
#include <QString>
#include "InsightWorkerTask.hpp"
#include "src/Targets/TargetRegister.hpp"
namespace Bloom
{
class ReadTargetRegisters: public InsightWorkerTask
{
Q_OBJECT
private:
Targets::TargetRegisterDescriptors descriptors;
protected:
void run(TargetControllerConsole& targetControllerConsole) override;
public:
ReadTargetRegisters(const Targets::TargetRegisterDescriptors& descriptors, QObject* parent):
InsightWorkerTask(nullptr), descriptors(descriptors) {}
signals:
void targetRegistersRead(Targets::TargetRegisters registers);
};
}