Major functionality implemented (missing reconfig).

This commit is contained in:
Martino Ferrari
2026-04-14 01:40:43 +02:00
parent 96d98dfc3d
commit 3a1ecd3aba
6 changed files with 1173 additions and 107 deletions
@@ -9,6 +9,7 @@
#include "MemoryMapBroker.h"
#include "ObjectBuilder.h"
#include "ObjectRegistryDatabase.h"
#include "Threads.h"
#include "Vec.h"
// Original broker headers
@@ -55,17 +56,62 @@ static Reference FindByNameRecursive(ReferenceContainer *container,
*/
class DebugBrokerHelper {
public:
// Evaluate a break condition against the current live value of a signal.
// Returns true if the condition is met and execution should be paused.
// Only called when signal->breakOp != BREAK_OFF; reads memoryAddress directly.
static bool EvaluateBreak(const DebugSignalInfo *s) {
if (s->memoryAddress == NULL_PTR(void *)) return false;
float64 val = 0.0;
const TypeDescriptor &t = s->type;
if (t == Float64Bit) val = *static_cast<const float64 *>(s->memoryAddress);
else if (t == Float32Bit) val = *static_cast<const float32 *>(s->memoryAddress);
else if (t == UnsignedInteger32Bit) val = *static_cast<const uint32 *>(s->memoryAddress);
else if (t == SignedInteger32Bit) val = *static_cast<const int32 *>(s->memoryAddress);
else if (t == UnsignedInteger64Bit) val = static_cast<float64>(*static_cast<const uint64 *>(s->memoryAddress));
else if (t == SignedInteger64Bit) val = static_cast<float64>(*static_cast<const int64 *>(s->memoryAddress));
else if (t == UnsignedInteger16Bit) val = *static_cast<const uint16 *>(s->memoryAddress);
else if (t == SignedInteger16Bit) val = *static_cast<const int16 *>(s->memoryAddress);
else if (t == UnsignedInteger8Bit) val = *static_cast<const uint8 *>(s->memoryAddress);
else if (t == SignedInteger8Bit) val = *static_cast<const int8 *>(s->memoryAddress);
else return false; // unsupported type — skip
const float64 thr = s->breakThreshold;
switch (s->breakOp) {
case BREAK_GT: return val > thr;
case BREAK_LT: return val < thr;
case BREAK_EQ: return val == thr;
case BREAK_GEQ: return val >= thr;
case BREAK_LEQ: return val <= thr;
case BREAK_NEQ: return val != thr;
default: return false;
}
}
// Spin-wait point for output brokers — called from Execute() AFTER Process().
// Spins while paused, then consumes one step counter tick (if stepping).
// Input brokers must NOT call this — they complete normally to avoid blocking
// cross-thread EventSem posts (RealTimeThreadSynchBroker would time out).
static void OutputPauseAndStep(DebugService *service, const char8 *gamName) {
if (service == NULL_PTR(DebugService *)) return;
// Wait if already paused (manual PAUSE or breakpoint from a previous cycle)
while (service->IsPaused()) Sleep::MSec(10);
// Pass the OS thread name so per-thread step filtering works.
const char8 *tName = Threads::Name(Threads::Id());
service->ConsumeStepIfNeeded(gamName, tName);
while (service->IsPaused()) Sleep::MSec(10);
}
static void Process(DebugService *service,
DebugSignalInfo **signalInfoPointers,
Vec<uint32> &activeIndices, Vec<uint32> &activeSizes,
FastPollingMutexSem &activeMutex) {
FastPollingMutexSem &activeMutex,
volatile bool *anyBreakFlag,
Vec<uint32> *breakIndices) {
if (service == NULL_PTR(DebugService *))
return;
// Re-establish break logic
while (service->IsPaused()) {
Sleep::MSec(10);
}
// NOTE: No spin here. Spinning for paused state is handled in Execute() of
// OUTPUT brokers only (see OutputPauseAndStep). Input brokers must not block
// because that prevents cross-thread EventSem posts from completing.
activeMutex.FastLock();
uint32 n = activeIndices.Size();
@@ -83,6 +129,23 @@ public:
}
}
}
// Conditional break check — zero cost when anyBreakFlag is false
// (single volatile read; the RT loop never pays for this when no break is set).
if (*anyBreakFlag && !service->IsPaused() &&
breakIndices != NULL_PTR(Vec<uint32> *)) {
uint32 nb = breakIndices->Size();
for (uint32 i = 0; i < nb; i++) {
uint32 idx = (*breakIndices)[i];
DebugSignalInfo *s = signalInfoPointers[idx];
if (s != NULL_PTR(DebugSignalInfo *) && s->breakOp != BREAK_OFF &&
EvaluateBreak(s)) {
service->SetPaused(true);
break;
}
}
}
activeMutex.FastUnLock();
}
@@ -93,7 +156,8 @@ public:
uint32 numCopies, MemoryMapBrokerCopyTableEntry *copyTable,
const char8 *functionName, SignalDirection direction,
volatile bool *anyActiveFlag, Vec<uint32> *activeIndices,
Vec<uint32> *activeSizes, FastPollingMutexSem *activeMutex) {
Vec<uint32> *activeSizes, FastPollingMutexSem *activeMutex,
volatile bool *anyBreakFlag, Vec<uint32> *breakIndices) {
if (numCopies > 0) {
signalInfoPointers = new DebugSignalInfo *[numCopies];
for (uint32 i = 0; i < numCopies; i++)
@@ -181,8 +245,12 @@ public:
}
// Register broker in DebugService for optimized control
bool isOutputBroker = (direction == OutputSignals);
service->RegisterBroker(signalInfoPointers, numCopies, mmb, anyActiveFlag,
activeIndices, activeSizes, activeMutex);
activeIndices, activeSizes, activeMutex,
anyBreakFlag, breakIndices,
(functionName != NULL_PTR(const char8 *)) ? functionName : dsPath.Buffer(),
isOutputBroker);
}
}
};
@@ -197,6 +265,9 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0;
anyActive = false;
anyBreakActive = false;
isOutput = false;
gamName[0] = '\0';
}
virtual ~DebugBrokerWrapper() {
@@ -206,9 +277,15 @@ public:
virtual bool Execute() {
bool ret = BaseClass::Execute();
if (ret && (anyActive || (service && service->IsPaused()))) {
if (ret && (anyActive || anyBreakActive)) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex);
activeSizes, activeMutex,
&anyBreakActive, &breakIndices);
}
// Output brokers are the safe pause point: base Execute has already
// committed data / posted any cross-thread EventSems.
if (ret && isOutput) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
}
return ret;
}
@@ -220,10 +297,13 @@ public:
direction == InputSignals ? "In" : "Out");
if (ret) {
numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
&activeSizes, &activeMutex,
&anyBreakActive, &breakIndices);
}
return ret;
}
@@ -235,10 +315,13 @@ public:
direction == InputSignals ? "In" : "Out");
if (ret) {
numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
&activeSizes, &activeMutex,
&anyBreakActive, &breakIndices);
}
return ret;
}
@@ -247,8 +330,12 @@ public:
DebugSignalInfo **signalInfoPointers;
uint32 numSignals;
volatile bool anyActive;
volatile bool anyBreakActive;
bool isOutput;
char8 gamName[256];
Vec<uint32> activeIndices;
Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex;
};
@@ -260,6 +347,9 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0;
anyActive = false;
anyBreakActive = false;
isOutput = false;
gamName[0] = '\0';
}
virtual ~DebugBrokerWrapperNoOptim() {
@@ -269,9 +359,13 @@ public:
virtual bool Execute() {
bool ret = BaseClass::Execute();
if (ret && (anyActive || (service && service->IsPaused()))) {
if (ret && (anyActive || anyBreakActive)) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex);
activeSizes, activeMutex,
&anyBreakActive, &breakIndices);
}
if (ret && isOutput) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
}
return ret;
}
@@ -281,10 +375,13 @@ public:
bool ret = BaseClass::Init(direction, ds, name, gamMem);
if (ret) {
numSignals = this->GetNumberOfCopies();
isOutput = (direction == OutputSignals);
StringHelper::CopyN(gamName, name, 255u);
DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers,
numSignals, this->copyTable, name,
direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
&activeSizes, &activeMutex,
&anyBreakActive, &breakIndices);
}
return ret;
}
@@ -293,8 +390,12 @@ public:
DebugSignalInfo **signalInfoPointers;
uint32 numSignals;
volatile bool anyActive;
volatile bool anyBreakActive;
bool isOutput;
char8 gamName[256];
Vec<uint32> activeIndices;
Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex;
};
@@ -305,6 +406,8 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0;
anyActive = false;
anyBreakActive = false;
gamName[0] = '\0';
}
virtual ~DebugMemoryMapAsyncOutputBroker() {
if (signalInfoPointers)
@@ -312,9 +415,14 @@ public:
}
virtual bool Execute() {
bool ret = MemoryMapAsyncOutputBroker::Execute();
if (ret && (anyActive || (service && service->IsPaused()))) {
if (ret && (anyActive || anyBreakActive)) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex);
activeSizes, activeMutex,
&anyBreakActive, &breakIndices);
}
// Async output brokers are always output direction
if (ret) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
}
return ret;
}
@@ -330,10 +438,11 @@ public:
numberOfBuffersIn, cpuMaskIn, stackSizeIn);
if (ret) {
numSignals = this->GetNumberOfCopies();
StringHelper::CopyN(gamName, (functionName != NULL_PTR(const char8 *)) ? functionName : "", 255u);
DebugBrokerHelper::InitSignals(
this, dataSourceIn, service, signalInfoPointers, numSignals,
this->copyTable, functionName, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
&activeSizes, &activeMutex, &anyBreakActive, &breakIndices);
}
return ret;
}
@@ -341,8 +450,11 @@ public:
DebugSignalInfo **signalInfoPointers;
uint32 numSignals;
volatile bool anyActive;
volatile bool anyBreakActive;
char8 gamName[256];
Vec<uint32> activeIndices;
Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex;
};
@@ -355,6 +467,8 @@ public:
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
numSignals = 0;
anyActive = false;
anyBreakActive = false;
gamName[0] = '\0';
}
virtual ~DebugMemoryMapAsyncTriggerOutputBroker() {
if (signalInfoPointers)
@@ -362,9 +476,13 @@ public:
}
virtual bool Execute() {
bool ret = MemoryMapAsyncTriggerOutputBroker::Execute();
if (ret && (anyActive || (service && service->IsPaused()))) {
if (ret && (anyActive || anyBreakActive)) {
DebugBrokerHelper::Process(service, signalInfoPointers, activeIndices,
activeSizes, activeMutex);
activeSizes, activeMutex,
&anyBreakActive, &breakIndices);
}
if (ret) {
DebugBrokerHelper::OutputPauseAndStep(service, gamName);
}
return ret;
}
@@ -380,10 +498,11 @@ public:
stackSizeIn);
if (ret) {
numSignals = this->GetNumberOfCopies();
StringHelper::CopyN(gamName, (functionName != NULL_PTR(const char8 *)) ? functionName : "", 255u);
DebugBrokerHelper::InitSignals(
this, dataSourceIn, service, signalInfoPointers, numSignals,
this->copyTable, functionName, direction, &anyActive, &activeIndices,
&activeSizes, &activeMutex);
&activeSizes, &activeMutex, &anyBreakActive, &breakIndices);
}
return ret;
}
@@ -391,8 +510,11 @@ public:
DebugSignalInfo **signalInfoPointers;
uint32 numSignals;
volatile bool anyActive;
volatile bool anyBreakActive;
char8 gamName[256];
Vec<uint32> activeIndices;
Vec<uint32> activeSizes;
Vec<uint32> breakIndices;
FastPollingMutexSem activeMutex;
};