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);
366bool PsySpace::setThreadPoolSize(uint16 threadCount) {
370 int32 c = threadCount - (uint32)threadPool.size();
371 threadTarget = threadCount;
376 c, (uint32)threadPool.size(), threadCount);
378 for (n=0; n<c; n++) {
391 if (!
manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
394 uint32 compID =
manager->dataMapsMemory->getCrankCompID(crankID);
398 uint16 oldCompNodeID =
manager->componentMemory->getComponentNodeID(compID);
402 if (!pullRemoteComponentData(compID, oldCompNodeID))
405 if (!threadPoolMutex.enter(1000, __FUNCTION__))
407 if (!(api = psyAPIs[crankID])) {
410 api->currentCompID = compID;
411 psyAPIs[crankID] = api;
413 threadPoolMutex.leave();
419 if (!
manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
421 if (!threadPoolMutex.enter(1000, __FUNCTION__))
423 cranks[crankID] = func;
424 threadPoolMutex.leave();
429 if (!name || !*name || !func)
431 if (!threadPoolMutex.enter(1000, __FUNCTION__))
433 internalCranks[name] = func;
434 threadPoolMutex.leave();
440 if (
manager->componentMemory->getComponentID(name, compID))
446bool PsySpace::pullRemoteComponentData(uint32 compID, uint16 fromNodeID) {
448 msg->
setInt(
"CompID", compID);
449 msg->
setInt(
"ProcID", this->procID);
450 msg->
setInt(
"NodeID", fromNodeID);
452 uint8 result =
query(msg, &resultMsg, 5000);
482 uint64 eol = msg->
getEOL();
483 if (eol && (eol < msg->getCreatedTime() - 10000))
486 if (!
manager->insertMessage(msg, memID)) {
492 if (!
manager->processMemory->addToMsgQ(0, msg)) {
493 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with System Message Queue...");
496 manager->processMemory->addToProcessStats(procID, NULL, msg);
505 if (!signalsMutex.enter(3000, __FUNCTION__))
511 signalList[type] = signal;
513 signalsMutex.leave();
515 if (signal->
mutex.
enter(3000, __FUNCTION__)) {
527 if (!
manager->processMemory->addToAllSignalQsExcept(msg, procID)) {
528 LogPrint(procID,
LOG_SPACE, 0,
"Could not communicate with All Signal Queues...");
531 manager->processMemory->addToProcessStats(procID, NULL, msg);
537 if (!signalsMutex.enter(3000, __FUNCTION__))
543 signalList[type] = signal;
545 signalsMutex.leave();
549 if (lastReceivedTime) {
550 if (signal->
mutex.
enter(3000, __FUNCTION__)) {
556 manager->processMemory->addToProcessStats(procID, msg, NULL);
579 if (lastReceivedTime) {
593 manager->processMemory->addToProcessStats(procID, msg, NULL);
603 uint32 to = msg->
getTo();
606 if (!
manager->dataMapsMemory->createNewRequest(msg->
getFrom(), to, 0, reqID))
611 manager->processMemory->addToProcessStats(procID, NULL, msg);
613 uint16 otherNodeID = 0;
614 uint16 otherProcID = 0;
618 if (!
manager->processMemory->addToReqQ(0, msg)) {
619 manager->dataMapsMemory->deleteRequest(reqID);
624 if (!
manager->componentMemory->getComponentLocation(to, otherNodeID, otherProcID))
627 if (otherNodeID !=
manager->getNodeID()) {
629 if (!
manager->processMemory->addToReqQ(0, msg)) {
630 manager->dataMapsMemory->deleteRequest(reqID);
636 otherProcID =
manager->componentMemory->getComponentProcessID(to);
637 if (!
manager->processMemory->addToReqQ(otherProcID, msg)) {
638 manager->dataMapsMemory->deleteRequest(reqID);
648 if (!
manager->dataMapsMemory->waitForRequestReply(reqID, timeout, status, time, msgID, msgEOL)) {
649 LogPrint(procID,
LOG_SPACE,0,
"Request reply timeout (%u) from node %u (req %u from comp %u)...",
650 status, otherNodeID, reqID, msg->
getFrom());
651 manager->dataMapsMemory->deleteRequest(reqID);
654 manager->dataMapsMemory->deleteRequest(reqID);
660 LogPrint(procID,
LOG_SPACE, 0,
"Request failed as remote system cannot be reached (req %u from comp %u)...", reqID, msg->
getFrom());
662 LogPrint(procID,
LOG_SPACE,0,
"Request reply failed (%u) from node %u (req %u from comp %u)...", status, otherNodeID, reqID, msg->
getFrom());
669 if (!(*result =
manager->temporalMemory->getCopyOfMessage(msgID))) {
670 LogPrint(procID,
LOG_SPACE,0,
"Couldn't getCopyOfMessage reply from node %u (req %u from comp %u)...", otherNodeID, reqID, msg->
getFrom());
675 manager->processMemory->addToProcessStats(procID, *result, NULL);
682 manager->processMemory->addToProcessStats(procID, NULL, resultMsg);
687 if (!
manager->dataMapsMemory->getRequestInfo(
id, origin, source, remoteID)) {
692 if (remoteID && !origin) {
699 manager->processMemory->addToReqQ(0, netMsg);
708 uint16 otherNodeID =
manager->componentMemory->getComponentNodeID(origin);
709 if (otherNodeID && (otherNodeID !=
manager->getNodeID())) {
715 manager->processMemory->addToReqQ(0, netMsg);
719 return manager->dataMapsMemory->deleteRequest(
id);
722 LogPrint(procID,
LOG_SPACE,0,
"Couldn't find otherNode %u for remote request %u (local %u) (source %u, origin %u)...",
723 otherNodeID, remoteID,
id, source, origin);
733 resultMsg->
setTTL(10000000);
734 msgEOL = resultMsg->
getEOL();
736 manager->temporalMemory->insertMessage(resultMsg, msgID);
752 return manager->dataMapsMemory->setRequestStatus(
id, reqStatus, msgID, msgEOL);
765bool PsySpace::threadPoolDispatch() {
769 uint32 idleCount = 0;
774 crankFunction[0] = 0;
776 crankLanguage[0] = 0;
778 libraryFilename[0] = 0;
787 threadPoolMutex.
enter();
792 if (idleCount < threadPoolWaitLowerThreshold)
793 setThreadPoolSize((uint16)(threadPool.size() + threadPoolWaitIncrement));
800 if (threadTarget < threadPool.size()) {
801 threadPoolMutex.
leave();
809 waitCounters[proc]++;
810 threadPoolMutex.
leave();
818 waitCounters[proc]++;
819 threadPoolMutex.leave();
820 msg =
manager->processMemory->waitForReqQ(procID, 100);
825 waitCounters[proc]++;
826 threadPoolMutex.leave();
827 if (msg =
manager->processMemory->waitForSigQ(procID, 100)) {
828 manager->processMemory->addToProcessStats(procID, msg, NULL);
830 if (signalsMutex.enter(3000, __FUNCTION__)) {
831 SignalStruct* signal = signalList[msg->
getType()];
833 signal =
new SignalStruct;
834 signal->lastSignalMsg = NULL;
835 signalList[msg->
getType()] = signal;
837 signalsMutex.leave();
838 if (signal->mutex.enter(3000, __FUNCTION__)) {
839 if (signal->lastSignalMsg)
840 delete(signal->lastSignalMsg);
841 signal->lastSignalMsg = msg;
842 signal->mutex.leave();
843 signal->event.signal();
860 while (!threadPoolMutex.enter(1000,
"Threadpool run with msg")) {
863 waitCounters[proc]--;
864 procCounters[proc]++;
883 if (!(compID = msg->
getTo())) {
886 procCounters[proc]--;
887 threadPoolMutex.leave();
891 manager->processMemory->addToProcessStats(procID, msg, NULL);
897 if (!(trigger = (TriggerSpec*) msg->
getData(
"TriggerSpec", s))) {
899 procCounters[proc]--;
900 threadPoolMutex.leave();
908 procCounters[proc]--;
909 threadPoolMutex.leave();
918 procCounters[proc]--;
919 threadPoolMutex.leave();
928 if (!(crankID = compCrankIDs[compID])) {
932 if (
manager->dataMapsMemory->getCrankID(compName, crankID)) {
933 compCrankIDs[compID] = crankID;
939 LogPrint(procID,
LOG_SPACE, 0,
"Unknown Component Crank for '%s' (%u)", compName, compID);
942 procCounters[proc]--;
943 threadPoolMutex.leave();
951 if (!crank && !(crank = cranks[crankID])) {
952 manager->dataMapsMemory->getCrankName(crankID, crankName, 256);
954 if (
manager->dataMapsMemory->getCrankLanguage(crankID, crankLanguage,
MAXVALUENAMELEN) && crankLanguage && strlen(crankLanguage)) {
957 LogPrint(procID,
LOG_SPACE, 0,
"Scripted language (%s) crank '%s' loading binary library '%s'", crankLanguage, crankName, libraryFilename);
961 if (!
manager->dataMapsMemory->getCrankFunction(crankID, crankFunction,
MAXVALUENAMELEN) || !crankFunction) {
962 LogPrint(procID,
LOG_SPACE, 0,
"Unknown Crank ID %u in Trigger Message", crankID);
964 procCounters[proc]--;
965 threadPoolMutex.leave();
968 if (!
manager->dataMapsMemory->getCrankLibraryFilename(crankID, libraryFilename,
MAXVALUENAMELEN) || !libraryFilename) {
969 LogPrint(procID,
LOG_SPACE, 0,
"Crank '%s' doesn't have a valid library specified", crankFunction);
971 procCounters[proc]--;
972 threadPoolMutex.leave();
981 if (crankFunction && strlen(crankFunction)) {
982 if (!(crank = loadCrankFromLibrary(crankFunction, libraryFilename))) {
983 if (strlen(crankLanguage)) {
984 LogPrint(procID,
LOG_SPACE, 0,
"The language library '%s' is unavailable - the language name '%s' may be incorrect", libraryFilename, crankLanguage);
987 LogPrint(procID,
LOG_SPACE, 0,
"Couldn't find crank '%s' in library '%s'", crankFunction, libraryFilename);
989 procCounters[proc]--;
990 threadPoolMutex.leave();
993 cranks[crankID] = crank;
1000 if (!(api = psyAPIs[crankID])) {
1003 psyAPIs[crankID] = api;
1013 status = api->addInputTrigger(crankID, compID, msg, dmsg);
1018 status = api->addInputTrigger(crankID, compID, msg, NULL);
1021 status = api->addInputTrigger(crankID, compID, NULL, msg);
1025 procCounters[proc]--;
1026 threadPoolMutex.leave();
1047 DataMessage* requeue = dmsg ? dmsg : msg;
1048 DataMessage* discard = dmsg ? msg : NULL;
1053 procCounters[proc]--;
1054 threadPoolMutex.leave();
1056 if (!
manager->processMemory->addToMsgQ(procID, requeue)) {
1058 "re-queue FAILED; message DROPPED", crankID);
1069 procCounters[proc]--;
1070 threadPoolMutex.leave();
1074 threadPoolMutex.leave();
1084 LogPrint(procID,
LOG_SPACE, 0,
"Crank %u ('%s') caused an exception", crankID, crankName);
1090 threadPoolMutex.enter();
1091 procCounters[proc]--;
1093 threadPoolMutex.leave();
1097 LogPrint(procID,
LOG_SPACE,3,
"Thread Pool %u exited, target %u, size: %u",
threadID, threadTarget, threadPool.size() - 1);
1098 threadPoolMutex.enter();
1099 std::map<uint32, uint8>::iterator i = threadPool.find(
threadID);
1100 if (i != threadPool.end())
1101 threadPool.erase(i);
1102 threadPoolMutex.leave();
1103 delete [] crankName;
1104 delete [] crankFunction;
1105 delete [] libraryFilename;
1109CrankFunction PsySpace::loadCrankFromLibrary(
const char* crankName,
const char* libraryFilename) {
1110 if (!crankName || !libraryFilename)
1113 if (!strlen(libraryFilename)) {
1115 return internalCranks[crankName];
1118 utils::Library* lib = libraries[libraryFilename];
1121 LogPrint(procID,
LOG_SPACE, 0,
"Could not find or load library '%s'", libraryFilename);
1124 libraries[libraryFilename] = lib;
1129 LogPrint(procID,
LOG_SPACE, 0,
"Could not load Crank '%s' from library '%s'", crankName, libraryFilename);
1136bool PsySpace::startContinuousComponent(uint32 compID) {
1138 std::map<uint32, uint32>::iterator it = continuousComponentThreads.find(compID);
1139 if (it != continuousComponentThreads.end())
1142 continuousComponentThreads[
threadID] = 0;
1148 continuousComponentThreads[
threadID] = compID;
1152bool PsySpace::runContinuousComponent() {
1154 DataMessage* msg = NULL;
1160 while (!(compID = continuousComponentThreads[
threadID])) {
1176bool PsySpace::run() {
1181 uint64 currentCPUTicks;
1183 uint32 checkCount = 50, c = 0;
1184 uint64 lastMsgCheck;
1185 std::map<uint32, PsyAPI*>::iterator i, e = psyAPIs.end();
1189 if (cmsg =
manager->processMemory->waitForCmdQ(procID, 100)) {
1203 i = psyAPIs.begin();
1205 if ((i->second) && (lastMsgCheck = i->second->checkLastWaitForMessage())) {
1206 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 CRANKAPI_INUSE
The API is already in use by another thread.
#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_GROUP
T1.6: wraps a <triggergroup> joined-set delivery (member map) to a component.
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 registerInternalCrank(const char *name, CrankFunction func)
Register a built-in ("internal") crank by function name, resolved when a component's <crank function=...
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.
bool GetProcessCPUTicks(uint64 &ticks)
Get accumulated CPU time of the current process.
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
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.
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.
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.