CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
PsySpace.cpp
Go to the documentation of this file.
1
8#include "PsySpace.h"
9
10namespace cmlabs {
11
12
14 this->interval = interval;
15 this->start = start;
16 this->end = end;
17}
18
21
22
24 timer = new utils::Timer();
25}
26
28 mutex.enter();
29 std::map<uint32, TimeQueueSchedule*>::iterator it, itEnd;
30 for (it = schedules.begin(), itEnd = schedules.end(); it!=itEnd; it++)
31 delete(it->second);
32 delete(timer);
33 mutex.leave();
34}
35
37 mutex.enter();
38 if (schedules[schedule->id]) {
39 mutex.leave();
40 return false;
41 }
42 schedules[schedule->id] = schedule;
43 mutex.leave();
44 return timer->addTimer(schedule->id, schedule->interval, schedule->start, schedule->end);
45}
46
48 mutex.enter();
49 TimeQueueSchedule* schedule = schedules[id];
50 if (!schedule) {
51 mutex.leave();
52 return true;
53 }
54 timer->removeTimer(id);
55 schedules.erase(id);
56 delete(schedule);
57 mutex.leave();
58 return true;
59}
60
62
63 uint32 id;
64 uint64 time;
65 if (!timer->waitForTimer(ms, id, time))
66 return NULL;
67
68 mutex.enter();
69 TimeQueueSchedule* schedule = schedules[id];
70 if (!schedule) {
71 mutex.leave();
72 return NULL;
73 }
74
75 DataMessage* msg = new DataMessage(schedule->msgType, 0);
76 if (schedule->msgTag)
77 msg->setTag(schedule->msgTag);
78 mutex.leave();
79 return msg;
80}
81
82
83
84
85
86
87
88PsySpace::PsySpace(const char* name, bool isAdHoc, uint16 procID, bool isLocal) {
89 isMaster = true;
90 manager = NULL;
91 masterCreatedTime = 0;
92 timeQ = new TimeQueue();
93 this->isAdHoc = isAdHoc;
94 if (name)
95 this->name = utils::TextTrimQuotes(name);
96 else
97 this->name = utils::StringFormat("Unnamed_Space_%u", (uint32)utils::RandomValue(MAXVALUINT32));
98 this->isLocal = isLocal;
99 this->procID = procID;
100 finishedShuttingDown = false;
101
102 memset(waitCounters, 0, 3*sizeof(uint32));
103 memset(procCounters, 0, 3*sizeof(uint32));
104
105 threadPoolWaitLowerThreshold = 5;
106 threadPoolWaitUpperThreshold = 20;
107 threadPoolWaitIncrement = 5;
108 lastThreadPoolCheck = GetTimeNow();
109 threadPoolCheckInterval = 5000;
110
111 internalCranks["Simple"] = Internal_Simple;
112 internalCranks["Ping"] = Internal_Ping;
113 internalCranks["Pong"] = Internal_Pong;
114 internalCranks["Shutdown"] = Internal_Shutdown;
115 internalCranks["Print"] = Internal_Print;
116 internalCranks["Time"] = Internal_Time;
117 internalCranks["SignalPing"] = Internal_SignalPing;
118 internalCranks["SignalPong"] = Internal_SignalPong;
119 internalCranks["RetrieveTest"] = Internal_RetrieveTest;
120 internalCranks["MessageScript"] = Internal_MessageScript;
121 internalCranks["QueryTest"] = Internal_QueryTest;
122 internalCranks["StatsLog"] = Internal_StatsLog;
123 internalCranks["BitmapPoster"] = Internal_BitmapPoster;
124 internalCranks["MessageToggler"] = Internal_MessageToggler;
125 internalCranks["MessageTypeConverter"] = Internal_MessageTypeConverter;
126}
127
129 reset();
130 if (timeQ) delete(timeQ);
131 timeQ = NULL;
132}
133
134bool PsySpace::connect(uint16 systemID, bool isMaster, const char* cmdline) {
135
136 // LogPrint(0, LOG_SPACE, 1, "PsySpace '%s' starting up, connecting to local Node %u...", name.c_str(), systemID);
137
138 this->isMaster = isMaster;
139
140 // Connect to MemoryManager
141 if (manager) delete(manager);
142 manager = new MemoryManager();
143 if (!manager->connect(systemID, isMaster)) {
144 // LogPrint(0, LOG_SPACE, 0, "PsySpace couldn't connect to local Node %u...", systemID);
145 delete(manager);
146 manager = NULL;
147 return false;
148 }
149 finishedShuttingDown = false;
150
151 uint16 checkID;
152 if (!isAdHoc) {
153 if (!manager->processMemory->getProcessID(name.c_str(), checkID)) {
154 LogPrint(0, LOG_SPACE, 0, "Could not find process '%s'...", name.c_str());
155 return false;
156 }
157 if (!procID)
158 procID = checkID;
159 else if (procID != checkID) {
160 LogPrint(0, LOG_SPACE, 0, "Process ID '%u' does not match shared memory id '%u'...", procID, checkID);
161 return false;
162 }
163 }
164 else {
165 if (manager->processMemory->getProcessID(name.c_str(), checkID) && checkID) {
166 procID = checkID;
167 }
168 else {
169 if (!manager->processMemory->createNewProcess(name.c_str(), procID)) {
170 LogPrint(0, LOG_SPACE, 0, "PsySpace couldn't connect to local Node %u...", systemID);
171 return false;
172 }
173 }
174 }
175
176 // Send message on sysQID to inform node that process has started
178 if (!manager->processMemory->addToCmdQ(0, msg)) {
179 LogPrint(procID, LOG_SPACE, 0, "Could not communicate with System Command Queue...");
180 delete(msg);
181 return false;
182 }
183 delete(msg);
184
185 //if (!manager->processMemory->createNewProcess(name.c_str(), procID)) {
186 // LogPrint(0, 0, 0, "Could not create Process Map\n");
187 // return false;
188 //}
189
190 if (cmdline)
191 manager->processMemory->setProcessCommandLine(procID, cmdline);
192 manager->processMemory->setProcessStatus(procID, PSYPROC_INIT);
193
194 // Connect to Node
195 // Send message on sysQID to inform node that process has started
197 if (!manager->processMemory->addToCmdQ(0, msg)) {
198 LogPrint(procID, LOG_SPACE, 0, "Could not communicate with System Command Queue...");
199 delete(msg);
200 return false;
201 }
202 delete(msg);
203
204 if (isMaster) {
205 // Logging will be done via LogPrint directly to the Node as we are in the same process
206 }
207 else {
208 //LogSystem::SetLogReceiver(this);
209 }
210
211 uint64 lastSeen;
212 manager->getNodeStatus(lastSeen, masterCreatedTime);
213
214 // Setup Heartbeat
215 manager->processMemory->setProcessStatus(procID, PSYPROC_READY);
216
217 // Start SpaceThread
219 LogPrint(procID, LOG_SPACE, 0, "Could not start PsySpace thread...");
220 return false;
221 }
222
223 return true;
224}
225
226bool PsySpace::isConnected(uint32 timeoutMS) {
227 if (!manager) return false;
228
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...");
233 reset();
234 return false;
235 }
236 if (status != PSYCLONE_STATUS_READY) {
237 LogPrint(procID, LOG_SPACE, 0, "Psyclone Node process doesn't appear to be running...");
238 reset();
239 return false;
240 }
241 if (GetTimeAgeMS(lastSeen) > (int32)timeoutMS) {
242 LogPrint(procID, LOG_SPACE, 0, "Psyclone Node process appears to have stopped, resetting connection...");
243 reset();
244 return false;
245 }
246 return true;
247}
248
250 if (!isMaster)
252 if (manager)
253 shutdown();
254 if (manager) delete(manager);
255 manager = NULL;
256
257 std::map<std::string, utils::Library*>::iterator it = libraries.begin(), itEnd = libraries.end();
258 while (it != itEnd)
259 delete((it++)->second);
260 libraries.clear();
261
262 std::map<uint32, PsyAPI*>::iterator ait = psyAPIs.begin(), aitEnd = psyAPIs.end();
263 while (ait != aitEnd)
264 delete((ait++)->second);
265 psyAPIs.clear();
266
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);
271 }
272 signalList.clear();
273 return true;
274}
275
276bool PsySpace::start(uint16 threadCount) {
277 // Setup Threading Pool
278 LogPrint(procID, LOG_SPACE, 1, "PsySpace '%s' (%u) starting up...", name.c_str(), procID);
279 return setThreadPoolSize(threadCount);
280}
281
283 if (finishedShuttingDown)
284 return true;
285 finishedShuttingDown = true;
286 stop();
287
288 //LogPrint(procID, LOG_SPACE, 1, "Space ID %u shutting down...", procID);
289 LogPrint(procID, LOG_SPACE, 1, "PsySpace '%s' (%u) shutting down...", name.c_str(), procID);
290
292 if (!manager->processMemory->addToCmdQ(0, msg)) {
293 LogPrint(procID, LOG_SPACE, 0, "Could not communicate with System Command Queue...");
294 delete(msg);
295 return false;
296 }
297 delete(msg);
298
299 // shutdown all components
300 std::map<uint32, PsyAPI*>::iterator it, itEnd;
301 for (it=psyAPIs.begin(), itEnd=psyAPIs.end(); it != itEnd; it++)
302 it->second->stop();
303
304 uint32 maxWaitCount = 20;
305 while (threadPool.size()) {
306 utils::Sleep(50);
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) {
311 if (!ThreadManager::TerminateThread(threadI->first))
312 LogPrint(procID, LOG_SPACE, 0, "PsySpace '%s' couldn't kill thread %u...", name.c_str(), threadI->first);
313 else
314 LogPrint(procID, LOG_SPACE, 0, "PsySpace '%s' killed thread %u...", name.c_str(), threadI->first);
315 threadI++;
316 }
317 threadPool.clear();
318 break;
319 }
320 }
321 while (isRunning) {
322 LogPrint(procID, LOG_SPACE,0,"PsySpace '%s' waiting for the main thread to terminate...", name.c_str());
323 utils::Sleep(50);
324 }
325
326 manager->processMemory->setProcessStatus(procID, PSYPROC_TERMINATED);
327 LogPrint(procID, LOG_SPACE, 0, "PsySpace '%s' has shut down (%u, %p)", name.c_str(), procID, this);
328 return true;
329}
330
332 return finishedShuttingDown;
333}
334
335// ***************** PsyProbe plugins *****************
336bool PsySpace::addPsyProbeCustomView(uint32 compID, const char* name, const char* templateURL) {
338 msg->setString("Name", name);
339 msg->setString("Template", templateURL);
340 manager->processMemory->addToCmdQ(0, msg);
341 delete(msg);
342 return true;
343}
344
345
347 if (!entry)
348 return false;
349
350 DataMessage* msg = new DataMessage(CTRL_LOGPRINT, procID);
351 msg->setData("LogEntry", (char*)entry, entry->size);
352 manager->processMemory->addToCmdQ(0, msg);
353 delete(msg);
354 delete(entry);
355 return true;
356}
357
359 return procID;
360}
361
362bool PsySpace::setThreadPoolSize(uint16 threadCount) {
363
364 uint32 id;
365 int32 n;
366 int32 c = threadCount - (uint32)threadPool.size();
367 threadTarget = threadCount;
368// LogPrint(procID, LOG_SPACE,0,"Setting PsySpace thread pool size to %u...", threadTarget);
369 lastThreadPoolCheck = GetTimeNow();
370 if (c > 0) {
371 LogPrint(procID, LOG_SPACE,2,"Creating %u more Pool Threads [%u -> %u]...",
372 c, (uint32)threadPool.size(), threadCount);
373 // create c more threads
374 for (n=0; n<c; n++) {
376 threadPool[id] = 1;
377 else
378 return false;
379 }
380 }
381 return true;
382}
383
384PsyAPI* PsySpace::getCrankAPI(const char* name) {
385 PsyAPI* api;
386 uint16 crankID;
387 if (!manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
388 return NULL;
389
390 uint32 compID = manager->dataMapsMemory->getCrankCompID(crankID);
391 if (!compID)
392 return NULL;
393
394 uint16 oldCompNodeID = manager->componentMemory->getComponentNodeID(compID);
395 if (!oldCompNodeID)
396 return NULL;
397
398 if (!pullRemoteComponentData(compID, oldCompNodeID))
399 return NULL;
400
401 if (!threadPoolMutex.enter(1000, __FUNCTION__))
402 return NULL;
403 if (!(api = psyAPIs[crankID])) {
404 api = new PsyAPI(this);
406 api->currentCompID = compID;
407 psyAPIs[crankID] = api;
408 }
409 threadPoolMutex.leave();
410 return api;
411}
412
413bool PsySpace::registerCrankCallback(const char* name, CrankFunction func) {
414 uint16 crankID;
415 if (!manager->dataMapsMemory->getCrankID(name, crankID) || !crankID)
416 return false;
417 if (!threadPoolMutex.enter(1000, __FUNCTION__))
418 return false;
419 cranks[crankID] = func;
420 threadPoolMutex.leave();
421 return true;
422}
423
424uint32 PsySpace::getComponentID(const char* name) {
425 uint32 compID;
426 if (manager->componentMemory->getComponentID(name, compID))
427 return compID;
428 else
429 return 0;
430}
431
432bool PsySpace::pullRemoteComponentData(uint32 compID, uint16 fromNodeID) {
434 msg->setInt("CompID", compID);
435 msg->setInt("ProcID", this->procID);
436 msg->setInt("NodeID", fromNodeID);
437 DataMessage* resultMsg = NULL;
438 uint8 result = query(msg, &resultMsg, 5000);
439 if (resultMsg)
440 delete(resultMsg);
441 delete(msg);
442 return (result >= QUERY_SUCCESS);
443}
444
445
446//PsyAPI* PsySpace::getComponentAPI(const char* name) {
447// return getComponentAPI(getComponentID(name));
448//}
449
450//PsyAPI* PsySpace::getComponentAPI(uint32 compID) {
451// if (!compID)
452// return false;
453//}
454
455//bool PsySpace::registerComponentCallback(const char* name, CrankFunction func) {
456// return registerComponentCallback(getComponentID(name), func);
457//}
458
459//bool PsySpace::registerComponentCallback(uint32 compID, CrankFunction func) {
460// if (!compID)
461// return false;
462//}
463
464
466 // Add datamessage to memory
467 uint64 memID = 0;
468 uint64 eol = msg->getEOL();
469 if (eol && (eol < msg->getCreatedTime() - 10000))
470 return false;
471 if (eol) {
472 if (!manager->insertMessage(msg, memID)) {
473 LogPrint(procID, LOG_SPACE, 0, "Could not add message from %u to shared memory...", msg->getFrom());
474 return false;
475 }
476 msg->data->memid = memID;
477 }
478 if (!manager->processMemory->addToMsgQ(0, msg)) {
479 LogPrint(procID, LOG_SPACE, 0, "Could not communicate with System Message Queue...");
480 return false;
481 }
482 manager->processMemory->addToProcessStats(procID, NULL, msg);
483// printf("************ Space Post Msg %lld us old...\n", GetTimeAge(msg->getCreatedTime()));
484 return true;
485}
486
487
488// ***************** Signals *****************
489bool PsySpace::emitSignal(const PsyType& type, DataMessage* msg) {
490 // Send signal to local signal struct first
491 if (!signalsMutex.enter(3000, __FUNCTION__))
492 return false;
493 SignalStruct* signal = signalList[type];
494 if (!signal) {
495 signal = new SignalStruct;
496 signal->lastSignalMsg = NULL;
497 signalList[type] = signal;
498 }
499 signalsMutex.leave();
500
501 if (signal->mutex.enter(3000, __FUNCTION__)) {
502 if (signal->lastSignalMsg)
503 delete(signal->lastSignalMsg);
504 signal->lastSignalMsg = msg;
505 signal->mutex.leave();
506 signal->event.signal();
507 }
508 else {
509 return false;
510 }
511 // Then to all other procs and the other nodes (via Node proc 0)
512// if (!manager->processMemory->addToAllSignalQs(msg)) {
513 if (!manager->processMemory->addToAllSignalQsExcept(msg, procID)) {
514 LogPrint(procID, LOG_SPACE, 0, "Could not communicate with All Signal Queues...");
515 return false;
516 }
517 manager->processMemory->addToProcessStats(procID, NULL, msg);
518 return true;
519}
520
521DataMessage* PsySpace::waitForSignal(const PsyType& type, uint32 timeout, uint64 lastReceivedTime) {
522
523 if (!signalsMutex.enter(3000, __FUNCTION__))
524 return NULL;
525 SignalStruct* signal = signalList[type];
526 if (!signal) {
527 signal = new SignalStruct;
528 signal->lastSignalMsg = NULL;
529 signalList[type] = signal;
530 }
531 signalsMutex.leave();
532
533 DataMessage* msg = NULL;
534
535 if (lastReceivedTime) {
536 if (signal->mutex.enter(3000, __FUNCTION__)) {
537 if (signal->lastSignalMsg && (signal->lastSignalMsg->getCreatedTime() > lastReceivedTime)) {
538 msg = new DataMessage((char*)signal->lastSignalMsg->data, true);
539 // printf("************ Space NoWait Signal %llu us old...\n", GetTimeAge(msg->getCreatedTime()));
540 signal->mutex.leave();
541 //LogPrint(procID, LOG_SPACE, 0, "Space signal no wait success %s...", PrintTimeString(msg->getCreatedTime()).c_str());
542 manager->processMemory->addToProcessStats(procID, msg, NULL);
543 return msg;
544 }
545 else {
546 //LogPrint(procID, LOG_SPACE, 0, "Not newer %s >= %s", PrintTimeString(lastReceivedTime).c_str(),
547 // PrintTimeString(signal->lastSignalMsg->getCreatedTime()).c_str());
548 //if (lastReceivedTime > signal->lastSignalMsg->getCreatedTime())
549 // LogPrint(procID, LOG_SPACE, 0, "%llu > %llu", lastReceivedTime, signal->lastSignalMsg->getCreatedTime());
550 //else if (lastReceivedTime < signal->lastSignalMsg->getCreatedTime())
551 // LogPrint(procID, LOG_SPACE, 0, "%llu < %llu", lastReceivedTime, signal->lastSignalMsg->getCreatedTime());
552 signal->mutex.leave();
553 }
554 }
555 }
556
557 //if (signal->lastSignalMsg)
558 // LogPrint(procID, LOG_SPACE, 0, "Space signal wait (%s)...", PrintTimeString(signal->lastSignalMsg->getCreatedTime()).c_str());
559 //else
560 // LogPrint(procID, LOG_SPACE, 0, "Space signal wait...");
561
562 if (signal->event.waitNext(timeout)) {
563 //LogPrint(procID, LOG_SPACE, 0, "Space signal wait success...");
564 if (signal->mutex.enter(3000, __FUNCTION__) && signal->lastSignalMsg) {
565 if (lastReceivedTime) {
566 if (signal->lastSignalMsg->getCreatedTime() > lastReceivedTime)
567 msg = new DataMessage((char*)signal->lastSignalMsg->data, true);
568 }
569 else
570 msg = new DataMessage((char*)signal->lastSignalMsg->data, true);
571 //if (msg)
572 //printf("************ Space Wait Signal %llu us old...\n", GetTimeAge(msg->getCreatedTime()));
573 // LogPrint(procID, LOG_SPACE, 0, "Space signal wait success %s...", PrintTimeString(msg->getCreatedTime()).c_str());
574 }
575 signal->mutex.leave();
576 }
577
578 if (msg)
579 manager->processMemory->addToProcessStats(procID, msg, NULL);
580 return msg;
581}
582
583
584uint8 PsySpace::query(DataMessage* msg, DataMessage** result, uint32 timeout) {
585 *result = NULL;
586 if (!msg)
587 return QUERY_FAILED;
588
589 uint32 to = msg->getTo();
590
591 uint32 reqID;
592 if (!manager->dataMapsMemory->createNewRequest(msg->getFrom(), to, 0, reqID))
593 return QUERY_FAILED;
594// LogPrint(procID, LOG_SPACE,0,"Created Request id %u from comp %u...", reqID, msg->getFrom());
595
596 msg->setReference(reqID);
597 manager->processMemory->addToProcessStats(procID, NULL, msg);
598
599 uint16 otherNodeID = 0;
600 uint16 otherProcID = 0;
601 // If to is 0 this request is for the local Node
602 if (!to) {
603 manager->dataMapsMemory->setRequestStatus(reqID, REQ_PROCESSING_LOCAL);
604 if (!manager->processMemory->addToReqQ(0, msg)) {
605 manager->dataMapsMemory->deleteRequest(reqID);
606 return QUERY_FAILED;
607 }
608 }
609 else {
610 if (!manager->componentMemory->getComponentLocation(to, otherNodeID, otherProcID))
611 return QUERY_FAILED;
612
613 if (otherNodeID != manager->getNodeID()) {
614 manager->dataMapsMemory->setRequestStatus(reqID, REQ_PROCESSING_REMOTE);
615 if (!manager->processMemory->addToReqQ(0, msg)) {
616 manager->dataMapsMemory->deleteRequest(reqID);
617 return QUERY_FAILED;
618 }
619 }
620 else {
621 manager->dataMapsMemory->setRequestStatus(reqID, REQ_PROCESSING_LOCAL);
622 otherProcID = manager->componentMemory->getComponentProcessID(to);
623 if (!manager->processMemory->addToReqQ(otherProcID, msg)) {
624 manager->dataMapsMemory->deleteRequest(reqID);
625 return QUERY_FAILED;
626 }
627 }
628 }
629
630 uint8 status = 0;
631 uint64 time = 0;
632 uint64 msgID = 0;
633 uint64 msgEOL = 0;
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);
638 return QUERY_TIMEOUT;
639 }
640 manager->dataMapsMemory->deleteRequest(reqID);
641
642 if (status < REQ_SUCCESS) {
643 if (status >= REQ_FAILED)
644 return QUERY_FAILED;
645 if (status == REQ_FAILED_TO_SEND)
646 LogPrint(procID, LOG_SPACE, 0, "Request failed as remote system cannot be reached (req %u from comp %u)...", reqID, msg->getFrom());
647 else
648 LogPrint(procID, LOG_SPACE,0,"Request reply failed (%u) from node %u (req %u from comp %u)...", status, otherNodeID, reqID, msg->getFrom());
649 return QUERY_NOT_REACHABLE;
650 }
651
652 if (!msgID)
653 return QUERY_SUCCESS;
654
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());
657 return QUERY_FAILED;
658 }
659
660 if (*result)
661 manager->processMemory->addToProcessStats(procID, *result, NULL);
662 return QUERY_SUCCESS;
663}
664
665bool PsySpace::queryReply(uint32 id, uint8 status, DataMessage* resultMsg) {
666
667 if (resultMsg)
668 manager->processMemory->addToProcessStats(procID, NULL, resultMsg);
669 // Check if this request was made locally
670 uint32 remoteID;
671 uint32 origin;
672 uint32 source;
673 if (!manager->dataMapsMemory->getRequestInfo(id, origin, source, remoteID)) {
674 LogPrint(procID, LOG_SPACE,0,"Couldn't find request info for local id %u", id);
675 return false;
676 }
677 // could this be a INTERSYSTEM_QUERY_REPLY
678 if (remoteID && !origin) {
679 DataMessage* netMsg = new DataMessage(PsyAPI::CTRL_INTERSYSTEM_QUERY_REPLY, source, origin, 10000);
680 // keep the local request id here, needed by the InterSystemManager
681 netMsg->setReference(id);
682 netMsg->setStatus(status);
683 if (resultMsg)
684 netMsg->setAttachedMessage("DataMessage", resultMsg);
685 manager->processMemory->addToReqQ(0, netMsg);
686 //LogPrint(procID, LOG_SPACE,3,"Replied to remote request %u (local %u) (source %u, origin %u)...", remoteID, id, source, origin);
687 delete(resultMsg);
688 delete(netMsg);
689 // dont delete this: manager->dataMapsMemory->deleteRequest(id);
690 // needed by the InterSystemManager
691 return true;
692 }
693 else if (remoteID) {
694 uint16 otherNodeID = manager->componentMemory->getComponentNodeID(origin);
695 if (otherNodeID && (otherNodeID != manager->getNodeID())) {
696 DataMessage* netMsg = new DataMessage(PsyAPI::CTRL_QUERY_REPLY, source, origin, 10000);
697 netMsg->setReference(remoteID);
698 netMsg->setStatus(status);
699 if (resultMsg)
700 netMsg->setAttachedMessage("DataMessage", resultMsg);
701 manager->processMemory->addToReqQ(0, netMsg);
702 //LogPrint(procID, LOG_SPACE,3,"Replied to remote request %u (local %u) (source %u, origin %u)...", remoteID, id, source, origin);
703 delete(resultMsg);
704 delete(netMsg);
705 return manager->dataMapsMemory->deleteRequest(id);
706 }
707 else {
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);
710 return false;
711 }
712 }
713
714 uint64 msgID = 0;
715 uint64 msgEOL = 0;
716 uint8 reqStatus = 0;
717
718 if (resultMsg) {
719 resultMsg->setTTL(10000000);
720 msgEOL = resultMsg->getEOL();
721 // decide on EOL ###################
722 manager->temporalMemory->insertMessage(resultMsg, msgID);
723 delete(resultMsg);
724 }
725
726 if (status == QUERY_SUCCESS) {
727 if (msgID)
728 reqStatus = REQ_SUCCESS_DATA_EOL;
729 else
730 reqStatus = REQ_SUCCESS;
731 }
732 else {
733 if (msgID)
734 reqStatus = REQ_FAILED_DATA_EOL;
735 else
736 reqStatus = REQ_FAILED;
737 }
738 return manager->dataMapsMemory->setRequestStatus(id, reqStatus, msgID, msgEOL);
739}
740
741
742
743
744
745
746
747
748
749
750
751bool PsySpace::threadPoolDispatch() {
752 DataMessage* msg, *dmsg;
753 uint32 threadID;
755 uint32 idleCount = 0;
756 uint8 proc;
757 char *crankName = new char[MAXVALUENAMELEN+1];
758 crankName[0] = 0;
759 char *crankFunction = new char[MAXVALUENAMELEN + 1];
760 crankFunction[0] = 0;
761 char *crankLanguage = new char[MAXVALUENAMELEN + 1];
762 crankLanguage[0] = 0;
763 char *libraryFilename = new char[MAXVALUENAMELEN + 1];
764 libraryFilename[0] = 0;
765 CrankFunction crank;
766 uint32 compID;
767 PsyAPI* api;
768 uint32 s;
769 TriggerSpec* trigger;
770
771 while (shouldContinue) {
772// printf(".");
773 threadPoolMutex.enter();
774
775// if (GetTimeAgeMS(lastThreadPoolCheck) > threadPoolCheckInterval) {
776 idleCount = waitCounters[PROCMESSAGE] + waitCounters[PROCSIGNAL] + waitCounters[PROCREQUEST];
777 // idleCount = waitCounters[PROCMESSAGE] + waitCounters[PROCSIGNAL];
778 if (idleCount < threadPoolWaitLowerThreshold)
779 setThreadPoolSize((uint16)(threadPool.size() + threadPoolWaitIncrement));
780 // else if (idleCount > threadPoolWaitLowerThreshold)
781 // setThreadPoolSize(threadPool.size() - threadPoolWaitIncrement);
782 else
783 lastThreadPoolCheck = GetTimeNow();
784// }
785
786 if (threadTarget < threadPool.size()) {
787 threadPoolMutex.leave();
788 break;
789 }
790
791 // uint64 t = GetTimeNow();
792 if ( (waitCounters[PROCMESSAGE] <= waitCounters[PROCSIGNAL]) && (waitCounters[PROCMESSAGE] <= waitCounters[PROCREQUEST]) ) {
793 // if (waitCounters[PROCMESSAGE] <= waitCounters[PROCSIGNAL]) {
794 proc = PROCMESSAGE;
795 waitCounters[proc]++;
796 threadPoolMutex.leave();
797 msg = manager->processMemory->waitForMsgQ(procID, 100);
798 // if (msg)
799 // printf("Wait for Msg counter: %llu [%u / %u]\n", GetTimeAge(msg->getCreatedTime()), waitCounters[PROCMESSAGE], waitCounters[PROCSIGNAL]);
800 // printf("************ Space waited %llu...\n", GetTimeAge(t));
801 }
802 else if ( (waitCounters[PROCREQUEST] <= waitCounters[PROCMESSAGE]) && (waitCounters[PROCREQUEST] <= waitCounters[PROCSIGNAL]) ) {
803 proc = PROCREQUEST;
804 waitCounters[proc]++;
805 threadPoolMutex.leave();
806 msg = manager->processMemory->waitForReqQ(procID, 100);
807 //if (msg) LogPrint(procID, LOG_SPACE, 1, "Got request message, processing...");
808 }
809 else {
810 proc = PROCSIGNAL;
811 waitCounters[proc]++;
812 threadPoolMutex.leave();
813 if (msg = manager->processMemory->waitForSigQ(procID, 100)) {
814 manager->processMemory->addToProcessStats(procID, msg, NULL);
815 // printf("Wait for Signal counter: %u [%u / %u]\n", GetTimeAge(msg->getCreatedTime()), waitCounters[PROCMESSAGE], waitCounters[PROCSIGNAL]);
816 if (signalsMutex.enter(3000, __FUNCTION__)) {
817 SignalStruct* signal = signalList[msg->getType()];
818 if (!signal) {
819 signal = new SignalStruct;
820 signal->lastSignalMsg = NULL;
821 signalList[msg->getType()] = signal;
822 }
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();
830 LogPrint(procID, LOG_SPACE, 5, "Space signal signal %s...", PrintTimeString(msg->getCreatedTime()).c_str());
831 }
832 else
833 delete(msg);
834 }
835 else
836 delete(msg);
837 msg = NULL;
838 }
839 }
840 //else {
841 // proc = PROCTIMER;
842 // waitCounters[proc]++;
843 // threadPoolMutex.leave();
844 // msg = timeQ->waitForNextEvent(30);
845 //}
846 while (!threadPoolMutex.enter(1000, "Threadpool run with msg")) {
847 }
848
849 waitCounters[proc]--;
850 procCounters[proc]++;
851
852 uint16 crankID;
853 char* compName;
854 if (msg) {
855 crank = NULL;
856 crankID = 0;
857 dmsg = NULL;
858
859// printf("************ Space Deliver to %u (%lld us old) %s...\n",
860// msg->getTo(), GetTimeAge(msg->getCreatedTime()), PrintTimeString(msg->getCreatedTime()).c_str());
861 if (!(compID = msg->getTo())) {
862 LogPrint(procID, LOG_SPACE, 1, "No compID, deleting...");
863 delete(msg);
864 procCounters[proc]--;
865 threadPoolMutex.leave();
866 continue;
867 }
868
869 manager->processMemory->addToProcessStats(procID, msg, NULL);
870
871 if (msg->getType() == PsyAPI::CTRL_TRIGGER) {
872 if (!(trigger = (TriggerSpec*) msg->getData("TriggerSpec", s))) {
873 delete(msg);
874 procCounters[proc]--;
875 threadPoolMutex.leave();
876 continue;
877 }
878 crankID = trigger->crankID;
879 if (!crankID) {
880 //crank = internalCranks["Simple"];
881 LogPrint(procID, LOG_SPACE, 0, "Crank not found for component!");
882 delete (msg);
883 procCounters[proc]--;
884 threadPoolMutex.leave();
885 continue;
886 }
887
888 // Get actual data message
889 if (!(dmsg = msg->getAttachedMessageCopy("Message"))) {
890 LogPrint(procID, LOG_SPACE, 0, "Couldn't find attached input message");
891 delete (msg);
892 procCounters[proc]--;
893 threadPoolMutex.leave();
894 continue;
895 }
896 }
897 else {
898 //LogPrint(procID, LOG_SPACE, 1, "Looking for crank for direct message to component queue");
899 if (!(crankID = compCrankIDs[compID])) {
900 compName = new char[MAXKEYNAMELEN+1];
901 if (manager->componentMemory->getComponentName(compID, compName, MAXKEYNAMELEN)) {
902 utils::strcpyavail(compName+strlen(compName), "ComponentCrank", 20, true);
903 if (manager->dataMapsMemory->getCrankID(compName, crankID)) {
904 compCrankIDs[compID] = crankID;
905 }
906 }
907 else
908 compName[0] = 0;
909 if (!crankID) {
910 LogPrint(procID, LOG_SPACE, 0, "Unknown Component Crank for '%s' (%u)", compName, compID);
911 delete [] compName;
912 delete (msg);
913 procCounters[proc]--;
914 threadPoolMutex.leave();
915 continue;
916 }
917 delete [] compName;
918 }
919 }
920
921 // Load function from already loaded cranks
922 if (!crank && !(crank = cranks[crankID])) {
923 manager->dataMapsMemory->getCrankName(crankID, crankName, 256);
924 // Check if this is a scripted module
925 if (manager->dataMapsMemory->getCrankLanguage(crankID, crankLanguage, MAXVALUENAMELEN) && crankLanguage && strlen(crankLanguage)) {
926 utils::StringFormatInto(crankFunction, MAXVALUENAMELEN, "%sLink", utils::TextCapitalise(crankLanguage).c_str());
927 utils::StringFormatInto(libraryFilename, MAXVALUENAMELEN, "Psy%sLink", utils::TextCapitalise(crankLanguage).c_str());
928 LogPrint(procID, LOG_SPACE, 0, "Scripted language (%s) crank '%s' loading binary library '%s'", crankLanguage, crankName, libraryFilename);
929 }
930 else {
931 // Load function from library
932 if (!manager->dataMapsMemory->getCrankFunction(crankID, crankFunction, MAXVALUENAMELEN) || !crankFunction) {
933 LogPrint(procID, LOG_SPACE, 0, "Unknown Crank ID %u in Trigger Message", crankID);
934 delete (msg);
935 procCounters[proc]--;
936 threadPoolMutex.leave();
937 continue;
938 }
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);
941 delete (msg);
942 procCounters[proc]--;
943 threadPoolMutex.leave();
944 continue;
945 }
946 }
947
948 // If crankFunction and/or libraryFilename are not yet set, accept
949 // as the message will be added to the API queue for when the module
950 // gets instantiated
951
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);
956 }
957 else
958 LogPrint(procID, LOG_SPACE, 0, "Couldn't find crank '%s' in library '%s'", crankFunction, libraryFilename);
959 delete (msg);
960 procCounters[proc]--;
961 threadPoolMutex.leave();
962 continue;
963 }
964 cranks[crankID] = crank;
965 }
966 }
967
968 //printf("************ Space Trigger %llu us old, Msg %llu us old...\n", GetTimeAge(msg->getCreatedTime()), GetTimeAge(dmsg->getCreatedTime()));
969
970 // Is the crank already running
971 if (!(api = psyAPIs[crankID])) {
972 api = new PsyAPI(this);
974 psyAPIs[crankID] = api;
975 }
976
977 uint8 status;
978 if (dmsg)
979 status = api->addInputTrigger(crankID, compID, msg, dmsg);
980 else {
981 //LogPrint(procID, LOG_SPACE, 1, "Added direct message to component queue");
982 status = api->addInputTrigger(crankID, compID, NULL, msg);
983 }
984 switch(status) {
985 case CRANKAPI_RUNNING:
986 procCounters[proc]--;
987 threadPoolMutex.leave();
988 continue;
989 case CRANKAPI_IDLE:
990 // threadPoolMutex.leave();
991 break;
992 case CRANKAPI_FAILED:
993 default:
994 LogPrint(procID, LOG_SPACE, 0, "Couldn't add trigger to Crank API");
995 delete(msg);
996 delete(dmsg);
997 procCounters[proc]--;
998 threadPoolMutex.leave();
999 continue;
1000 }
1001
1002 threadPoolMutex.leave();
1003 // Call function
1004 if (crank) {
1005 api->begin();
1006 do {
1007 try {
1008 if (crank(api) < 0)
1009 break;
1010 }
1011 catch (...) {
1012 LogPrint(procID, LOG_SPACE, 0, "Crank %u ('%s') caused an exception", crankID, crankName);
1013 break;
1014 }
1015 } while (api->shouldContinue() && api->getInputQueueSize());
1016 api->finish();
1017 }
1018
1019 threadPoolMutex.enter();
1020 procCounters[proc]--;
1021 }
1022 threadPoolMutex.leave();
1023
1024 }
1025
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;
1035 return true;
1036}
1037
1038CrankFunction PsySpace::loadCrankFromLibrary(const char* crankName, const char* libraryFilename) {
1039 if (!crankName || !libraryFilename)
1040 return NULL;
1041
1042 if (!strlen(libraryFilename)) {
1043 // Internal cranks
1044 return internalCranks[crankName];
1045 }
1046
1047 utils::Library* lib = libraries[libraryFilename];
1048 if (!lib) {
1049 if (!(lib = utils::OpenLibrary(libraryFilename))) {
1050 LogPrint(procID, LOG_SPACE, 0, "Could not find or load library '%s'", libraryFilename);
1051 return NULL;
1052 }
1053 libraries[libraryFilename] = lib;
1054 }
1055
1056 CrankFunction crank = (CrankFunction)lib->getFunction(crankName);
1057 if (!crank) {
1058 LogPrint(procID, LOG_SPACE, 0, "Could not load Crank '%s' from library '%s'", crankName, libraryFilename);
1059 return NULL;
1060 }
1061 return crank;
1062}
1063
1064
1065bool PsySpace::startContinuousComponent(uint32 compID) {
1066
1067 std::map<uint32, uint32>::iterator it = continuousComponentThreads.find(compID);
1068 if (it != continuousComponentThreads.end())
1069 return false;
1070
1071 continuousComponentThreads[threadID] = 0;
1072
1073 uint32 threadID;
1075 return false;
1076
1077 continuousComponentThreads[threadID] = compID;
1078 return true;
1079}
1080
1081bool PsySpace::runContinuousComponent() {
1082 uint32 threadID;
1083 DataMessage* msg = NULL;
1084
1086
1087 uint32 count = 0;
1088 uint32 compID;
1089 while (!(compID = continuousComponentThreads[threadID])) {
1090 if (++count > 10)
1091 return false;
1092 utils::Sleep(50);
1093 }
1094
1095 // Find function name and library to call
1096 // Load function from library
1097 // Check stats
1098 // Call function
1099 // Record stats usage
1100
1101 return true;
1102}
1103
1104
1105bool PsySpace::run() {
1106 // Space Thread
1107 // Update Heartbeat
1108 manager->processMemory->setProcessStatus(procID, PSYPROC_ACTIVE);
1109 // Update Space Stats
1110 uint64 currentCPUTicks;
1111// utils::GetProcessCPUTicks(currentCPUTicks);
1112 uint32 checkCount = 50, c = 0;
1113 uint64 lastMsgCheck;
1114 std::map<uint32, PsyAPI*>::iterator i, e = psyAPIs.end();
1115
1116 DataMessage* cmsg;
1117 while (shouldContinue) {
1118 if (cmsg = manager->processMemory->waitForCmdQ(procID, 100)) {
1119 if (cmsg->getType() == PsyAPI::CTRL_SYSTEM_SHUTDOWN) {
1120 delete(cmsg);
1121 shutdown();
1122 break;
1123 }
1124 delete(cmsg);
1125 }
1126 // Update Heartbeat
1127 utils::GetProcessCPUTicks(currentCPUTicks);
1128 manager->processMemory->setProcessStatus(procID, PSYPROC_ACTIVE, currentCPUTicks);
1129
1130 if (++c > 50) {
1131 // check all apis for checkLastWaitForMessage()
1132 i = psyAPIs.begin();
1133 while (i != e) {
1134 if ((i->second) && (lastMsgCheck = i->second->checkLastWaitForMessage())) {
1135 i->second->logPrint(1, "Component has unchecked messages, last check %s ago",
1136 PrintTimeDifString(GetTimeAge(lastMsgCheck)).c_str());
1137 }
1138 i++;
1139 }
1140 c = 0;
1141 }
1142 }
1143
1144 manager->processMemory->setProcessStatus(procID, PSYPROC_SHUTTING_DOWN);
1145 //LogPrint(procID, LOG_SPACE, 1, "PsySpace '%s' shutting down...", name.c_str());
1146 isRunning = false;
1147 return true;
1148}
1149
1151 if (arg == NULL) thread_ret_val(1);
1152 thread_ret_val((int)(((PsySpace*)arg)->run() ? 0 : 1));
1153}
1154
1155
1157 if (arg == NULL) thread_ret_val(1);
1158 thread_ret_val((int)(((PsySpace*)arg)->threadPoolDispatch() ? 0 : 1));
1159}
1160
1162 if (arg == NULL) thread_ret_val(1);
1163 thread_ret_val((int)(((PsySpace*)arg)->runContinuousComponent() ? 0 : 1));
1164}
1165
1166
1167} // namespace cmlabs
#define REQ_PROCESSING_REMOTE
#define REQ_SUCCESS_DATA_EOL
#define REQ_SUCCESS
#define REQ_FAILED_DATA_EOL
#define REQ_FAILED
#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.
Definition PsyAPI.h:62
#define QUERY_SUCCESS
The query succeeded.
Definition PsyAPI.h:60
#define CRANKAPI_RUNNING
The crank is currently executing.
Definition PsyAPI.h:40
#define QUERY_FAILED
General failure.
Definition PsyAPI.h:55
#define CRANKAPI_IDLE
The crank is idle, waiting for input.
Definition PsyAPI.h:41
#define CRANKAPI_FAILED
The API could not be obtained or is invalid.
Definition PsyAPI.h:38
#define QUERY_TIMEOUT
No reply within the timeout.
Definition PsyAPI.h:56
The PsySpace process/node context: the runtime container in which Psyclone components (cranks) live a...
#define PROCSIGNAL
Signal processing.
Definition PsySpace.h:141
#define LOG_SPACE
Log source id used by PsySpace when writing entries to the system log.
Definition PsySpace.h:52
#define PROCREQUEST
Query/request processing.
Definition PsySpace.h:142
#define PROCMESSAGE
Ordinary trigger-message processing.
Definition PsySpace.h:140
#define MAXVALUINT32
Definition Types.h:87
#define MAXKEYNAMELEN
Definition Utils.h:85
#define thread_ret_val(ret)
Definition Utils.h:131
#define THREAD_RET
Definition Utils.h:127
#define THREAD_FUNCTION_CALL
Definition Utils.h:129
#define LogPrint
Definition Utils.h:313
#define MAXVALUENAMELEN
Definition Utils.h:86
#define THREAD_ARG
Definition Utils.h:130
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 getEOL()
getEOL()
uint64 getCreatedTime()
getCreatedTime()
bool setData(const char *key, const char *value, uint32 size)
setData(const char* key, const char* value, uint32 size)
uint32 getTo()
getTo()
static bool SetLogReceiver(LogReceiver *rec)
Register a receiver that gets every accepted LogEntry.
Definition Utils.cpp:169
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.
Definition PsyAPI.h:82
static struct PsyType CTRL_PROCESS_INITIALISE
Sent to a process to initialise it.
Definition PsyAPI.h:91
static struct PsyType CTRL_PROCESS_SHUTDOWN
Orders a single process to shut down.
Definition PsyAPI.h:93
static struct PsyType CTRL_PULLCOMPONENTDATA
Requests component data from another node.
Definition PsyAPI.h:100
static struct PsyType CTRL_TRIGGER
Wraps a trigger delivery to a component.
Definition PsyAPI.h:97
static struct PsyType CTRL_PROCESS_GREETING
Handshake from a newly joined process.
Definition PsyAPI.h:92
bool shouldContinue()
Check whether the crank should keep running, or exit its loop.
Definition PsyAPI.cpp:87
static struct PsyType CTRL_QUERY_REPLY
Carries a query reply back to the asker.
Definition PsyAPI.h:99
bool setCommandlineBasedir(const char *cmdlineBasedir)
Internal use only.
Definition PsyAPI.cpp:104
uint32 getInputQueueSize()
Get the size of the input queue, i.e.
Definition PsyAPI.cpp:239
static struct PsyType CTRL_INTERSYSTEM_QUERY_REPLY
Reply from a different Psyclone system.
Definition PsyAPI.h:105
static struct PsyType CTRL_SYSTEM_SHUTDOWN
Orders a full system shutdown.
Definition PsyAPI.h:95
static struct PsyType CTRL_CREATECUSTOMPAGE
Registers a custom PsyProbe view.
Definition PsyAPI.h:101
bool postMessage(DataMessage *msg)
Post a raw message into the system for distribution to subscribers.
Definition PsySpace.cpp:465
bool reset()
Reset the space's runtime state (counters, queues) without disconnecting.
Definition PsySpace.cpp:249
bool connect(uint16 systemID, bool isMaster=false, const char *cmdline=NULL)
Join a Psyclone system (attach to the node's shared memory).
Definition PsySpace.cpp:134
bool shutdown()
Request an orderly shutdown of the space and all its components.
Definition PsySpace.cpp:282
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.
Definition PsySpace.cpp:276
uint8 query(DataMessage *msg, DataMessage **result, uint32 timeout)
Send a query message and wait for its reply.
Definition PsySpace.cpp:584
uint32 getComponentID(const char *name)
Look up the numeric component id for a component name.
Definition PsySpace.cpp:424
DataMessage * waitForSignal(const PsyType &type, uint32 timeout, uint64 lastReceivedTime=0)
Block until a signal of the given type arrives (or has already arrived).
Definition PsySpace.cpp:521
friend THREAD_RET THREAD_FUNCTION_CALL PsySpaceContinuousRun(THREAD_ARG arg)
Thread entry for continuously running components.
~PsySpace()
Destructor.
Definition PsySpace.cpp:128
bool isConnected(uint32 timeoutMS=5000)
Wait until the space is fully connected to the system.
Definition PsySpace.cpp:226
MemoryManager * manager
The process-local memory manager: entry point to the node's shared-memory fabric. Owned by the space.
Definition PsySpace.h:330
friend class PsyAPI
Definition PsySpace.h:165
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...
Definition PsySpace.cpp:413
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(...
Definition PsySpace.cpp:336
PsyAPI * getCrankAPI(const char *name)
Get (or create) the PsyAPI handle for a crank hosted in this space.
Definition PsySpace.cpp:384
bool queryReply(uint32 id, uint8 status, DataMessage *result)
Reply to a previously received query.
Definition PsySpace.cpp:665
bool emitSignal(const PsyType &type, DataMessage *msg)
Emit a system-wide signal of the given type.
Definition PsySpace.cpp:489
bool logEntry(LogEntry *entry)
LogReceiver interface: accept a log entry produced within this space.
Definition PsySpace.cpp:346
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()).
Definition PsySpace.cpp:88
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.
Definition PsySpace.h:91
DataMessage * waitForNextEvent(uint32 ms)
Block until the next scheduled event is due, or the timeout expires.
Definition PsySpace.cpp:61
bool removeSchedule(uint32 id)
Remove (and delete) a schedule by id.
Definition PsySpace.cpp:47
bool addSchedule(TimeQueueSchedule *schedule)
Add a schedule to the queue.
Definition PsySpace.cpp:36
~TimeQueue()
Destroy the queue and delete all remaining schedules (owned by the queue).
Definition PsySpace.cpp:27
TimeQueue()
Create an empty time queue with its own timer.
Definition PsySpace.cpp:23
One recurring (or time-bounded) activation schedule managed by a TimeQueue.
Definition PsySpace.h:61
uint32 msgTag
Tag attached to the generated message.
Definition PsySpace.h:80
uint64 start
First-activation time (µs), or 0 for immediate.
Definition PsySpace.h:76
PsyType msgType
Type of the message generated on each activation.
Definition PsySpace.h:79
uint32 interval
Repeat interval in milliseconds.
Definition PsySpace.h:75
TimeQueueSchedule(uint32 interval, uint64 start=0, uint64 end=0)
Create a schedule.
Definition PsySpace.cpp:13
~TimeQueueSchedule()
Destructor.
Definition PsySpace.cpp:19
uint64 end
Expiry time (µs), or 0 for no expiry.
Definition PsySpace.h:77
uint32 id
Unique schedule id, used for removal via TimeQueue::removeSchedule().
Definition PsySpace.h:72
bool waitNext()
Block until the next signal() occurs.
Definition Utils.cpp:1568
bool signal()
Wake all threads currently waiting on this event.
Definition Utils.cpp:1592
bool leave()
Release the mutex.
Definition Utils.cpp:1194
bool enter()
Block until the mutex is acquired.
Definition Utils.cpp:1059
Multiplexing timer: schedule many periodic timers and consume their expiries from one queue.
Definition Utils.h:640
std::string PrintTimeString(uint64 t, bool local=true, bool us=true, bool ms=true)
Definition PsyTime.cpp:676
uint64 GetTimeNow()
Return the current absolute time (µs since year 0) according to the TMC.
Definition PsyTime.cpp:69
std::string PrintTimeDifString(uint64 t, bool us=true, bool ms=true)
Definition PsyTime.cpp:722
int32 GetTimeAgeMS(uint64 t)
Age of a timestamp relative to now, in milliseconds.
Definition PsyTime.cpp:35
int64 GetTimeAge(uint64 t)
Age of a timestamp relative to now.
Definition PsyTime.cpp:25
bool Sleep(uint32 ms)
Suspend the calling thread.
Definition Utils.cpp:2802
std::string GetCommandLinePath()
Get the directory portion of the executable path.
Definition Utils.cpp:4252
double RandomValue()
Uniform random double in [0,1).
Definition Utils.cpp:7678
std::string TextTrimQuotes(const char *text)
Strip a single pair of surrounding quotes if present.
Definition Utils.cpp:6151
bool StringFormatInto(char *dst, uint32 maxsize, const char *format,...)
printf into a caller-supplied buffer with truncation.
Definition Utils.cpp:6596
bool GetProcessCPUTicks(uint64 &ticks)
Get accumulated CPU time of the current process.
Definition Utils.cpp:3289
std::string StringFormat(const char *format,...)
printf into a std::string.
Definition Utils.cpp:6626
Library * OpenLibrary(const char *libName)
Load a library by name, applying platform filename conventions.
Definition Utils.cpp:4492
uint32 strcpyavail(char *dst, const char *src, uint32 maxlen, bool copyAvailable)
Bounded strcpy that always NUL-terminates.
Definition Utils.cpp:6056
std::string TextCapitalise(const char *text)
Capitalise the first letter of text.
Definition Utils.cpp:6093
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.
Definition PsySpace.h:49
int8 Internal_Print(PsyAPI *api)
Prints incoming messages to the console/log.
static struct PsyType CTRL_LOGPRINT
Definition ObjectIDs.h:83
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.
Definition Types.h:123
uint64 memid
Shared-memory id assigned when the message is stored in a memory map.
Wire/storage layout of one log record: fixed header immediately followed by the message text.
Definition Utils.h:228
uint32 size
Definition Utils.h:229
Per-signal bookkeeping for PsySpace signal distribution.
Definition PsySpace.h:130
utils::Mutex mutex
Protects lastSignalMsg.
Definition PsySpace.h:133
DataMessage * lastSignalMsg
Most recently emitted message for this signal type (owned by the space).
Definition PsySpace.h:131
utils::Event event
Signalled whenever a new message arrives; wakes waiters.
Definition PsySpace.h:132
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.