29 std::map<uint32, TimeQueueSchedule*>::iterator it, itEnd;
30 for (it = schedules.begin(), itEnd = schedules.end(); it!=itEnd; it++)
38 if (schedules[schedule->
id]) {
42 schedules[schedule->
id] = schedule;
44 return timer->addTimer(schedule->
id, schedule->
interval, schedule->
start, schedule->
end);
54 timer->removeTimer(
id);
65 if (!timer->waitForTimer(ms,
id, time))
91 masterCreatedTime = 0;
93 this->isAdHoc = isAdHoc;
98 this->isLocal = isLocal;
99 this->procID = procID;
100 finishedShuttingDown =
false;
102 memset(waitCounters, 0, 3*
sizeof(uint32));
103 memset(procCounters, 0, 3*
sizeof(uint32));
105 threadPoolWaitLowerThreshold = 5;
106 threadPoolWaitUpperThreshold = 20;
107 threadPoolWaitIncrement = 5;
109 threadPoolCheckInterval = 5000;
130 if (timeQ)
delete(timeQ);
138 this->isMaster = isMaster;
143 if (!
manager->connect(systemID, isMaster)) {
149 finishedShuttingDown =
false;
153 if (!
manager->processMemory->getProcessID(name.c_str(), checkID)) {
159 else if (procID != checkID) {
160 LogPrint(0,
LOG_SPACE, 0,
"Process ID '%u' does not match shared memory id '%u'...", procID, checkID);
165 if (
manager->processMemory->getProcessID(name.c_str(), checkID) && checkID) {
169 if (!
manager->processMemory->createNewProcess(name.c_str(), procID)) {
170 LogPrint(0,
LOG_SPACE, 0,
"PsySpace couldn't connect to local Node %u...", systemID);
178 if (!
manager->processMemory->addToCmdQ(0, msg)) {
179 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with System Command Queue...");
191 manager->processMemory->setProcessCommandLine(procID, cmdline);
197 if (!
manager->processMemory->addToCmdQ(0, msg)) {
198 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with System Command Queue...");
212 manager->getNodeStatus(lastSeen, masterCreatedTime);
229 uint64 lastSeen, createTime;
230 uint8 status =
manager->getNodeStatus(lastSeen, createTime);
231 if (masterCreatedTime && (createTime != masterCreatedTime)) {
232 LogPrint(procID,
LOG_SPACE, 0,
"Psyclone Node process appears to have restarted...");
237 LogPrint(procID,
LOG_SPACE, 0,
"Psyclone Node process doesn't appear to be running...");
242 LogPrint(procID,
LOG_SPACE, 0,
"Psyclone Node process appears to have stopped, resetting connection...");
257 std::map<std::string, utils::Library*>::iterator it = libraries.begin(), itEnd = libraries.end();
259 delete((it++)->second);
262 std::map<uint32, PsyAPI*>::iterator ait = psyAPIs.begin(), aitEnd = psyAPIs.end();
263 while (ait != aitEnd)
264 delete((ait++)->second);
267 std::map<PsyType, SignalStruct*>::iterator sit = signalList.begin(), sitEnd = signalList.end();
268 while (sit != sitEnd) {
269 delete(sit->second->lastSignalMsg);
270 delete((sit++)->second);
278 LogPrint(procID,
LOG_SPACE, 1,
"PsySpace '%s' (%u) starting up...", name.c_str(), procID);
279 return setThreadPoolSize(threadCount);
283 if (finishedShuttingDown)
285 finishedShuttingDown =
true;
289 LogPrint(procID,
LOG_SPACE, 1,
"PsySpace '%s' (%u) shutting down...", name.c_str(), procID);
292 if (!
manager->processMemory->addToCmdQ(0, msg)) {
293 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with System Command Queue...");
300 std::map<uint32, PsyAPI*>::iterator it, itEnd;
301 for (it=psyAPIs.begin(), itEnd=psyAPIs.end(); it != itEnd; it++)
304 uint32 maxWaitCount = 20;
305 while (threadPool.size()) {
307 if (!(--maxWaitCount)) {
308 LogPrint(procID,
LOG_SPACE, 0,
"PsySpace '%s' waited for the last %u threads to terminate, killing threads now...", name.c_str(), threadPool.size());
309 std::map<uint32, uint8>::iterator threadI = threadPool.begin(), threadE = threadPool.end();
310 while (threadI != threadE) {
312 LogPrint(procID,
LOG_SPACE, 0,
"PsySpace '%s' couldn't kill thread %u...", name.c_str(), threadI->first);
314 LogPrint(procID,
LOG_SPACE, 0,
"PsySpace '%s' killed thread %u...", name.c_str(), threadI->first);
322 LogPrint(procID,
LOG_SPACE,0,
"PsySpace '%s' waiting for the main thread to terminate...", name.c_str());
327 LogPrint(procID,
LOG_SPACE, 0,
"PsySpace '%s' has shut down (%u, %p)", name.c_str(), procID,
this);
332 return finishedShuttingDown;
340 manager->processMemory->addToCmdQ(0, msg);
351 msg->
setData(
"LogEntry", (
char*)entry, entry->
size);
352 manager->processMemory->addToCmdQ(0, msg);
362bool PsySpace::setThreadPoolSize(uint16 threadCount) {
366 int32 c = threadCount - (uint32)threadPool.size();
367 threadTarget = threadCount;
372 c, (uint32)threadPool.size(), threadCount);
374 for (n=0; n<c; n++) {
387 if (!
manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
390 uint32 compID =
manager->dataMapsMemory->getCrankCompID(crankID);
394 uint16 oldCompNodeID =
manager->componentMemory->getComponentNodeID(compID);
398 if (!pullRemoteComponentData(compID, oldCompNodeID))
401 if (!threadPoolMutex.enter(1000, __FUNCTION__))
403 if (!(api = psyAPIs[crankID])) {
406 api->currentCompID = compID;
407 psyAPIs[crankID] = api;
409 threadPoolMutex.leave();
415 if (!
manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
417 if (!threadPoolMutex.enter(1000, __FUNCTION__))
419 cranks[crankID] = func;
420 threadPoolMutex.leave();
426 if (
manager->componentMemory->getComponentID(name, compID))
432bool PsySpace::pullRemoteComponentData(uint32 compID, uint16 fromNodeID) {
434 msg->
setInt(
"CompID", compID);
435 msg->
setInt(
"ProcID", this->procID);
436 msg->
setInt(
"NodeID", fromNodeID);
438 uint8 result =
query(msg, &resultMsg, 5000);
468 uint64 eol = msg->
getEOL();
469 if (eol && (eol < msg->getCreatedTime() - 10000))
472 if (!
manager->insertMessage(msg, memID)) {
478 if (!
manager->processMemory->addToMsgQ(0, msg)) {
479 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with System Message Queue...");
482 manager->processMemory->addToProcessStats(procID, NULL, msg);
491 if (!signalsMutex.enter(3000, __FUNCTION__))
497 signalList[type] = signal;
499 signalsMutex.leave();
501 if (signal->
mutex.
enter(3000, __FUNCTION__)) {
513 if (!
manager->processMemory->addToAllSignalQsExcept(msg, procID)) {
514 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with All Signal Queues...");
517 manager->processMemory->addToProcessStats(procID, NULL, msg);
523 if (!signalsMutex.enter(3000, __FUNCTION__))
529 signalList[type] = signal;
531 signalsMutex.leave();
535 if (lastReceivedTime) {
536 if (signal->
mutex.
enter(3000, __FUNCTION__)) {
542 manager->processMemory->addToProcessStats(procID, msg, NULL);
565 if (lastReceivedTime) {
579 manager->processMemory->addToProcessStats(procID, msg, NULL);
589 uint32 to = msg->
getTo();
592 if (!
manager->dataMapsMemory->createNewRequest(msg->
getFrom(), to, 0, reqID))
597 manager->processMemory->addToProcessStats(procID, NULL, msg);
599 uint16 otherNodeID = 0;
600 uint16 otherProcID = 0;
604 if (!
manager->processMemory->addToReqQ(0, msg)) {
605 manager->dataMapsMemory->deleteRequest(reqID);
610 if (!
manager->componentMemory->getComponentLocation(to, otherNodeID, otherProcID))
613 if (otherNodeID !=
manager->getNodeID()) {
615 if (!
manager->processMemory->addToReqQ(0, msg)) {
616 manager->dataMapsMemory->deleteRequest(reqID);
622 otherProcID =
manager->componentMemory->getComponentProcessID(to);
623 if (!
manager->processMemory->addToReqQ(otherProcID, msg)) {
624 manager->dataMapsMemory->deleteRequest(reqID);
634 if (!
manager->dataMapsMemory->waitForRequestReply(reqID, timeout, status, time, msgID, msgEOL)) {
635 LogPrint(procID,
LOG_SPACE,0,
"Request reply timeout (%u) from node %u (req %u from comp %u)...",
636 status, otherNodeID, reqID, msg->
getFrom());
637 manager->dataMapsMemory->deleteRequest(reqID);
640 manager->dataMapsMemory->deleteRequest(reqID);
646 LogPrint(procID,
LOG_SPACE, 0,
"Request failed as remote system cannot be reached (req %u from comp %u)...", reqID, msg->
getFrom());
648 LogPrint(procID,
LOG_SPACE,0,
"Request reply failed (%u) from node %u (req %u from comp %u)...", status, otherNodeID, reqID, msg->
getFrom());
655 if (!(*result =
manager->temporalMemory->getCopyOfMessage(msgID))) {
656 LogPrint(procID,
LOG_SPACE,0,
"Couldn't getCopyOfMessage reply from node %u (req %u from comp %u)...", otherNodeID, reqID, msg->
getFrom());
661 manager->processMemory->addToProcessStats(procID, *result, NULL);
668 manager->processMemory->addToProcessStats(procID, NULL, resultMsg);
673 if (!
manager->dataMapsMemory->getRequestInfo(
id, origin, source, remoteID)) {
678 if (remoteID && !origin) {
685 manager->processMemory->addToReqQ(0, netMsg);
694 uint16 otherNodeID =
manager->componentMemory->getComponentNodeID(origin);
695 if (otherNodeID && (otherNodeID !=
manager->getNodeID())) {
701 manager->processMemory->addToReqQ(0, netMsg);
705 return manager->dataMapsMemory->deleteRequest(
id);
708 LogPrint(procID,
LOG_SPACE,0,
"Couldn't find otherNode %u for remote request %u (local %u) (source %u, origin %u)...",
709 otherNodeID, remoteID,
id, source, origin);
719 resultMsg->
setTTL(10000000);
720 msgEOL = resultMsg->
getEOL();
722 manager->temporalMemory->insertMessage(resultMsg, msgID);
738 return manager->dataMapsMemory->setRequestStatus(
id, reqStatus, msgID, msgEOL);
751bool PsySpace::threadPoolDispatch() {
755 uint32 idleCount = 0;
760 crankFunction[0] = 0;
762 crankLanguage[0] = 0;
764 libraryFilename[0] = 0;
773 threadPoolMutex.
enter();
778 if (idleCount < threadPoolWaitLowerThreshold)
779 setThreadPoolSize((uint16)(threadPool.size() + threadPoolWaitIncrement));
786 if (threadTarget < threadPool.size()) {
787 threadPoolMutex.
leave();
795 waitCounters[proc]++;
796 threadPoolMutex.
leave();
804 waitCounters[proc]++;
805 threadPoolMutex.leave();
806 msg =
manager->processMemory->waitForReqQ(procID, 100);
811 waitCounters[proc]++;
812 threadPoolMutex.leave();
813 if (msg =
manager->processMemory->waitForSigQ(procID, 100)) {
814 manager->processMemory->addToProcessStats(procID, msg, NULL);
816 if (signalsMutex.enter(3000, __FUNCTION__)) {
817 SignalStruct* signal = signalList[msg->
getType()];
819 signal =
new SignalStruct;
820 signal->lastSignalMsg = NULL;
821 signalList[msg->
getType()] = signal;
823 signalsMutex.leave();
824 if (signal->mutex.enter(3000, __FUNCTION__)) {
825 if (signal->lastSignalMsg)
826 delete(signal->lastSignalMsg);
827 signal->lastSignalMsg = msg;
828 signal->mutex.leave();
829 signal->event.signal();
846 while (!threadPoolMutex.enter(1000,
"Threadpool run with msg")) {
849 waitCounters[proc]--;
850 procCounters[proc]++;
861 if (!(compID = msg->
getTo())) {
864 procCounters[proc]--;
865 threadPoolMutex.leave();
869 manager->processMemory->addToProcessStats(procID, msg, NULL);
872 if (!(trigger = (TriggerSpec*) msg->
getData(
"TriggerSpec", s))) {
874 procCounters[proc]--;
875 threadPoolMutex.leave();
883 procCounters[proc]--;
884 threadPoolMutex.leave();
892 procCounters[proc]--;
893 threadPoolMutex.leave();
899 if (!(crankID = compCrankIDs[compID])) {
903 if (
manager->dataMapsMemory->getCrankID(compName, crankID)) {
904 compCrankIDs[compID] = crankID;
910 LogPrint(procID,
LOG_SPACE, 0,
"Unknown Component Crank for '%s' (%u)", compName, compID);
913 procCounters[proc]--;
914 threadPoolMutex.leave();
922 if (!crank && !(crank = cranks[crankID])) {
923 manager->dataMapsMemory->getCrankName(crankID, crankName, 256);
925 if (
manager->dataMapsMemory->getCrankLanguage(crankID, crankLanguage,
MAXVALUENAMELEN) && crankLanguage && strlen(crankLanguage)) {
928 LogPrint(procID,
LOG_SPACE, 0,
"Scripted language (%s) crank '%s' loading binary library '%s'", crankLanguage, crankName, libraryFilename);
932 if (!
manager->dataMapsMemory->getCrankFunction(crankID, crankFunction,
MAXVALUENAMELEN) || !crankFunction) {
933 LogPrint(procID,
LOG_SPACE, 0,
"Unknown Crank ID %u in Trigger Message", crankID);
935 procCounters[proc]--;
936 threadPoolMutex.leave();
939 if (!
manager->dataMapsMemory->getCrankLibraryFilename(crankID, libraryFilename,
MAXVALUENAMELEN) || !libraryFilename) {
940 LogPrint(procID,
LOG_SPACE, 0,
"Crank '%s' doesn't have a valid library specified", crankFunction);
942 procCounters[proc]--;
943 threadPoolMutex.leave();
952 if (crankFunction && strlen(crankFunction)) {
953 if (!(crank = loadCrankFromLibrary(crankFunction, libraryFilename))) {
954 if (strlen(crankLanguage)) {
955 LogPrint(procID,
LOG_SPACE, 0,
"The language library '%s' is unavailable - the language name '%s' may be incorrect", libraryFilename, crankLanguage);
958 LogPrint(procID,
LOG_SPACE, 0,
"Couldn't find crank '%s' in library '%s'", crankFunction, libraryFilename);
960 procCounters[proc]--;
961 threadPoolMutex.leave();
964 cranks[crankID] = crank;
971 if (!(api = psyAPIs[crankID])) {
974 psyAPIs[crankID] = api;
979 status = api->addInputTrigger(crankID, compID, msg, dmsg);
982 status = api->addInputTrigger(crankID, compID, NULL, msg);
986 procCounters[proc]--;
987 threadPoolMutex.leave();
997 procCounters[proc]--;
998 threadPoolMutex.leave();
1002 threadPoolMutex.leave();
1012 LogPrint(procID,
LOG_SPACE, 0,
"Crank %u ('%s') caused an exception", crankID, crankName);
1019 threadPoolMutex.enter();
1020 procCounters[proc]--;
1022 threadPoolMutex.leave();
1026 LogPrint(procID,
LOG_SPACE,3,
"Thread Pool %u exited, target %u, size: %u",
threadID, threadTarget, threadPool.size() - 1);
1027 threadPoolMutex.enter();
1028 std::map<uint32, uint8>::iterator i = threadPool.find(
threadID);
1029 if (i != threadPool.end())
1030 threadPool.erase(i);
1031 threadPoolMutex.leave();
1032 delete [] crankName;
1033 delete [] crankFunction;
1034 delete [] libraryFilename;
1038CrankFunction PsySpace::loadCrankFromLibrary(
const char* crankName,
const char* libraryFilename) {
1039 if (!crankName || !libraryFilename)
1042 if (!strlen(libraryFilename)) {
1044 return internalCranks[crankName];
1047 utils::Library* lib = libraries[libraryFilename];
1050 LogPrint(procID,
LOG_SPACE, 0,
"Could not find or load library '%s'", libraryFilename);
1053 libraries[libraryFilename] = lib;
1058 LogPrint(procID,
LOG_SPACE, 0,
"Could not load Crank '%s' from library '%s'", crankName, libraryFilename);
1065bool PsySpace::startContinuousComponent(uint32 compID) {
1067 std::map<uint32, uint32>::iterator it = continuousComponentThreads.find(compID);
1068 if (it != continuousComponentThreads.end())
1071 continuousComponentThreads[
threadID] = 0;
1077 continuousComponentThreads[
threadID] = compID;
1081bool PsySpace::runContinuousComponent() {
1083 DataMessage* msg = NULL;
1089 while (!(compID = continuousComponentThreads[
threadID])) {
1105bool PsySpace::run() {
1110 uint64 currentCPUTicks;
1112 uint32 checkCount = 50, c = 0;
1113 uint64 lastMsgCheck;
1114 std::map<uint32, PsyAPI*>::iterator i, e = psyAPIs.end();
1118 if (cmsg =
manager->processMemory->waitForCmdQ(procID, 100)) {
1132 i = psyAPIs.begin();
1134 if ((i->second) && (lastMsgCheck = i->second->checkLastWaitForMessage())) {
1135 i->second->logPrint(1,
"Component has unchecked messages, last check %s ago",
#define REQ_PROCESSING_REMOTE
#define REQ_SUCCESS_DATA_EOL
#define REQ_FAILED_DATA_EOL
#define REQ_FAILED_TO_SEND
#define REQ_PROCESSING_LOCAL
#define PSYCLONE_STATUS_READY
Instance is fully operational.
#define PSYPROC_INIT
Process is initialising.
#define PSYPROC_ACTIVE
Process is actively running.
#define PSYPROC_SHUTTING_DOWN
Process is shutting down.
#define PSYPROC_TERMINATED
Process has terminated.
#define PSYPROC_READY
Process is ready to run components.
#define QUERY_NOT_REACHABLE
The target could not be reached (e.g.
#define QUERY_SUCCESS
The query succeeded.
#define CRANKAPI_RUNNING
The crank is currently executing.
#define QUERY_FAILED
General failure.
#define CRANKAPI_IDLE
The crank is idle, waiting for input.
#define CRANKAPI_FAILED
The API could not be obtained or is invalid.
#define QUERY_TIMEOUT
No reply within the timeout.
The PsySpace process/node context: the runtime container in which Psyclone components (cranks) live a...
#define PROCSIGNAL
Signal processing.
#define LOG_SPACE
Log source id used by PsySpace when writing entries to the system log.
#define PROCREQUEST
Query/request processing.
#define PROCMESSAGE
Ordinary trigger-message processing.
#define thread_ret_val(ret)
#define THREAD_FUNCTION_CALL
The central Psyclone data container: a self-contained binary message with typed, named user entries.
bool setTTL(uint64 ttl)
setTTL(uint64 ttl)
uint32 getFrom()
getFrom() Get the sender id
bool setString(const char *key, const char *value)
setString(const char* key, const char* value)
bool setInt(const char *key, int64 value)
setInt(const char* key, int64 value)
bool setTag(uint32 tag)
setTag(uint32 tag)
DataMessageHeader * data
Pointer to the message's flat memory block (header + user entries).
bool setStatus(uint16 status)
setStatus(uint16 status)
PsyType getType()
getType()
const char * getData(const char *key, uint32 &size)
getData(const char* key, uint32& size)
bool setAttachedMessage(const char *key, DataMessage *msg)
setAttachedMessage(const char* key, DataMessage* msg)
bool setReference(uint64 ref)
setReference(uint64 ref) Set message reference
DataMessage * getAttachedMessageCopy(const char *key)
getAttachedMessageCopy(const char* key)
uint64 getCreatedTime()
getCreatedTime()
bool setData(const char *key, const char *value, uint32 size)
setData(const char* key, const char* value, uint32 size)
static bool SetLogReceiver(LogReceiver *rec)
Register a receiver that gets every accepted LogEntry.
Top-level facade of the shared-memory subsystem for one process.
ProcessMemory * processMemory
Accessor for the process table and per-process queues.
DataMessage * waitForMsgQ(uint16 procID, uint32 timeout)
Wait on the data-message queue.
The API handle a component (crank) uses to talk to the Psyclone system.
static struct PsyType CTRL_PROCESS_INITIALISE
Sent to a process to initialise it.
static struct PsyType CTRL_PROCESS_SHUTDOWN
Orders a single process to shut down.
static struct PsyType CTRL_PULLCOMPONENTDATA
Requests component data from another node.
static struct PsyType CTRL_TRIGGER
Wraps a trigger delivery to a component.
static struct PsyType CTRL_PROCESS_GREETING
Handshake from a newly joined process.
bool shouldContinue()
Check whether the crank should keep running, or exit its loop.
static struct PsyType CTRL_QUERY_REPLY
Carries a query reply back to the asker.
bool setCommandlineBasedir(const char *cmdlineBasedir)
Internal use only.
uint32 getInputQueueSize()
Get the size of the input queue, i.e.
static struct PsyType CTRL_INTERSYSTEM_QUERY_REPLY
Reply from a different Psyclone system.
static struct PsyType CTRL_SYSTEM_SHUTDOWN
Orders a full system shutdown.
static struct PsyType CTRL_CREATECUSTOMPAGE
Registers a custom PsyProbe view.
bool postMessage(DataMessage *msg)
Post a raw message into the system for distribution to subscribers.
bool reset()
Reset the space's runtime state (counters, queues) without disconnecting.
bool connect(uint16 systemID, bool isMaster=false, const char *cmdline=NULL)
Join a Psyclone system (attach to the node's shared memory).
bool shutdown()
Request an orderly shutdown of the space and all its components.
friend THREAD_RET THREAD_FUNCTION_CALL PsySpaceRun(THREAD_ARG arg)
Thread entry for the space's main service thread.
bool start(uint16 threadCount=5)
Start processing: spin up the thread pool and begin dispatching triggers.
uint8 query(DataMessage *msg, DataMessage **result, uint32 timeout)
Send a query message and wait for its reply.
uint32 getComponentID(const char *name)
Look up the numeric component id for a component name.
DataMessage * waitForSignal(const PsyType &type, uint32 timeout, uint64 lastReceivedTime=0)
Block until a signal of the given type arrives (or has already arrived).
friend THREAD_RET THREAD_FUNCTION_CALL PsySpaceContinuousRun(THREAD_ARG arg)
Thread entry for continuously running components.
bool isConnected(uint32 timeoutMS=5000)
Wait until the space is fully connected to the system.
MemoryManager * manager
The process-local memory manager: entry point to the node's shared-memory fabric. Owned by the space.
bool registerCrankCallback(const char *name, CrankFunction func)
Register a C/C++ entry function for a crank, to be invoked by the thread pool when the component trig...
bool addPsyProbeCustomView(uint32 compID, const char *name, const char *templateURL)
Add a custom PsyProbe view tab for a component (space-level variant of PsyAPI::addPsyProbeCustomView(...
PsyAPI * getCrankAPI(const char *name)
Get (or create) the PsyAPI handle for a crank hosted in this space.
bool queryReply(uint32 id, uint8 status, DataMessage *result)
Reply to a previously received query.
bool emitSignal(const PsyType &type, DataMessage *msg)
Emit a system-wide signal of the given type.
bool logEntry(LogEntry *entry)
LogReceiver interface: accept a log entry produced within this space.
PsySpace(const char *name=NULL, bool isAdHoc=true, uint16 procID=0, bool isLocal=false)
Create a space (does not yet join a system; call connect()).
bool isRunning
Set by the worker while its loop is active.
virtual bool stop(uint32 timeout=200)
Ask the worker loop to finish and wait for it to do so.
uint32 threadID
ThreadManager slot ID of the worker thread (0 until known).
bool shouldContinue
Loop-continuation flag; cleared by stop().
static bool GetLocalThreadID(uint32 &id)
Look up the manager slot ID of the calling thread.
static bool CreateThread(THREAD_FUNCTION func, void *args, uint32 &newID, uint32 reqID=0)
Create a new native thread and start it immediately.
static bool TerminateThread(uint32 id)
Forcibly terminate the thread and release its slot.
Time-binned activation queue used by a PsySpace to drive time-triggered modules.
DataMessage * waitForNextEvent(uint32 ms)
Block until the next scheduled event is due, or the timeout expires.
bool removeSchedule(uint32 id)
Remove (and delete) a schedule by id.
bool addSchedule(TimeQueueSchedule *schedule)
Add a schedule to the queue.
~TimeQueue()
Destroy the queue and delete all remaining schedules (owned by the queue).
TimeQueue()
Create an empty time queue with its own timer.
One recurring (or time-bounded) activation schedule managed by a TimeQueue.
uint32 msgTag
Tag attached to the generated message.
uint64 start
First-activation time (µs), or 0 for immediate.
PsyType msgType
Type of the message generated on each activation.
uint32 interval
Repeat interval in milliseconds.
TimeQueueSchedule(uint32 interval, uint64 start=0, uint64 end=0)
Create a schedule.
~TimeQueueSchedule()
Destructor.
uint64 end
Expiry time (µs), or 0 for no expiry.
uint32 id
Unique schedule id, used for removal via TimeQueue::removeSchedule().
bool waitNext()
Block until the next signal() occurs.
bool signal()
Wake all threads currently waiting on this event.
bool leave()
Release the mutex.
bool enter()
Block until the mutex is acquired.
Multiplexing timer: schedule many periodic timers and consume their expiries from one queue.
std::string PrintTimeString(uint64 t, bool local=true, bool us=true, bool ms=true)
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
std::string PrintTimeDifString(uint64 t, bool us=true, bool ms=true)
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
bool Sleep(uint32 ms)
Suspend the calling thread.
std::string GetCommandLinePath()
Get the directory portion of the executable path.
double RandomValue()
Uniform random double in [0,1).
std::string TextTrimQuotes(const char *text)
Strip a single pair of surrounding quotes if present.
bool StringFormatInto(char *dst, uint32 maxsize, const char *format,...)
printf into a caller-supplied buffer with truncation.
bool GetProcessCPUTicks(uint64 &ticks)
Get accumulated CPU time of the current process.
std::string StringFormat(const char *format,...)
printf into a std::string.
Library * OpenLibrary(const char *libName)
Load a library by name, applying platform filename conventions.
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
std::string TextCapitalise(const char *text)
Capitalise the first letter of text.
int8 Internal_QueryTest(PsyAPI *api)
Exercises query/queryReply round-trips.
int8 Internal_Pong(PsyAPI *api)
Latency test counterpart: answers pings.
int8(* CrankFunction)(PsyAPI *api)
Signature of a component (crank) entry function.
int8 Internal_Print(PsyAPI *api)
Prints incoming messages to the console/log.
static struct PsyType CTRL_LOGPRINT
int8 Internal_Simple(PsyAPI *api)
Pass-through test crank: copies each incoming message to its posts.
int8 Internal_SignalPong(PsyAPI *api)
Signal-based pong counterpart.
int8 Internal_StatsLog(PsyAPI *api)
Periodically logs system statistics.
int8 Internal_SignalPing(PsyAPI *api)
Signal-based ping test.
THREAD_RET THREAD_FUNCTION_CALL PsySpaceContinuousRun(THREAD_ARG arg)
Continuous-component thread entry: runs PsySpace::runContinuousComponent() for the space passed in ar...
int8 Internal_MessageToggler(PsyAPI *api)
Alternates/toggles message output for testing.
int8 Internal_Shutdown(PsyAPI *api)
Initiates system shutdown when triggered.
THREAD_RET THREAD_FUNCTION_CALL PsySpaceRun(THREAD_ARG arg)
Main service-thread entry: runs PsySpace::run() for the space passed in arg.
int8 Internal_Ping(PsyAPI *api)
Latency test: posts pings, expects pongs.
int8 Internal_Time(PsyAPI *api)
Posts time information/timestamps.
THREAD_RET THREAD_FUNCTION_CALL PsySpacePoolRun(THREAD_ARG arg)
Pool worker-thread entry: runs PsySpace::threadPoolDispatch() for the space passed in arg.
int8 Internal_BitmapPoster(PsyAPI *api)
Posts test bitmap/image messages.
int8 Internal_MessageTypeConverter(PsyAPI *api)
Converts incoming messages to another type before reposting.
int8 Internal_MessageScript(PsyAPI *api)
Plays back scripted TrackPlayerMessage sequences.
int8 Internal_RetrieveTest(PsyAPI *api)
Exercises whiteboard retrieve calls.
Hierarchical message type identifier — the key used for publish/subscribe matching in Psyclone.
Wire/storage layout of one log record: fixed header immediately followed by the message text.
Per-signal bookkeeping for PsySpace signal distribution.
utils::Mutex mutex
Protects lastSignalMsg.
DataMessage * lastSignalMsg
Most recently emitted message for this signal type (owned by the space).
utils::Event event
Signalled whenever a new message arrives; wakes waiters.
A complete trigger definition: what fires a component's crank and what happens then.
uint16 crankID
Id of the crank (processing function) to run when fired.