2021-08-30 22:17:59 +01:00
|
|
|
#include "InsightWorker.hpp"
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <QObject>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
|
|
|
|
|
#include "src/Helpers/Thread.hpp"
|
2021-08-30 22:17:59 +01:00
|
|
|
#include "src/Logger/Logger.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
using namespace Bloom;
|
2021-05-24 20:58:49 +01:00
|
|
|
using namespace Bloom::Exceptions;
|
|
|
|
|
|
|
|
|
|
using Bloom::Targets::TargetState;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-10-06 21:12:31 +01:00
|
|
|
InsightWorker::InsightWorker(EventManager& eventManager): eventManager(eventManager) {}
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
void InsightWorker::startup() {
|
|
|
|
|
Logger::debug("Starting InsightWorker thread");
|
|
|
|
|
this->eventManager.registerListener(this->eventListener);
|
|
|
|
|
|
2021-06-22 14:44:00 +01:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::TargetControllerStateReported>(
|
2021-09-11 20:45:26 +01:00
|
|
|
std::bind(&InsightWorker::onTargetControllerStateReportedEvent, this, std::placeholders::_1)
|
2021-05-30 16:53:24 +01:00
|
|
|
);
|
|
|
|
|
|
2021-06-22 14:44:00 +01:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::TargetExecutionStopped>(
|
2021-04-04 21:04:12 +01:00
|
|
|
std::bind(&InsightWorker::onTargetStoppedEvent, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2021-06-22 14:44:00 +01:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::TargetExecutionResumed>(
|
2021-04-04 21:04:12 +01:00
|
|
|
std::bind(&InsightWorker::onTargetResumedEvent, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-11 20:45:06 +01:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::RegistersWrittenToTarget>(
|
|
|
|
|
std::bind(&InsightWorker::onTargetRegistersWrittenEvent, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
this->eventDispatchTimer = new QTimer(this);
|
2021-10-21 19:24:48 +01:00
|
|
|
QObject::connect(this->eventDispatchTimer, &QTimer::timeout, this, &InsightWorker::dispatchEvents);
|
2021-04-14 23:18:37 +01:00
|
|
|
this->eventDispatchTimer->start(5);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-10-21 19:24:48 +01:00
|
|
|
QObject::connect(this, &InsightWorker::taskQueued, this, &InsightWorker::executeTasks);
|
2021-08-30 22:17:59 +01:00
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
this->eventManager.triggerEvent(
|
2021-05-29 21:39:00 +01:00
|
|
|
std::make_shared<Events::InsightThreadStateChanged>(ThreadState::READY)
|
2021-04-04 21:04:12 +01:00
|
|
|
);
|
2021-10-18 01:03:22 +01:00
|
|
|
|
|
|
|
|
emit this->ready();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2021-10-06 21:12:31 +01:00
|
|
|
void InsightWorker::requestPinStates(int variantId) {
|
|
|
|
|
this->targetControllerConsole.requestPinStates(variantId);
|
2021-08-30 22:17:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 14:44:00 +01:00
|
|
|
void InsightWorker::onTargetStoppedEvent(const Events::TargetExecutionStopped& event) {
|
2021-05-25 21:50:17 +01:00
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2021-06-22 14:44:00 +01:00
|
|
|
auto resumedEvent = this->eventListener->waitForEvent<Events::TargetExecutionResumed>(
|
2021-05-25 21:50:17 +01:00
|
|
|
std::chrono::milliseconds(650)
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
if (!resumedEvent.has_value()) {
|
|
|
|
|
emit this->targetStateUpdated(TargetState::STOPPED);
|
2021-06-22 03:06:20 +01:00
|
|
|
emit this->targetProgramCounterUpdated(event.programCounter);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 14:44:00 +01:00
|
|
|
void InsightWorker::onTargetResumedEvent(const Events::TargetExecutionResumed& event) {
|
2021-04-04 21:04:12 +01:00
|
|
|
emit this->targetStateUpdated(TargetState::RUNNING);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-11 20:45:06 +01:00
|
|
|
void InsightWorker::onTargetRegistersWrittenEvent(const Events::RegistersWrittenToTarget& event) {
|
2021-09-18 22:35:30 +01:00
|
|
|
emit this->targetRegistersWritten(event.registers, event.createdTimestamp);
|
2021-09-11 20:45:06 +01:00
|
|
|
}
|
|
|
|
|
|
2021-09-11 20:45:26 +01:00
|
|
|
void InsightWorker::onTargetControllerStateReportedEvent(const Events::TargetControllerStateReported& event) {
|
2021-05-30 16:53:24 +01:00
|
|
|
if (this->lastTargetControllerState == TargetControllerState::ACTIVE
|
2021-06-22 03:06:20 +01:00
|
|
|
&& event.state == TargetControllerState::SUSPENDED
|
2021-05-30 16:53:24 +01:00
|
|
|
) {
|
|
|
|
|
emit this->targetControllerSuspended();
|
|
|
|
|
|
|
|
|
|
} else if (this->lastTargetControllerState == TargetControllerState::SUSPENDED
|
2021-06-22 03:06:20 +01:00
|
|
|
&& event.state == TargetControllerState::ACTIVE
|
2021-05-30 16:53:24 +01:00
|
|
|
) {
|
|
|
|
|
try {
|
|
|
|
|
emit this->targetControllerResumed(this->targetControllerConsole.getTargetDescriptor());
|
|
|
|
|
|
|
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::error("Insight resume failed - " + exception.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-22 03:06:20 +01:00
|
|
|
this->lastTargetControllerState = event.state;
|
2021-05-30 16:53:24 +01:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
|
|
|
|
void InsightWorker::executeTasks() {
|
|
|
|
|
auto task = std::optional<InsightWorkerTask*>();
|
|
|
|
|
|
|
|
|
|
while ((task = this->getQueuedTask()).has_value()) {
|
|
|
|
|
task.value()->execute(this->targetControllerConsole);
|
|
|
|
|
}
|
|
|
|
|
}
|