interface added and web ui created
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
#include "BrokerI.h"
|
||||
#include "DataSourceI.h"
|
||||
#include "DebugService.h"
|
||||
#include "DebugServiceI.h"
|
||||
#include "FastPollingMutexSem.h"
|
||||
#include "HighResolutionTimer.h"
|
||||
#include "MemoryMapBroker.h"
|
||||
@@ -90,8 +90,11 @@ public:
|
||||
// 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;
|
||||
static void OutputPauseAndStep(DebugServiceI *service, const char8 *gamName) {
|
||||
if (service == NULL_PTR(DebugServiceI *)) return;
|
||||
// Fast path: nothing to do when neither paused nor stepping.
|
||||
// Avoids Threads::Name() lookup (and its mutex) on every 1000 Hz cycle.
|
||||
if (!service->IsPaused() && !service->IsStepPending()) 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.
|
||||
@@ -100,13 +103,13 @@ public:
|
||||
while (service->IsPaused()) Sleep::MSec(10);
|
||||
}
|
||||
|
||||
static void Process(DebugService *service,
|
||||
static void Process(DebugServiceI *service,
|
||||
DebugSignalInfo **signalInfoPointers,
|
||||
Vec<uint32> &activeIndices, Vec<uint32> &activeSizes,
|
||||
FastPollingMutexSem &activeMutex,
|
||||
volatile bool *anyBreakFlag,
|
||||
Vec<uint32> *breakIndices) {
|
||||
if (service == NULL_PTR(DebugService *))
|
||||
if (service == NULL_PTR(DebugServiceI *))
|
||||
return;
|
||||
|
||||
// NOTE: No spin here. Spinning for paused state is handled in Execute() of
|
||||
@@ -118,7 +121,7 @@ public:
|
||||
if (n > 0 && signalInfoPointers != NULL_PTR(DebugSignalInfo **)) {
|
||||
// Capture timestamp ONCE per broker cycle for lowest impact
|
||||
uint64 ts = (uint64)((float64)HighResolutionTimer::Counter() *
|
||||
HighResolutionTimer::Period() * 1000000.0);
|
||||
HighResolutionTimer::Period() * 1.0e9);
|
||||
|
||||
for (uint32 i = 0; i < n; i++) {
|
||||
uint32 idx = activeIndices[i];
|
||||
@@ -130,13 +133,33 @@ 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();
|
||||
// FIX #3: copy break indices under lock into a local stack array, then
|
||||
// release activeMutex BEFORE evaluating. EvaluateBreak reads signal
|
||||
// memory which can stall (cache miss); holding activeMutex during that
|
||||
// stall would block UpdateBrokersBreakStatus() in the Server thread and
|
||||
// cause unnecessary priority inversion on the RT path.
|
||||
bool shouldCheckBreak = (*anyBreakFlag && !service->IsPaused() &&
|
||||
breakIndices != NULL_PTR(Vec<uint32> *) &&
|
||||
signalInfoPointers != NULL_PTR(DebugSignalInfo **));
|
||||
static const uint32 MAX_BREAK_INDICES = 64u;
|
||||
uint32 localBreakIdx[MAX_BREAK_INDICES];
|
||||
uint32 nb = 0u;
|
||||
if (shouldCheckBreak) {
|
||||
nb = breakIndices->Size();
|
||||
if (nb > MAX_BREAK_INDICES) nb = MAX_BREAK_INDICES;
|
||||
for (uint32 i = 0; i < nb; i++) {
|
||||
uint32 idx = (*breakIndices)[i];
|
||||
localBreakIdx[i] = (*breakIndices)[i];
|
||||
}
|
||||
}
|
||||
|
||||
activeMutex.FastUnLock();
|
||||
|
||||
// Evaluate break conditions outside the lock — safe because
|
||||
// EvaluateBreak only reads signalInfoPointers[idx]->memoryAddress,
|
||||
// which is RT data-bus memory and is never freed during the RT cycle.
|
||||
if (shouldCheckBreak && nb > 0u) {
|
||||
for (uint32 i = 0; i < nb; i++) {
|
||||
uint32 idx = localBreakIdx[i];
|
||||
DebugSignalInfo *s = signalInfoPointers[idx];
|
||||
if (s != NULL_PTR(DebugSignalInfo *) && s->breakOp != BREAK_OFF &&
|
||||
EvaluateBreak(s)) {
|
||||
@@ -145,14 +168,12 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
activeMutex.FastUnLock();
|
||||
}
|
||||
|
||||
// Pass numCopies explicitly so we can mock it
|
||||
static void
|
||||
InitSignals(BrokerI *broker, DataSourceI &dataSourceIn,
|
||||
DebugService *&service, DebugSignalInfo **&signalInfoPointers,
|
||||
DebugServiceI *&service, DebugSignalInfo **&signalInfoPointers,
|
||||
uint32 numCopies, MemoryMapBrokerCopyTableEntry *copyTable,
|
||||
const char8 *functionName, SignalDirection direction,
|
||||
volatile bool *anyActiveFlag, Vec<uint32> *activeIndices,
|
||||
@@ -164,16 +185,14 @@ public:
|
||||
signalInfoPointers[i] = NULL_PTR(DebugSignalInfo *);
|
||||
}
|
||||
|
||||
ReferenceContainer *root = ObjectRegistryDatabase::Instance();
|
||||
Reference serviceRef = root->Find("DebugService");
|
||||
if (serviceRef.IsValid()) {
|
||||
service = dynamic_cast<DebugService *>(serviceRef.operator->());
|
||||
}
|
||||
// Use the singleton registered by DebugService::Initialise() — no ORD
|
||||
// search on the Init path, and no dependency on a concrete type.
|
||||
service = DebugServiceI::GetInstance();
|
||||
|
||||
if (service && (copyTable != NULL_PTR(MemoryMapBrokerCopyTableEntry *))) {
|
||||
|
||||
StreamString dsPath;
|
||||
DebugService::GetFullObjectName(dataSourceIn, dsPath);
|
||||
DebugServiceI::GetFullObjectName(dataSourceIn, dsPath);
|
||||
fprintf(stderr, ">> %s broker for %s [%d]\n",
|
||||
direction == InputSignals ? "Input" : "Output", dsPath.Buffer(),
|
||||
numCopies);
|
||||
@@ -225,7 +244,7 @@ public:
|
||||
|
||||
if (gamRef.IsValid()) {
|
||||
StreamString absGamPath;
|
||||
DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath);
|
||||
DebugServiceI::GetFullObjectName(*(gamRef.operator->()), absGamPath);
|
||||
// Register short path (In/Out) for GUI compatibility
|
||||
gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStrShort,
|
||||
signalName.Buffer());
|
||||
@@ -261,7 +280,7 @@ public:
|
||||
template <typename BaseClass> class DebugBrokerWrapper : public BaseClass {
|
||||
public:
|
||||
DebugBrokerWrapper() : BaseClass() {
|
||||
service = NULL_PTR(DebugService *);
|
||||
service = NULL_PTR(DebugServiceI *);
|
||||
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
|
||||
numSignals = 0;
|
||||
anyActive = false;
|
||||
@@ -326,7 +345,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
DebugService *service;
|
||||
DebugServiceI *service;
|
||||
DebugSignalInfo **signalInfoPointers;
|
||||
uint32 numSignals;
|
||||
volatile bool anyActive;
|
||||
@@ -343,7 +362,7 @@ template <typename BaseClass>
|
||||
class DebugBrokerWrapperNoOptim : public BaseClass {
|
||||
public:
|
||||
DebugBrokerWrapperNoOptim() : BaseClass() {
|
||||
service = NULL_PTR(DebugService *);
|
||||
service = NULL_PTR(DebugServiceI *);
|
||||
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
|
||||
numSignals = 0;
|
||||
anyActive = false;
|
||||
@@ -386,7 +405,7 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
DebugService *service;
|
||||
DebugServiceI *service;
|
||||
DebugSignalInfo **signalInfoPointers;
|
||||
uint32 numSignals;
|
||||
volatile bool anyActive;
|
||||
@@ -402,7 +421,7 @@ public:
|
||||
class DebugMemoryMapAsyncOutputBroker : public MemoryMapAsyncOutputBroker {
|
||||
public:
|
||||
DebugMemoryMapAsyncOutputBroker() : MemoryMapAsyncOutputBroker() {
|
||||
service = NULL_PTR(DebugService *);
|
||||
service = NULL_PTR(DebugServiceI *);
|
||||
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
|
||||
numSignals = 0;
|
||||
anyActive = false;
|
||||
@@ -446,7 +465,7 @@ public:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
DebugService *service;
|
||||
DebugServiceI *service;
|
||||
DebugSignalInfo **signalInfoPointers;
|
||||
uint32 numSignals;
|
||||
volatile bool anyActive;
|
||||
@@ -463,7 +482,7 @@ class DebugMemoryMapAsyncTriggerOutputBroker
|
||||
public:
|
||||
DebugMemoryMapAsyncTriggerOutputBroker()
|
||||
: MemoryMapAsyncTriggerOutputBroker() {
|
||||
service = NULL_PTR(DebugService *);
|
||||
service = NULL_PTR(DebugServiceI *);
|
||||
signalInfoPointers = NULL_PTR(DebugSignalInfo **);
|
||||
numSignals = 0;
|
||||
anyActive = false;
|
||||
@@ -506,7 +525,7 @@ public:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
DebugService *service;
|
||||
DebugServiceI *service;
|
||||
DebugSignalInfo **signalInfoPointers;
|
||||
uint32 numSignals;
|
||||
volatile bool anyActive;
|
||||
|
||||
Reference in New Issue
Block a user